From 00f7dc636366f72474b1896f4990b3c086cd2c6d Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 31 Jul 2013 09:19:59 +0200 Subject: [PATCH] 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 --- arch/arm/boot/dts/zynq-7000.dtsi | 5 +++ arch/arm/mach-zynq/Kconfig | 1 + arch/arm/mach-zynq/common.c | 71 +++++++++++++++++++++++++++++++- arch/arm/mach-zynq/common.h | 1 + arch/arm/mach-zynq/slcr.c | 19 +++++++++ 5 files changed, 96 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi index 511180769af5..f55bf53da7d1 100644 --- a/arch/arm/boot/dts/zynq-7000.dtsi +++ b/arch/arm/boot/dts/zynq-7000.dtsi @@ -154,6 +154,11 @@ }; }; + devcfg: devcfg@f8007000 { + compatible = "xlnx,zynq-devcfg-1.0"; + reg = <0xf8007000 0x100>; + } ; + global_timer: timer@f8f00200 { compatible = "arm,cortex-a9-global-timer"; reg = <0xf8f00200 0x20>; diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig index 58c2b844e0a3..77cb52ed4b16 100644 --- a/arch/arm/mach-zynq/Kconfig +++ b/arch/arm/mach-zynq/Kconfig @@ -10,5 +10,6 @@ config ARCH_ZYNQ select CADENCE_TTC_TIMER select ARM_GLOBAL_TIMER if !CPU_FREQ select MFD_SYSCON + select SOC_BUS help Support for Xilinx Zynq ARM Cortex A9 Platform diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 6fcc584c1a11..edbd9d83f407 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -37,10 +39,15 @@ #include #include #include +#include #include #include "common.h" +#define ZYNQ_DEVCFG_MCTRL 0x80 +#define ZYNQ_DEVCFG_PS_VERSION_SHIFT 28 +#define ZYNQ_DEVCFG_PS_VERSION_MASK 0xF + void __iomem *zynq_scu_base; /** @@ -59,6 +66,38 @@ static struct platform_device zynq_cpuidle_device = { .name = "cpuidle-zynq", }; +/** + * zynq_get_revision - Get Zynq silicon revision + * + * Return: Silicon version or -1 otherwise + */ +static int __init zynq_get_revision(void) +{ + struct device_node *np; + void __iomem *zynq_devcfg_base; + u32 revision; + + np = of_find_compatible_node(NULL, NULL, "xlnx,zynq-devcfg-1.0"); + if (!np) { + pr_err("%s: no devcfg node found\n", __func__); + return -1; + } + + zynq_devcfg_base = of_iomap(np, 0); + if (!zynq_devcfg_base) { + pr_err("%s: Unable to map I/O memory\n", __func__); + return -1; + } + + revision = readl(zynq_devcfg_base + ZYNQ_DEVCFG_MCTRL); + revision >>= ZYNQ_DEVCFG_PS_VERSION_SHIFT; + revision &= ZYNQ_DEVCFG_PS_VERSION_MASK; + + iounmap(zynq_devcfg_base); + + return revision; +} + /** * zynq_init_machine - System specific initialization, intended to be * called from board specific initialization. @@ -66,13 +105,43 @@ static struct platform_device zynq_cpuidle_device = { static void __init zynq_init_machine(void) { struct platform_device_info devinfo = { .name = "cpufreq-cpu0", }; + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + struct device *parent = NULL; /* * 64KB way size, 8-way associativity, parity disabled */ l2x0_of_init(0x02060000, 0xF0F0FFFF); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + goto out; + + system_rev = zynq_get_revision(); + + soc_dev_attr->family = kasprintf(GFP_KERNEL, "Xilinx Zynq"); + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "0x%x", system_rev); + soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "0x%x", + zynq_slcr_get_device_id()); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->family); + kfree(soc_dev_attr->revision); + kfree(soc_dev_attr->soc_id); + kfree(soc_dev_attr); + goto out; + } + + parent = soc_device_to_device(soc_dev); + +out: + /* + * Finished with the static registrations now; fill in the missing + * devices + */ + of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); platform_device_register(&zynq_cpuidle_device); platform_device_register_full(&devinfo); diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h index b097844d3175..f652f0a884a6 100644 --- a/arch/arm/mach-zynq/common.h +++ b/arch/arm/mach-zynq/common.h @@ -24,6 +24,7 @@ extern int zynq_early_slcr_init(void); extern void zynq_slcr_system_reset(void); extern void zynq_slcr_cpu_stop(int cpu); extern void zynq_slcr_cpu_start(int cpu); +extern u32 zynq_slcr_get_device_id(void); #ifdef CONFIG_SMP extern void secondary_startup(void); diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c index a37d49a6e657..c43a2d16e223 100644 --- a/arch/arm/mach-zynq/slcr.c +++ b/arch/arm/mach-zynq/slcr.c @@ -26,10 +26,13 @@ #define SLCR_PS_RST_CTRL_OFFSET 0x200 /* PS Software Reset Control */ #define SLCR_A9_CPU_RST_CTRL_OFFSET 0x244 /* CPU Software Reset Control */ #define SLCR_REBOOT_STATUS_OFFSET 0x258 /* PS Reboot Status */ +#define SLCR_PSS_IDCODE 0x530 /* PS IDCODE */ #define SLCR_UNLOCK_MAGIC 0xDF0D #define SLCR_A9_CPU_CLKSTOP 0x10 #define SLCR_A9_CPU_RST 0x1 +#define SLCR_PSS_IDCODE_DEVICE_SHIFT 12 +#define SLCR_PSS_IDCODE_DEVICE_MASK 0x1F static void __iomem *zynq_slcr_base; static struct regmap *zynq_slcr_regmap; @@ -82,6 +85,22 @@ static inline int zynq_slcr_unlock(void) return 0; } +/** + * zynq_slcr_get_device_id - Read device code id + * + * Return: Device code id + */ +u32 zynq_slcr_get_device_id(void) +{ + u32 val; + + zynq_slcr_read(&val, SLCR_PSS_IDCODE); + val >>= SLCR_PSS_IDCODE_DEVICE_SHIFT; + val &= SLCR_PSS_IDCODE_DEVICE_MASK; + + return val; +} + /** * zynq_slcr_system_reset - Reset the entire system. */