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> | ||||
| S:	Maintained | ||||
| F:	Documentation/devicetree/bindings/*/litex,*.yaml | ||||
| F:	drivers/soc/litex/litex_soc_ctrl.c | ||||
| F:	include/linux/litex.h | ||||
| 
 | ||||
| LIVE PATCHING | ||||
| M:	Josh Poimboeuf <jpoimboe@redhat.com> | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ source "drivers/soc/bcm/Kconfig" | |||
| source "drivers/soc/fsl/Kconfig" | ||||
| source "drivers/soc/imx/Kconfig" | ||||
| source "drivers/soc/ixp4xx/Kconfig" | ||||
| source "drivers/soc/litex/Kconfig" | ||||
| source "drivers/soc/mediatek/Kconfig" | ||||
| source "drivers/soc/qcom/Kconfig" | ||||
| source "drivers/soc/renesas/Kconfig" | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ obj-$(CONFIG_ARCH_GEMINI)	+= gemini/ | |||
| obj-y				+= imx/ | ||||
| obj-$(CONFIG_ARCH_IXP4XX)	+= ixp4xx/ | ||||
| obj-$(CONFIG_SOC_XWAY)		+= lantiq/ | ||||
| obj-$(CONFIG_LITEX_SOC_CONTROLLER) += litex/ | ||||
| obj-y				+= mediatek/ | ||||
| obj-y				+= amlogic/ | ||||
| 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