forked from mirrors/linux
		
	drivers/soc/litex: add LiteX SoC Controller driver
This commit adds driver for the FPGA-based LiteX SoC Controller from LiteX SoC builder. Co-developed-by: Mateusz Holenko <mholenko@antmicro.com> Signed-off-by: Mateusz Holenko <mholenko@antmicro.com> Signed-off-by: Pawel Czarnecki <pczarnecki@internships.antmicro.com> Signed-off-by: Stafford Horne <shorne@gmail.com>
This commit is contained in:
		
							parent
							
								
									3399bac5ef
								
							
						
					
					
						commit
						22447a99c9
					
				
					 7 changed files with 304 additions and 0 deletions
				
			
		|  | @ -10177,6 +10177,8 @@ M:	Karol Gugala <kgugala@antmicro.com> | ||||||
| M:	Mateusz Holenko <mholenko@antmicro.com> | M:	Mateusz Holenko <mholenko@antmicro.com> | ||||||
| S:	Maintained | S:	Maintained | ||||||
| F:	Documentation/devicetree/bindings/*/litex,*.yaml | F:	Documentation/devicetree/bindings/*/litex,*.yaml | ||||||
|  | F:	drivers/soc/litex/litex_soc_ctrl.c | ||||||
|  | F:	include/linux/litex.h | ||||||
| 
 | 
 | ||||||
| LIVE PATCHING | LIVE PATCHING | ||||||
| M:	Josh Poimboeuf <jpoimboe@redhat.com> | M:	Josh Poimboeuf <jpoimboe@redhat.com> | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ source "drivers/soc/bcm/Kconfig" | ||||||
| source "drivers/soc/fsl/Kconfig" | source "drivers/soc/fsl/Kconfig" | ||||||
| source "drivers/soc/imx/Kconfig" | source "drivers/soc/imx/Kconfig" | ||||||
| source "drivers/soc/ixp4xx/Kconfig" | source "drivers/soc/ixp4xx/Kconfig" | ||||||
|  | source "drivers/soc/litex/Kconfig" | ||||||
| source "drivers/soc/mediatek/Kconfig" | source "drivers/soc/mediatek/Kconfig" | ||||||
| source "drivers/soc/qcom/Kconfig" | source "drivers/soc/qcom/Kconfig" | ||||||
| source "drivers/soc/renesas/Kconfig" | source "drivers/soc/renesas/Kconfig" | ||||||
|  |  | ||||||
|  | @ -14,6 +14,7 @@ obj-$(CONFIG_ARCH_GEMINI)	+= gemini/ | ||||||
| obj-y				+= imx/ | obj-y				+= imx/ | ||||||
| obj-$(CONFIG_ARCH_IXP4XX)	+= ixp4xx/ | obj-$(CONFIG_ARCH_IXP4XX)	+= ixp4xx/ | ||||||
| obj-$(CONFIG_SOC_XWAY)		+= lantiq/ | obj-$(CONFIG_SOC_XWAY)		+= lantiq/ | ||||||
|  | obj-$(CONFIG_LITEX_SOC_CONTROLLER) += litex/ | ||||||
| obj-y				+= mediatek/ | obj-y				+= mediatek/ | ||||||
| obj-y				+= amlogic/ | obj-y				+= amlogic/ | ||||||
| obj-y				+= qcom/ | obj-y				+= qcom/ | ||||||
|  |  | ||||||
							
								
								
									
										19
									
								
								drivers/soc/litex/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								drivers/soc/litex/Kconfig
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | ||||||
|  | # SPDX-License_Identifier: GPL-2.0 | ||||||
|  | 
 | ||||||
|  | menu "Enable LiteX SoC Builder specific drivers" | ||||||
|  | 
 | ||||||
|  | config LITEX | ||||||
|  | 	bool | ||||||
|  | 
 | ||||||
|  | config LITEX_SOC_CONTROLLER | ||||||
|  | 	tristate "Enable LiteX SoC Controller driver" | ||||||
|  | 	depends on OF || COMPILE_TEST | ||||||
|  | 	select LITEX | ||||||
|  | 	help | ||||||
|  | 	  This option enables the SoC Controller Driver which verifies | ||||||
|  | 	  LiteX CSR access and provides common litex_get_reg/litex_set_reg | ||||||
|  | 	  accessors. | ||||||
|  | 	  All drivers that use functions from litex.h must depend on | ||||||
|  | 	  LITEX. | ||||||
|  | 
 | ||||||
|  | endmenu | ||||||
							
								
								
									
										3
									
								
								drivers/soc/litex/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								drivers/soc/litex/Makefile
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | ||||||
|  | # SPDX-License_Identifier: GPL-2.0
 | ||||||
|  | 
 | ||||||
|  | obj-$(CONFIG_LITEX_SOC_CONTROLLER)	+= litex_soc_ctrl.o | ||||||
							
								
								
									
										176
									
								
								drivers/soc/litex/litex_soc_ctrl.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								drivers/soc/litex/litex_soc_ctrl.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,176 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-2.0
 | ||||||
|  | /*
 | ||||||
|  |  * LiteX SoC Controller Driver | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2020 Antmicro <www.antmicro.com> | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <linux/litex.h> | ||||||
|  | #include <linux/device.h> | ||||||
|  | #include <linux/errno.h> | ||||||
|  | #include <linux/of.h> | ||||||
|  | #include <linux/platform_device.h> | ||||||
|  | #include <linux/printk.h> | ||||||
|  | #include <linux/module.h> | ||||||
|  | #include <linux/errno.h> | ||||||
|  | #include <linux/io.h> | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * LiteX SoC Generator, depending on the configuration, can split a single | ||||||
|  |  * logical CSR (Control&Status Register) into a series of consecutive physical | ||||||
|  |  * registers. | ||||||
|  |  * | ||||||
|  |  * For example, in the configuration with 8-bit CSR Bus, 32-bit aligned (the | ||||||
|  |  * default one for 32-bit CPUs) a 32-bit logical CSR will be generated as four | ||||||
|  |  * 32-bit physical registers, each one containing one byte of meaningful data. | ||||||
|  |  * | ||||||
|  |  * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus
 | ||||||
|  |  * | ||||||
|  |  * The purpose of `litex_set_reg`/`litex_get_reg` is to implement the logic | ||||||
|  |  * of writing to/reading from the LiteX CSR in a single place that can be | ||||||
|  |  * then reused by all LiteX drivers. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * litex_set_reg() - Writes the value to the LiteX CSR (Control&Status Register) | ||||||
|  |  * @reg: Address of the CSR | ||||||
|  |  * @reg_size: The width of the CSR expressed in the number of bytes | ||||||
|  |  * @val: Value to be written to the CSR | ||||||
|  |  * | ||||||
|  |  * In the currently supported LiteX configuration (8-bit CSR Bus, 32-bit aligned), | ||||||
|  |  * a 32-bit LiteX CSR is generated as 4 consecutive 32-bit physical registers, | ||||||
|  |  * each one containing one byte of meaningful data. | ||||||
|  |  * | ||||||
|  |  * This function splits a single possibly multi-byte write into a series of | ||||||
|  |  * single-byte writes with a proper offset. | ||||||
|  |  */ | ||||||
|  | void litex_set_reg(void __iomem *reg, unsigned long reg_size, | ||||||
|  | 		    unsigned long val) | ||||||
|  | { | ||||||
|  | 	unsigned long shifted_data, shift, i; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < reg_size; ++i) { | ||||||
|  | 		shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT); | ||||||
|  | 		shifted_data = val >> shift; | ||||||
|  | 
 | ||||||
|  | 		WRITE_LITEX_SUBREGISTER(shifted_data, reg, i); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(litex_set_reg); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * litex_get_reg() - Reads the value of the LiteX CSR (Control&Status Register) | ||||||
|  |  * @reg: Address of the CSR | ||||||
|  |  * @reg_size: The width of the CSR expressed in the number of bytes | ||||||
|  |  * | ||||||
|  |  * Return: Value read from the CSR | ||||||
|  |  * | ||||||
|  |  * In the currently supported LiteX configuration (8-bit CSR Bus, 32-bit aligned), | ||||||
|  |  * a 32-bit LiteX CSR is generated as 4 consecutive 32-bit physical registers, | ||||||
|  |  * each one containing one byte of meaningful data. | ||||||
|  |  * | ||||||
|  |  * This function generates a series of single-byte reads with a proper offset | ||||||
|  |  * and joins their results into a single multi-byte value. | ||||||
|  |  */ | ||||||
|  | unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_size) | ||||||
|  | { | ||||||
|  | 	unsigned long shifted_data, shift, i; | ||||||
|  | 	unsigned long result = 0; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < reg_size; ++i) { | ||||||
|  | 		shifted_data = READ_LITEX_SUBREGISTER(reg, i); | ||||||
|  | 
 | ||||||
|  | 		shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT); | ||||||
|  | 		result |= (shifted_data << shift); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(litex_get_reg); | ||||||
|  | 
 | ||||||
|  | #define SCRATCH_REG_OFF         0x04 | ||||||
|  | #define SCRATCH_REG_VALUE       0x12345678 | ||||||
|  | #define SCRATCH_TEST_VALUE      0xdeadbeef | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Check LiteX CSR read/write access | ||||||
|  |  * | ||||||
|  |  * This function reads and writes a scratch register in order to verify if CSR | ||||||
|  |  * access works. | ||||||
|  |  * | ||||||
|  |  * In case any problems are detected, the driver should panic. | ||||||
|  |  * | ||||||
|  |  * Access to the LiteX CSR is, by design, done in CPU native endianness. | ||||||
|  |  * The driver should not dynamically configure access functions when | ||||||
|  |  * the endianness mismatch is detected. Such situation indicates problems in | ||||||
|  |  * the soft SoC design and should be solved at the LiteX generator level, | ||||||
|  |  * not in the software. | ||||||
|  |  */ | ||||||
|  | static int litex_check_csr_access(void __iomem *reg_addr) | ||||||
|  | { | ||||||
|  | 	unsigned long reg; | ||||||
|  | 
 | ||||||
|  | 	reg = litex_read32(reg_addr + SCRATCH_REG_OFF); | ||||||
|  | 
 | ||||||
|  | 	if (reg != SCRATCH_REG_VALUE) { | ||||||
|  | 		panic("Scratch register read error - the system is probably broken! Expected: 0x%x but got: 0x%lx", | ||||||
|  | 			SCRATCH_REG_VALUE, reg); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	litex_write32(reg_addr + SCRATCH_REG_OFF, SCRATCH_TEST_VALUE); | ||||||
|  | 	reg = litex_read32(reg_addr + SCRATCH_REG_OFF); | ||||||
|  | 
 | ||||||
|  | 	if (reg != SCRATCH_TEST_VALUE) { | ||||||
|  | 		panic("Scratch register write error - the system is probably broken! Expected: 0x%x but got: 0x%lx", | ||||||
|  | 			SCRATCH_TEST_VALUE, reg); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* restore original value of the SCRATCH register */ | ||||||
|  | 	litex_write32(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_VALUE); | ||||||
|  | 
 | ||||||
|  | 	pr_info("LiteX SoC Controller driver initialized"); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct litex_soc_ctrl_device { | ||||||
|  | 	void __iomem *base; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct of_device_id litex_soc_ctrl_of_match[] = { | ||||||
|  | 	{.compatible = "litex,soc-controller"}, | ||||||
|  | 	{}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | MODULE_DEVICE_TABLE(of, litex_soc_ctrl_of_match); | ||||||
|  | 
 | ||||||
|  | static int litex_soc_ctrl_probe(struct platform_device *pdev) | ||||||
|  | { | ||||||
|  | 	struct litex_soc_ctrl_device *soc_ctrl_dev; | ||||||
|  | 
 | ||||||
|  | 	soc_ctrl_dev = devm_kzalloc(&pdev->dev, sizeof(*soc_ctrl_dev), GFP_KERNEL); | ||||||
|  | 	if (!soc_ctrl_dev) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	soc_ctrl_dev->base = devm_platform_ioremap_resource(pdev, 0); | ||||||
|  | 	if (IS_ERR(soc_ctrl_dev->base)) | ||||||
|  | 		return PTR_ERR(soc_ctrl_dev->base); | ||||||
|  | 
 | ||||||
|  | 	return litex_check_csr_access(soc_ctrl_dev->base); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct platform_driver litex_soc_ctrl_driver = { | ||||||
|  | 	.driver = { | ||||||
|  | 		.name = "litex-soc-controller", | ||||||
|  | 		.of_match_table = of_match_ptr(litex_soc_ctrl_of_match) | ||||||
|  | 	}, | ||||||
|  | 	.probe = litex_soc_ctrl_probe, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | module_platform_driver(litex_soc_ctrl_driver); | ||||||
|  | MODULE_DESCRIPTION("LiteX SoC Controller driver"); | ||||||
|  | MODULE_AUTHOR("Antmicro <www.antmicro.com>"); | ||||||
|  | MODULE_LICENSE("GPL v2"); | ||||||
							
								
								
									
										102
									
								
								include/linux/litex.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								include/linux/litex.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,102 @@ | ||||||
|  | /* SPDX-License-Identifier: GPL-2.0 */ | ||||||
|  | /*
 | ||||||
|  |  * Common LiteX header providing | ||||||
|  |  * helper functions for accessing CSRs. | ||||||
|  |  * | ||||||
|  |  * Implementation of the functions is provided by | ||||||
|  |  * the LiteX SoC Controller driver. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2019-2020 Antmicro <www.antmicro.com> | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef _LINUX_LITEX_H | ||||||
|  | #define _LINUX_LITEX_H | ||||||
|  | 
 | ||||||
|  | #include <linux/io.h> | ||||||
|  | #include <linux/types.h> | ||||||
|  | #include <linux/compiler_types.h> | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * The parameters below are true for LiteX SoCs configured for 8-bit CSR Bus, | ||||||
|  |  * 32-bit aligned. | ||||||
|  |  * | ||||||
|  |  * Supporting other configurations will require extending the logic in this | ||||||
|  |  * header and in the LiteX SoC controller driver. | ||||||
|  |  */ | ||||||
|  | #define LITEX_REG_SIZE	  0x4 | ||||||
|  | #define LITEX_SUBREG_SIZE	0x1 | ||||||
|  | #define LITEX_SUBREG_SIZE_BIT	 (LITEX_SUBREG_SIZE * 8) | ||||||
|  | 
 | ||||||
|  | #define WRITE_LITEX_SUBREGISTER(val, base_offset, subreg_id) \ | ||||||
|  | 	writel((u32 __force)cpu_to_le32(val), base_offset + (LITEX_REG_SIZE * subreg_id)) | ||||||
|  | 
 | ||||||
|  | #define READ_LITEX_SUBREGISTER(base_offset, subreg_id) \ | ||||||
|  | 	le32_to_cpu((__le32 __force)readl(base_offset + (LITEX_REG_SIZE * subreg_id))) | ||||||
|  | 
 | ||||||
|  | void litex_set_reg(void __iomem *reg, unsigned long reg_sz, unsigned long val); | ||||||
|  | 
 | ||||||
|  | unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_sz); | ||||||
|  | 
 | ||||||
|  | static inline void litex_write8(void __iomem *reg, u8 val) | ||||||
|  | { | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val, reg, 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void litex_write16(void __iomem *reg, u16 val) | ||||||
|  | { | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val >> 8, reg, 0); | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val, reg, 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void litex_write32(void __iomem *reg, u32 val) | ||||||
|  | { | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val >> 24, reg, 0); | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val >> 16, reg, 1); | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val >> 8, reg, 2); | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val, reg, 3); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void litex_write64(void __iomem *reg, u64 val) | ||||||
|  | { | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val >> 56, reg, 0); | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val >> 48, reg, 1); | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val >> 40, reg, 2); | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val >> 32, reg, 3); | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val >> 24, reg, 4); | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val >> 16, reg, 5); | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val >> 8, reg, 6); | ||||||
|  | 	WRITE_LITEX_SUBREGISTER(val, reg, 7); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline u8 litex_read8(void __iomem *reg) | ||||||
|  | { | ||||||
|  | 	return READ_LITEX_SUBREGISTER(reg, 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline u16 litex_read16(void __iomem *reg) | ||||||
|  | { | ||||||
|  | 	return (READ_LITEX_SUBREGISTER(reg, 0) << 8) | ||||||
|  | 		| (READ_LITEX_SUBREGISTER(reg, 1)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline u32 litex_read32(void __iomem *reg) | ||||||
|  | { | ||||||
|  | 	return (READ_LITEX_SUBREGISTER(reg, 0) << 24) | ||||||
|  | 		| (READ_LITEX_SUBREGISTER(reg, 1) << 16) | ||||||
|  | 		| (READ_LITEX_SUBREGISTER(reg, 2) << 8) | ||||||
|  | 		| (READ_LITEX_SUBREGISTER(reg, 3)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline u64 litex_read64(void __iomem *reg) | ||||||
|  | { | ||||||
|  | 	return ((u64)READ_LITEX_SUBREGISTER(reg, 0) << 56) | ||||||
|  | 		| ((u64)READ_LITEX_SUBREGISTER(reg, 1) << 48) | ||||||
|  | 		| ((u64)READ_LITEX_SUBREGISTER(reg, 2) << 40) | ||||||
|  | 		| ((u64)READ_LITEX_SUBREGISTER(reg, 3) << 32) | ||||||
|  | 		| ((u64)READ_LITEX_SUBREGISTER(reg, 4) << 24) | ||||||
|  | 		| ((u64)READ_LITEX_SUBREGISTER(reg, 5) << 16) | ||||||
|  | 		| ((u64)READ_LITEX_SUBREGISTER(reg, 6) << 8) | ||||||
|  | 		| ((u64)READ_LITEX_SUBREGISTER(reg, 7)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif /* _LINUX_LITEX_H */ | ||||||
		Loading…
	
		Reference in a new issue
	
	 Pawel Czarnecki
						Pawel Czarnecki