From b5cc96d3bfcbc495a350f78aa2e1295b238d26da Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Mon, 20 Jan 2020 14:51:28 +0200 Subject: soc: imx: gpcv2: include linux/sizes.h This header is included indirectly on arm/arm64 but not on x86 so CONFIG_COMPILE_TEST breaks. Fix by including directly. Signed-off-by: Leonard Crestez Signed-off-by: Shawn Guo --- drivers/soc/imx/gpcv2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc/imx') diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index b0dffb06c05d..6cf8a7a412bd 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From fc40200ebf82fae3e40c4e88246496644edafe66 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 21 Feb 2020 10:32:19 +0800 Subject: soc: imx: increase build coverage for imx8m soc driver The soc-imx8.c driver is actually for i.MX8M family, so rename it to soc-imx8m.c. Use CONFIG_SOC_IMX8M as build gate, not CONFIG_ARCH_MXC, to control whether build this driver, also make it possible for compile test. Default set it to y for ARCH_MXC && ARM64 Signed-off-by: Peng Fan Reviewed-by: Leonard Crestez Signed-off-by: Shawn Guo --- drivers/soc/imx/Kconfig | 9 ++ drivers/soc/imx/Makefile | 2 +- drivers/soc/imx/soc-imx8.c | 230 -------------------------------------------- drivers/soc/imx/soc-imx8m.c | 230 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 240 insertions(+), 231 deletions(-) delete mode 100644 drivers/soc/imx/soc-imx8.c create mode 100644 drivers/soc/imx/soc-imx8m.c (limited to 'drivers/soc/imx') diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig index 0281ef9a1800..70019cefa617 100644 --- a/drivers/soc/imx/Kconfig +++ b/drivers/soc/imx/Kconfig @@ -17,4 +17,13 @@ config IMX_SCU_SOC Controller Unit SoC info module, it will provide the SoC info like SoC family, ID and revision etc. +config SOC_IMX8M + bool "i.MX8M SoC family support" + depends on ARCH_MXC || COMPILE_TEST + default ARCH_MXC && ARM64 + help + If you say yes here you get support for the NXP i.MX8M family + support, it will provide the SoC info like SoC family, + ID and revision etc. + endmenu diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile index cf9ca42ff739..103e2c93c342 100644 --- a/drivers/soc/imx/Makefile +++ b/drivers/soc/imx/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o -obj-$(CONFIG_ARCH_MXC) += soc-imx8.o +obj-$(CONFIG_SOC_IMX8M) += soc-imx8m.o obj-$(CONFIG_IMX_SCU_SOC) += soc-imx-scu.o diff --git a/drivers/soc/imx/soc-imx8.c b/drivers/soc/imx/soc-imx8.c deleted file mode 100644 index 719e1f189ebf..000000000000 --- a/drivers/soc/imx/soc-imx8.c +++ /dev/null @@ -1,230 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright 2019 NXP. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define REV_B1 0x21 - -#define IMX8MQ_SW_INFO_B1 0x40 -#define IMX8MQ_SW_MAGIC_B1 0xff0055aa - -#define IMX_SIP_GET_SOC_INFO 0xc2000006 - -#define OCOTP_UID_LOW 0x410 -#define OCOTP_UID_HIGH 0x420 - -/* Same as ANADIG_DIGPROG_IMX7D */ -#define ANADIG_DIGPROG_IMX8MM 0x800 - -struct imx8_soc_data { - char *name; - u32 (*soc_revision)(void); -}; - -static u64 soc_uid; - -#ifdef CONFIG_HAVE_ARM_SMCCC -static u32 imx8mq_soc_revision_from_atf(void) -{ - struct arm_smccc_res res; - - arm_smccc_smc(IMX_SIP_GET_SOC_INFO, 0, 0, 0, 0, 0, 0, 0, &res); - - if (res.a0 == SMCCC_RET_NOT_SUPPORTED) - return 0; - else - return res.a0 & 0xff; -} -#else -static inline u32 imx8mq_soc_revision_from_atf(void) { return 0; }; -#endif - -static u32 __init imx8mq_soc_revision(void) -{ - struct device_node *np; - void __iomem *ocotp_base; - u32 magic; - u32 rev = 0; - - np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp"); - if (!np) - goto out; - - ocotp_base = of_iomap(np, 0); - WARN_ON(!ocotp_base); - - /* - * SOC revision on older imx8mq is not available in fuses so query - * the value from ATF instead. - */ - rev = imx8mq_soc_revision_from_atf(); - if (!rev) { - magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1); - if (magic == IMX8MQ_SW_MAGIC_B1) - rev = REV_B1; - } - - soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH); - soc_uid <<= 32; - soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW); - - iounmap(ocotp_base); - -out: - of_node_put(np); - return rev; -} - -static void __init imx8mm_soc_uid(void) -{ - void __iomem *ocotp_base; - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-ocotp"); - if (!np) - return; - - ocotp_base = of_iomap(np, 0); - WARN_ON(!ocotp_base); - - soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH); - soc_uid <<= 32; - soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW); - - iounmap(ocotp_base); - of_node_put(np); -} - -static u32 __init imx8mm_soc_revision(void) -{ - struct device_node *np; - void __iomem *anatop_base; - u32 rev; - - np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop"); - if (!np) - return 0; - - anatop_base = of_iomap(np, 0); - WARN_ON(!anatop_base); - - rev = readl_relaxed(anatop_base + ANADIG_DIGPROG_IMX8MM); - - iounmap(anatop_base); - of_node_put(np); - - imx8mm_soc_uid(); - - return rev; -} - -static const struct imx8_soc_data imx8mq_soc_data = { - .name = "i.MX8MQ", - .soc_revision = imx8mq_soc_revision, -}; - -static const struct imx8_soc_data imx8mm_soc_data = { - .name = "i.MX8MM", - .soc_revision = imx8mm_soc_revision, -}; - -static const struct imx8_soc_data imx8mn_soc_data = { - .name = "i.MX8MN", - .soc_revision = imx8mm_soc_revision, -}; - -static const struct imx8_soc_data imx8mp_soc_data = { - .name = "i.MX8MP", - .soc_revision = imx8mm_soc_revision, -}; - -static const struct of_device_id imx8_soc_match[] = { - { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, }, - { .compatible = "fsl,imx8mm", .data = &imx8mm_soc_data, }, - { .compatible = "fsl,imx8mn", .data = &imx8mn_soc_data, }, - { .compatible = "fsl,imx8mp", .data = &imx8mp_soc_data, }, - { } -}; - -#define imx8_revision(soc_rev) \ - soc_rev ? \ - kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \ - "unknown" - -static int __init imx8_soc_init(void) -{ - struct soc_device_attribute *soc_dev_attr; - struct soc_device *soc_dev; - const struct of_device_id *id; - u32 soc_rev = 0; - const struct imx8_soc_data *data; - int ret; - - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); - if (!soc_dev_attr) - return -ENOMEM; - - soc_dev_attr->family = "Freescale i.MX"; - - ret = of_property_read_string(of_root, "model", &soc_dev_attr->machine); - if (ret) - goto free_soc; - - id = of_match_node(imx8_soc_match, of_root); - if (!id) { - ret = -ENODEV; - goto free_soc; - } - - data = id->data; - if (data) { - soc_dev_attr->soc_id = data->name; - if (data->soc_revision) - soc_rev = data->soc_revision(); - } - - soc_dev_attr->revision = imx8_revision(soc_rev); - if (!soc_dev_attr->revision) { - ret = -ENOMEM; - goto free_soc; - } - - soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid); - if (!soc_dev_attr->serial_number) { - ret = -ENOMEM; - goto free_rev; - } - - soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR(soc_dev)) { - ret = PTR_ERR(soc_dev); - goto free_serial_number; - } - - pr_info("SoC: %s revision %s\n", soc_dev_attr->soc_id, - soc_dev_attr->revision); - - if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT)) - platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0); - - return 0; - -free_serial_number: - kfree(soc_dev_attr->serial_number); -free_rev: - if (strcmp(soc_dev_attr->revision, "unknown")) - kfree(soc_dev_attr->revision); -free_soc: - kfree(soc_dev_attr); - return ret; -} -device_initcall(imx8_soc_init); diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c new file mode 100644 index 000000000000..719e1f189ebf --- /dev/null +++ b/drivers/soc/imx/soc-imx8m.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 NXP. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define REV_B1 0x21 + +#define IMX8MQ_SW_INFO_B1 0x40 +#define IMX8MQ_SW_MAGIC_B1 0xff0055aa + +#define IMX_SIP_GET_SOC_INFO 0xc2000006 + +#define OCOTP_UID_LOW 0x410 +#define OCOTP_UID_HIGH 0x420 + +/* Same as ANADIG_DIGPROG_IMX7D */ +#define ANADIG_DIGPROG_IMX8MM 0x800 + +struct imx8_soc_data { + char *name; + u32 (*soc_revision)(void); +}; + +static u64 soc_uid; + +#ifdef CONFIG_HAVE_ARM_SMCCC +static u32 imx8mq_soc_revision_from_atf(void) +{ + struct arm_smccc_res res; + + arm_smccc_smc(IMX_SIP_GET_SOC_INFO, 0, 0, 0, 0, 0, 0, 0, &res); + + if (res.a0 == SMCCC_RET_NOT_SUPPORTED) + return 0; + else + return res.a0 & 0xff; +} +#else +static inline u32 imx8mq_soc_revision_from_atf(void) { return 0; }; +#endif + +static u32 __init imx8mq_soc_revision(void) +{ + struct device_node *np; + void __iomem *ocotp_base; + u32 magic; + u32 rev = 0; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp"); + if (!np) + goto out; + + ocotp_base = of_iomap(np, 0); + WARN_ON(!ocotp_base); + + /* + * SOC revision on older imx8mq is not available in fuses so query + * the value from ATF instead. + */ + rev = imx8mq_soc_revision_from_atf(); + if (!rev) { + magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1); + if (magic == IMX8MQ_SW_MAGIC_B1) + rev = REV_B1; + } + + soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH); + soc_uid <<= 32; + soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW); + + iounmap(ocotp_base); + +out: + of_node_put(np); + return rev; +} + +static void __init imx8mm_soc_uid(void) +{ + void __iomem *ocotp_base; + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-ocotp"); + if (!np) + return; + + ocotp_base = of_iomap(np, 0); + WARN_ON(!ocotp_base); + + soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH); + soc_uid <<= 32; + soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW); + + iounmap(ocotp_base); + of_node_put(np); +} + +static u32 __init imx8mm_soc_revision(void) +{ + struct device_node *np; + void __iomem *anatop_base; + u32 rev; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop"); + if (!np) + return 0; + + anatop_base = of_iomap(np, 0); + WARN_ON(!anatop_base); + + rev = readl_relaxed(anatop_base + ANADIG_DIGPROG_IMX8MM); + + iounmap(anatop_base); + of_node_put(np); + + imx8mm_soc_uid(); + + return rev; +} + +static const struct imx8_soc_data imx8mq_soc_data = { + .name = "i.MX8MQ", + .soc_revision = imx8mq_soc_revision, +}; + +static const struct imx8_soc_data imx8mm_soc_data = { + .name = "i.MX8MM", + .soc_revision = imx8mm_soc_revision, +}; + +static const struct imx8_soc_data imx8mn_soc_data = { + .name = "i.MX8MN", + .soc_revision = imx8mm_soc_revision, +}; + +static const struct imx8_soc_data imx8mp_soc_data = { + .name = "i.MX8MP", + .soc_revision = imx8mm_soc_revision, +}; + +static const struct of_device_id imx8_soc_match[] = { + { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, }, + { .compatible = "fsl,imx8mm", .data = &imx8mm_soc_data, }, + { .compatible = "fsl,imx8mn", .data = &imx8mn_soc_data, }, + { .compatible = "fsl,imx8mp", .data = &imx8mp_soc_data, }, + { } +}; + +#define imx8_revision(soc_rev) \ + soc_rev ? \ + kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \ + "unknown" + +static int __init imx8_soc_init(void) +{ + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + const struct of_device_id *id; + u32 soc_rev = 0; + const struct imx8_soc_data *data; + int ret; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->family = "Freescale i.MX"; + + ret = of_property_read_string(of_root, "model", &soc_dev_attr->machine); + if (ret) + goto free_soc; + + id = of_match_node(imx8_soc_match, of_root); + if (!id) { + ret = -ENODEV; + goto free_soc; + } + + data = id->data; + if (data) { + soc_dev_attr->soc_id = data->name; + if (data->soc_revision) + soc_rev = data->soc_revision(); + } + + soc_dev_attr->revision = imx8_revision(soc_rev); + if (!soc_dev_attr->revision) { + ret = -ENOMEM; + goto free_soc; + } + + soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid); + if (!soc_dev_attr->serial_number) { + ret = -ENOMEM; + goto free_rev; + } + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + ret = PTR_ERR(soc_dev); + goto free_serial_number; + } + + pr_info("SoC: %s revision %s\n", soc_dev_attr->soc_id, + soc_dev_attr->revision); + + if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT)) + platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0); + + return 0; + +free_serial_number: + kfree(soc_dev_attr->serial_number); +free_rev: + if (strcmp(soc_dev_attr->revision, "unknown")) + kfree(soc_dev_attr->revision); +free_soc: + kfree(soc_dev_attr); + return ret; +} +device_initcall(imx8_soc_init); -- cgit v1.2.3 From e0ea2d11f8a08ba7066ff897e16c5217215d1e68 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 13 Mar 2020 11:09:12 +0100 Subject: soc: imx: gpc: fix power up sequencing Currently we wait only until the PGC inverts the isolation setting before disabling the peripheral clocks. This doesn't ensure that the reset is properly propagated through the peripheral devices in the power domain. Wait until the PGC signals that the power up request is done and wait a bit for resets to propagate before disabling the clocks. Signed-off-by: Lucas Stach Signed-off-by: Shawn Guo --- drivers/soc/imx/gpc.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/soc/imx') diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index 98b9d9a902ae..90a8b2c0676f 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c @@ -87,8 +87,8 @@ static int imx6_pm_domain_power_off(struct generic_pm_domain *genpd) static int imx6_pm_domain_power_on(struct generic_pm_domain *genpd) { struct imx_pm_domain *pd = to_imx_pm_domain(genpd); - int i, ret, sw, sw2iso; - u32 val; + int i, ret; + u32 val, req; if (pd->supply) { ret = regulator_enable(pd->supply); @@ -107,17 +107,18 @@ static int imx6_pm_domain_power_on(struct generic_pm_domain *genpd) regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS, 0x1, 0x1); - /* Read ISO and ISO2SW power up delays */ - regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PUPSCR_OFFS, &val); - sw = val & 0x3f; - sw2iso = (val >> 8) & 0x3f; - /* Request GPC to power up domain */ - val = BIT(pd->cntr_pdn_bit + 1); - regmap_update_bits(pd->regmap, GPC_CNTR, val, val); + req = BIT(pd->cntr_pdn_bit + 1); + regmap_update_bits(pd->regmap, GPC_CNTR, req, req); - /* Wait ISO + ISO2SW IPG clock cycles */ - udelay(DIV_ROUND_UP(sw + sw2iso, pd->ipg_rate_mhz)); + /* Wait for the PGC to handle the request */ + ret = regmap_read_poll_timeout(pd->regmap, GPC_CNTR, val, !(val & req), + 1, 50); + if (ret) + pr_err("powerup request on domain %s timed out\n", genpd->name); + + /* Wait for reset to propagate through peripherals */ + usleep_range(5, 10); /* Disable reset clocks for all devices in the domain */ for (i = 0; i < pd->num_clks; i++) @@ -343,6 +344,7 @@ static const struct regmap_config imx_gpc_regmap_config = { .rd_table = &access_table, .wr_table = &access_table, .max_register = 0x2ac, + .fast_io = true, }; static struct generic_pm_domain *imx_gpc_onecell_domains[] = { -- cgit v1.2.3 From 2a52651292ad9e642d205ce2ece2686d3b3395a7 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 16 Mar 2020 11:09:02 +0800 Subject: soc: imx: drop COMPILE_TEST for IMX_SCU_SOC With COMPILE_TEST, there will be build error, because IMX_SCU might be set to n, so drop COMPILE_TEST. Suggested-by: Shawn Guo Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/soc/imx/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc/imx') diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig index 70019cefa617..67aa94b2481b 100644 --- a/drivers/soc/imx/Kconfig +++ b/drivers/soc/imx/Kconfig @@ -10,7 +10,7 @@ config IMX_GPCV2_PM_DOMAINS config IMX_SCU_SOC bool "i.MX System Controller Unit SoC info support" - depends on IMX_SCU || COMPILE_TEST + depends on IMX_SCU select SOC_BUS help If you say yes here you get support for the NXP i.MX System -- cgit v1.2.3