Patchwork ARM: mxs: Use soc bus infrastructure

login
register
mail settings
Submitter Fabio Estevam
Date June 3, 2013, 10:52 p.m.
Message ID <1370299944-7656-1-git-send-email-festevam@gmail.com>
Download mbox | patch
Permalink /patch/248438/
State New
Headers show

Comments

Fabio Estevam - June 3, 2013, 10:52 p.m.
From: Fabio Estevam <fabio.estevam@freescale.com>

Using the soc bus infrastructure is helpful for reporting several SoC related
information such as: family, machine, SoC name and SoC revision.

$ cat /sys/bus/soc/devices/soc0/family 
Freescale MXS Family

$ cat /sys/bus/soc/devices/soc0/machine 
Freescale i.MX28 Evaluation Kit

$ cat /sys/bus/soc/devices/soc0/soc_id 
i.MX28

$ cat /sys/bus/soc/devices/soc0/revision 
TO1.2 

Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
---
 arch/arm/mach-mxs/Kconfig    |   1 +
 arch/arm/mach-mxs/mach-mxs.c | 117 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 117 insertions(+), 1 deletion(-)
Shawn Guo - June 4, 2013, 3:53 a.m.
On Mon, Jun 03, 2013 at 07:52:24PM -0300, Fabio Estevam wrote:
> From: Fabio Estevam <fabio.estevam@freescale.com>
> 
> Using the soc bus infrastructure is helpful for reporting several SoC related
> information such as: family, machine, SoC name and SoC revision.
> 
> $ cat /sys/bus/soc/devices/soc0/family 
> Freescale MXS Family
> 
> $ cat /sys/bus/soc/devices/soc0/machine 
> Freescale i.MX28 Evaluation Kit
> 
> $ cat /sys/bus/soc/devices/soc0/soc_id 
> i.MX28
> 
> $ cat /sys/bus/soc/devices/soc0/revision 
> TO1.2 
> 
> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
> ---
>  arch/arm/mach-mxs/Kconfig    |   1 +
>  arch/arm/mach-mxs/mach-mxs.c | 117 ++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 117 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
> index 4dc2fbb..59c30ef 100644
> --- a/arch/arm/mach-mxs/Kconfig
> +++ b/arch/arm/mach-mxs/Kconfig
> @@ -25,6 +25,7 @@ config ARCH_MXS
>  	select GENERIC_CLOCKEVENTS
>  	select HAVE_CLK_PREPARE
>  	select PINCTRL
> +	select SOC_BUS
>  	select SOC_IMX23
>  	select SOC_IMX28
>  	select STMP_DEVICE
> diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c
> index bd225e9..bc72393 100644
> --- a/arch/arm/mach-mxs/mach-mxs.c
> +++ b/arch/arm/mach-mxs/mach-mxs.c
> @@ -25,6 +25,7 @@
>  #include <linux/of_platform.h>
>  #include <linux/phy.h>
>  #include <linux/pinctrl/consumer.h>
> +#include <linux/sys_soc.h>
>  #include <asm/mach/arch.h>
>  #include <asm/mach/map.h>
>  #include <asm/mach/time.h>
> @@ -38,12 +39,27 @@
>  #define MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0		0x2
>  #define MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR1		0x3
>  
> +#define HW_DIGCTL_CHIPID	0x310
> +#define HW_DIGCTL_CHIPID_MASK	(0xffff << 16)
> +#define HW_DIGCTL_REV_MASK	0xff
> +#define HW_DIGCTL_CHIPID_MX23	(0x3780 << 16)
> +#define HW_DIGCTL_CHIPID_MX28	(0x2800 << 16)
> +
> +#define MXS_CHIP_REVISION_1_0	0x10
> +#define MXS_CHIP_REVISION_1_1	0x11
> +#define MXS_CHIP_REVISION_1_2	0x12
> +#define MXS_CHIP_REVISION_1_3	0x13
> +#define MXS_CHIP_REVISION_1_4	0x14
> +#define MXS_CHIP_REV_UNKNOWN	0xff
> +
>  #define MXS_GPIO_NR(bank, nr)	((bank) * 32 + (nr))
>  
>  #define MXS_SET_ADDR		0x4
>  #define MXS_CLR_ADDR		0x8
>  #define MXS_TOG_ADDR		0xc
>  
> +static void __iomem *digctl_base;
> +

Rather than defining a static base address for reading the same register
multiple times, I would suggest we define static variables to hold id
and revision with accessing register only once.  In that case, the
digctl_base can be a local variable in function and could be unmapped
after we're done with it.

>  static inline void __mxs_setl(u32 mask, void __iomem *reg)
>  {
>  	__raw_writel(mask, reg + MXS_SET_ADDR);
> @@ -361,8 +377,107 @@ static void __init cfa10037_init(void)
>  	update_fec_mac_prop(OUI_CRYSTALFONTZ);
>  }
>  
> +static const char __init *mxs_get_soc_id(void)
> +{
> +	u32 socid;
> +	struct device_node *np;
> +
> +	np = of_find_compatible_node(NULL, NULL, "fsl,imx28-digctl");

It will fail to find the node when running on i.MX23.  It seems we need
to change the digctl node in imx28 device tree as below, and then use
"fsl,imx23-digctl" to find the node.

  compatible = "fsl,imx28-digctl", "fsl,imx23-digctl"

> +	digctl_base = of_iomap(np, 0);
> +	WARN_ON(!digctl_base);
> +
> +	socid = readl(digctl_base + HW_DIGCTL_CHIPID) & HW_DIGCTL_CHIPID_MASK;
> +	switch (socid) {
> +	case HW_DIGCTL_CHIPID_MX23:
> +		return "i.MX23";
> +	case HW_DIGCTL_CHIPID_MX28:
> +		return "i.MX28";
> +	default:
> +		return "unknown";
> +	}
> +}
> +
> +static int __init mxs_get_cpu_rev(void)
> +{
> +	u32 socid, rev;
> +
> +	socid = readl(digctl_base + HW_DIGCTL_CHIPID) & HW_DIGCTL_CHIPID_MASK;
> +	rev = readl(digctl_base + HW_DIGCTL_CHIPID) & HW_DIGCTL_REV_MASK;
> +
> +	switch (socid) {
> +	case HW_DIGCTL_CHIPID_MX23:
> +		switch (rev) {
> +		case 0x0:
> +			return MXS_CHIP_REVISION_1_0;
> +		case 0x1:
> +			return MXS_CHIP_REVISION_1_1;
> +		case 0x2:
> +			return MXS_CHIP_REVISION_1_2;
> +		case 0x3:
> +			return MXS_CHIP_REVISION_1_3;
> +		case 0x4:
> +			return MXS_CHIP_REVISION_1_4;
> +		default:
> +			return MXS_CHIP_REV_UNKNOWN;
> +		}
> +	case HW_DIGCTL_CHIPID_MX28:
> +		switch (rev) {
> +		case 0x0:
> +			return MXS_CHIP_REVISION_1_1;
> +		case 0x1:
> +			return MXS_CHIP_REVISION_1_2;
> +		default:
> +			return MXS_CHIP_REV_UNKNOWN;
> +		}
> +	default:
> +		return MXS_CHIP_REV_UNKNOWN;
> +	}

I do not understand why we need to set up all these mapping at all.  I
think all we need is reporting the revision in the format you gave
below.

  kasprintf(GFP_KERNEL, "TO%d.%d", (rev >> 4) & 0xf, rev & 0xf);

> +}
> +
> +static const char __init *mxs_get_revision(void)
> +{
> +	u32 rev = mxs_get_cpu_rev();
> +
> +	if (rev != MXS_CHIP_REV_UNKNOWN)
> +		return kasprintf(GFP_KERNEL, "TO%d.%d", (rev >> 4) & 0xf,
> +				rev & 0xf);
> +
> +	else
> +		return kasprintf(GFP_KERNEL, "%s", "Unknown");
> +}
> +
>  static void __init mxs_machine_init(void)
>  {
> +	struct device_node *root;
> +	struct device *parent;
> +	struct soc_device *soc_dev;
> +	struct soc_device_attribute *soc_dev_attr;
> +	int ret;
> +
> +	root = of_find_node_by_path("/");
> +	if (!root)
> +		return;

I do not think the check is needed.  We will never get here if there is
no device tree root node.

> +
> +	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
> +	if (!soc_dev_attr)
> +		return;
> +
> +	ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
> +	if (ret)
> +		return;
> +
> +	soc_dev_attr->family = "Freescale MXS Family";
> +	soc_dev_attr->soc_id = mxs_get_soc_id();
> +	soc_dev_attr->revision = mxs_get_revision();
> +
> +	soc_dev = soc_device_register(soc_dev_attr);
> +	if (IS_ERR(soc_dev)) {

soc_dev_attr->revision should be freed.

Shawn

> +		kfree(soc_dev_attr);
> +		return;
> +	}
> +
> +	parent = soc_device_to_device(soc_dev);
> +
>  	if (of_machine_is_compatible("fsl,imx28-evk"))
>  		imx28_evk_init();
>  	else if (of_machine_is_compatible("bluegiga,apx4devkit"))
> @@ -373,7 +488,7 @@ static void __init mxs_machine_init(void)
>  		cfa10049_init();
>  
>  	of_platform_populate(NULL, of_default_bus_match_table,
> -			     mxs_auxdata_lookup, NULL);
> +			     mxs_auxdata_lookup, parent);
>  
>  	if (of_machine_is_compatible("karo,tx28"))
>  		tx28_post_init();
> -- 
> 1.8.1.2
>

Patch

diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index 4dc2fbb..59c30ef 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -25,6 +25,7 @@  config ARCH_MXS
 	select GENERIC_CLOCKEVENTS
 	select HAVE_CLK_PREPARE
 	select PINCTRL
+	select SOC_BUS
 	select SOC_IMX23
 	select SOC_IMX28
 	select STMP_DEVICE
diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c
index bd225e9..bc72393 100644
--- a/arch/arm/mach-mxs/mach-mxs.c
+++ b/arch/arm/mach-mxs/mach-mxs.c
@@ -25,6 +25,7 @@ 
 #include <linux/of_platform.h>
 #include <linux/phy.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/sys_soc.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
@@ -38,12 +39,27 @@ 
 #define MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0		0x2
 #define MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR1		0x3
 
+#define HW_DIGCTL_CHIPID	0x310
+#define HW_DIGCTL_CHIPID_MASK	(0xffff << 16)
+#define HW_DIGCTL_REV_MASK	0xff
+#define HW_DIGCTL_CHIPID_MX23	(0x3780 << 16)
+#define HW_DIGCTL_CHIPID_MX28	(0x2800 << 16)
+
+#define MXS_CHIP_REVISION_1_0	0x10
+#define MXS_CHIP_REVISION_1_1	0x11
+#define MXS_CHIP_REVISION_1_2	0x12
+#define MXS_CHIP_REVISION_1_3	0x13
+#define MXS_CHIP_REVISION_1_4	0x14
+#define MXS_CHIP_REV_UNKNOWN	0xff
+
 #define MXS_GPIO_NR(bank, nr)	((bank) * 32 + (nr))
 
 #define MXS_SET_ADDR		0x4
 #define MXS_CLR_ADDR		0x8
 #define MXS_TOG_ADDR		0xc
 
+static void __iomem *digctl_base;
+
 static inline void __mxs_setl(u32 mask, void __iomem *reg)
 {
 	__raw_writel(mask, reg + MXS_SET_ADDR);
@@ -361,8 +377,107 @@  static void __init cfa10037_init(void)
 	update_fec_mac_prop(OUI_CRYSTALFONTZ);
 }
 
+static const char __init *mxs_get_soc_id(void)
+{
+	u32 socid;
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx28-digctl");
+	digctl_base = of_iomap(np, 0);
+	WARN_ON(!digctl_base);
+
+	socid = readl(digctl_base + HW_DIGCTL_CHIPID) & HW_DIGCTL_CHIPID_MASK;
+	switch (socid) {
+	case HW_DIGCTL_CHIPID_MX23:
+		return "i.MX23";
+	case HW_DIGCTL_CHIPID_MX28:
+		return "i.MX28";
+	default:
+		return "unknown";
+	}
+}
+
+static int __init mxs_get_cpu_rev(void)
+{
+	u32 socid, rev;
+
+	socid = readl(digctl_base + HW_DIGCTL_CHIPID) & HW_DIGCTL_CHIPID_MASK;
+	rev = readl(digctl_base + HW_DIGCTL_CHIPID) & HW_DIGCTL_REV_MASK;
+
+	switch (socid) {
+	case HW_DIGCTL_CHIPID_MX23:
+		switch (rev) {
+		case 0x0:
+			return MXS_CHIP_REVISION_1_0;
+		case 0x1:
+			return MXS_CHIP_REVISION_1_1;
+		case 0x2:
+			return MXS_CHIP_REVISION_1_2;
+		case 0x3:
+			return MXS_CHIP_REVISION_1_3;
+		case 0x4:
+			return MXS_CHIP_REVISION_1_4;
+		default:
+			return MXS_CHIP_REV_UNKNOWN;
+		}
+	case HW_DIGCTL_CHIPID_MX28:
+		switch (rev) {
+		case 0x0:
+			return MXS_CHIP_REVISION_1_1;
+		case 0x1:
+			return MXS_CHIP_REVISION_1_2;
+		default:
+			return MXS_CHIP_REV_UNKNOWN;
+		}
+	default:
+		return MXS_CHIP_REV_UNKNOWN;
+	}
+}
+
+static const char __init *mxs_get_revision(void)
+{
+	u32 rev = mxs_get_cpu_rev();
+
+	if (rev != MXS_CHIP_REV_UNKNOWN)
+		return kasprintf(GFP_KERNEL, "TO%d.%d", (rev >> 4) & 0xf,
+				rev & 0xf);
+
+	else
+		return kasprintf(GFP_KERNEL, "%s", "Unknown");
+}
+
 static void __init mxs_machine_init(void)
 {
+	struct device_node *root;
+	struct device *parent;
+	struct soc_device *soc_dev;
+	struct soc_device_attribute *soc_dev_attr;
+	int ret;
+
+	root = of_find_node_by_path("/");
+	if (!root)
+		return;
+
+	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+	if (!soc_dev_attr)
+		return;
+
+	ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
+	if (ret)
+		return;
+
+	soc_dev_attr->family = "Freescale MXS Family";
+	soc_dev_attr->soc_id = mxs_get_soc_id();
+	soc_dev_attr->revision = mxs_get_revision();
+
+	soc_dev = soc_device_register(soc_dev_attr);
+	if (IS_ERR(soc_dev)) {
+		kfree(soc_dev_attr);
+		return;
+	}
+
+	parent = soc_device_to_device(soc_dev);
+
 	if (of_machine_is_compatible("fsl,imx28-evk"))
 		imx28_evk_init();
 	else if (of_machine_is_compatible("bluegiga,apx4devkit"))
@@ -373,7 +488,7 @@  static void __init mxs_machine_init(void)
 		cfa10049_init();
 
 	of_platform_populate(NULL, of_default_bus_match_table,
-			     mxs_auxdata_lookup, NULL);
+			     mxs_auxdata_lookup, parent);
 
 	if (of_machine_is_compatible("karo,tx28"))
 		tx28_post_init();