Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: zynq: Add support for SOC_BUS

Provide information through SOC_BUS to user space.
Silicon revision is provided through devcfg device.

Signed-off-by: Michal Simek <michal.simek@xilinx.com>

+96 -1
+5
arch/arm/boot/dts/zynq-7000.dtsi
··· 154 154 }; 155 155 }; 156 156 157 + devcfg: devcfg@f8007000 { 158 + compatible = "xlnx,zynq-devcfg-1.0"; 159 + reg = <0xf8007000 0x100>; 160 + } ; 161 + 157 162 global_timer: timer@f8f00200 { 158 163 compatible = "arm,cortex-a9-global-timer"; 159 164 reg = <0xf8f00200 0x20>;
+1
arch/arm/mach-zynq/Kconfig
··· 10 10 select CADENCE_TTC_TIMER 11 11 select ARM_GLOBAL_TIMER if !CPU_FREQ 12 12 select MFD_SYSCON 13 + select SOC_BUS 13 14 help 14 15 Support for Xilinx Zynq ARM Cortex A9 Platform
+70 -1
arch/arm/mach-zynq/common.c
··· 29 29 #include <linux/memblock.h> 30 30 #include <linux/irqchip.h> 31 31 #include <linux/irqchip/arm-gic.h> 32 + #include <linux/slab.h> 33 + #include <linux/sys_soc.h> 32 34 33 35 #include <asm/mach/arch.h> 34 36 #include <asm/mach/map.h> ··· 39 37 #include <asm/page.h> 40 38 #include <asm/pgtable.h> 41 39 #include <asm/smp_scu.h> 40 + #include <asm/system_info.h> 42 41 #include <asm/hardware/cache-l2x0.h> 43 42 44 43 #include "common.h" 44 + 45 + #define ZYNQ_DEVCFG_MCTRL 0x80 46 + #define ZYNQ_DEVCFG_PS_VERSION_SHIFT 28 47 + #define ZYNQ_DEVCFG_PS_VERSION_MASK 0xF 45 48 46 49 void __iomem *zynq_scu_base; 47 50 ··· 67 60 }; 68 61 69 62 /** 63 + * zynq_get_revision - Get Zynq silicon revision 64 + * 65 + * Return: Silicon version or -1 otherwise 66 + */ 67 + static int __init zynq_get_revision(void) 68 + { 69 + struct device_node *np; 70 + void __iomem *zynq_devcfg_base; 71 + u32 revision; 72 + 73 + np = of_find_compatible_node(NULL, NULL, "xlnx,zynq-devcfg-1.0"); 74 + if (!np) { 75 + pr_err("%s: no devcfg node found\n", __func__); 76 + return -1; 77 + } 78 + 79 + zynq_devcfg_base = of_iomap(np, 0); 80 + if (!zynq_devcfg_base) { 81 + pr_err("%s: Unable to map I/O memory\n", __func__); 82 + return -1; 83 + } 84 + 85 + revision = readl(zynq_devcfg_base + ZYNQ_DEVCFG_MCTRL); 86 + revision >>= ZYNQ_DEVCFG_PS_VERSION_SHIFT; 87 + revision &= ZYNQ_DEVCFG_PS_VERSION_MASK; 88 + 89 + iounmap(zynq_devcfg_base); 90 + 91 + return revision; 92 + } 93 + 94 + /** 70 95 * zynq_init_machine - System specific initialization, intended to be 71 96 * called from board specific initialization. 72 97 */ 73 98 static void __init zynq_init_machine(void) 74 99 { 75 100 struct platform_device_info devinfo = { .name = "cpufreq-cpu0", }; 101 + struct soc_device_attribute *soc_dev_attr; 102 + struct soc_device *soc_dev; 103 + struct device *parent = NULL; 76 104 77 105 /* 78 106 * 64KB way size, 8-way associativity, parity disabled 79 107 */ 80 108 l2x0_of_init(0x02060000, 0xF0F0FFFF); 81 109 82 - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 110 + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 111 + if (!soc_dev_attr) 112 + goto out; 113 + 114 + system_rev = zynq_get_revision(); 115 + 116 + soc_dev_attr->family = kasprintf(GFP_KERNEL, "Xilinx Zynq"); 117 + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "0x%x", system_rev); 118 + soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "0x%x", 119 + zynq_slcr_get_device_id()); 120 + 121 + soc_dev = soc_device_register(soc_dev_attr); 122 + if (IS_ERR(soc_dev)) { 123 + kfree(soc_dev_attr->family); 124 + kfree(soc_dev_attr->revision); 125 + kfree(soc_dev_attr->soc_id); 126 + kfree(soc_dev_attr); 127 + goto out; 128 + } 129 + 130 + parent = soc_device_to_device(soc_dev); 131 + 132 + out: 133 + /* 134 + * Finished with the static registrations now; fill in the missing 135 + * devices 136 + */ 137 + of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); 83 138 84 139 platform_device_register(&zynq_cpuidle_device); 85 140 platform_device_register_full(&devinfo);
+1
arch/arm/mach-zynq/common.h
··· 24 24 extern void zynq_slcr_system_reset(void); 25 25 extern void zynq_slcr_cpu_stop(int cpu); 26 26 extern void zynq_slcr_cpu_start(int cpu); 27 + extern u32 zynq_slcr_get_device_id(void); 27 28 28 29 #ifdef CONFIG_SMP 29 30 extern void secondary_startup(void);
+19
arch/arm/mach-zynq/slcr.c
··· 26 26 #define SLCR_PS_RST_CTRL_OFFSET 0x200 /* PS Software Reset Control */ 27 27 #define SLCR_A9_CPU_RST_CTRL_OFFSET 0x244 /* CPU Software Reset Control */ 28 28 #define SLCR_REBOOT_STATUS_OFFSET 0x258 /* PS Reboot Status */ 29 + #define SLCR_PSS_IDCODE 0x530 /* PS IDCODE */ 29 30 30 31 #define SLCR_UNLOCK_MAGIC 0xDF0D 31 32 #define SLCR_A9_CPU_CLKSTOP 0x10 32 33 #define SLCR_A9_CPU_RST 0x1 34 + #define SLCR_PSS_IDCODE_DEVICE_SHIFT 12 35 + #define SLCR_PSS_IDCODE_DEVICE_MASK 0x1F 33 36 34 37 static void __iomem *zynq_slcr_base; 35 38 static struct regmap *zynq_slcr_regmap; ··· 83 80 zynq_slcr_write(SLCR_UNLOCK_MAGIC, SLCR_UNLOCK_OFFSET); 84 81 85 82 return 0; 83 + } 84 + 85 + /** 86 + * zynq_slcr_get_device_id - Read device code id 87 + * 88 + * Return: Device code id 89 + */ 90 + u32 zynq_slcr_get_device_id(void) 91 + { 92 + u32 val; 93 + 94 + zynq_slcr_read(&val, SLCR_PSS_IDCODE); 95 + val >>= SLCR_PSS_IDCODE_DEVICE_SHIFT; 96 + val &= SLCR_PSS_IDCODE_DEVICE_MASK; 97 + 98 + return val; 86 99 } 87 100 88 101 /**