diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2024-02-21 07:43:45 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2024-02-21 07:43:45 +0100 |
commit | b83407415e5a2d28a7876b936f1c682d62a0372a (patch) | |
tree | f5f9dd201feec42f7527f9f069aef56eca8c6aa2 /drivers | |
parent | 9fd550e388e2181a6cb9abe9ba06ae25897902fd (diff) | |
parent | 7eedf79ba92912455954ec178822f0a03e9c28e3 (diff) | |
download | barebox-b83407415e5a2d28a7876b936f1c682d62a0372a.tar.gz barebox-b83407415e5a2d28a7876b936f1c682d62a0372a.tar.xz |
Merge branch 'for-next/imx'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/Kconfig | 3 | ||||
-rw-r--r-- | drivers/base/Makefile | 1 | ||||
-rw-r--r-- | drivers/base/soc.c | 123 | ||||
-rw-r--r-- | drivers/ddr/imx/imx8m_ddr_init.c | 6 | ||||
-rw-r--r-- | drivers/hab/hab.c | 137 | ||||
-rw-r--r-- | drivers/hab/hab.h | 10 | ||||
-rw-r--r-- | drivers/hab/habv3.c | 6 | ||||
-rw-r--r-- | drivers/hab/habv4.c | 78 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-imx-lpi2c.c | 70 | ||||
-rw-r--r-- | drivers/nvmem/imx-ocotp-ele.c | 22 | ||||
-rw-r--r-- | drivers/nvmem/ocotp.c | 80 | ||||
-rw-r--r-- | drivers/soc/imx/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/imx/soc-imx8m.c | 296 |
14 files changed, 703 insertions, 132 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 612a84be33..21a4793cfa 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -6,4 +6,7 @@ config PM_GENERIC_DOMAINS config FEATURE_CONTROLLER bool "Feature controller support" if COMPILE_TEST || SANDBOX +config SOC_BUS + bool + source "drivers/base/regmap/Kconfig" diff --git a/drivers/base/Makefile b/drivers/base/Makefile index e8e354cdaa..acc53763da 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -7,3 +7,4 @@ obj-y += regmap/ obj-$(CONFIG_PM_GENERIC_DOMAINS) += power.o obj-$(CONFIG_FEATURE_CONTROLLER) += featctrl.o +obj-$(CONFIG_SOC_BUS) += soc.o diff --git a/drivers/base/soc.c b/drivers/base/soc.c new file mode 100644 index 0000000000..a481f8987b --- /dev/null +++ b/drivers/base/soc.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2024 Marco Felsch, Pengutronix +/* + * Based on Linux drivers/base/soc.c: + * Copyright (C) ST-Ericsson SA 2011 + */ + +#include <common.h> +#include <init.h> +#include <of.h> + +#include <linux/slab.h> +#include <linux/sys_soc.h> +#include <linux/err.h> + +struct soc_device { + struct device dev; + struct soc_device_attribute *attr; +}; + +static struct bus_type soc_bus_type = { + .name = "soc", +}; +static bool soc_bus_registered; + +static void soc_device_add_params(struct soc_device *soc_dev) +{ + struct soc_device_attribute *attr = soc_dev->attr; + struct device *dev = &soc_dev->dev; + + if (attr->machine) + dev_add_param_string_fixed(dev, "machine", attr->machine); + if (attr->family) + dev_add_param_string_fixed(dev, "family", attr->family); + if (attr->revision) + dev_add_param_string_fixed(dev, "revision", attr->revision); + if (attr->serial_number) + dev_add_param_string_fixed(dev, "serial_number", attr->serial_number); + if (attr->soc_id) + dev_add_param_string_fixed(dev, "soc_id", attr->soc_id); +} + +static void soc_device_get_machine(struct soc_device_attribute *soc_dev_attr) +{ + struct device_node *np; + + if (soc_dev_attr->machine) + return; + + np = of_find_node_by_path("/"); + of_property_read_string(np, "model", &soc_dev_attr->machine); + of_node_put(np); +} + +static struct soc_device_attribute *early_soc_dev_attr; + +struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr) +{ + struct soc_device *soc_dev; + int ret; + + soc_device_get_machine(soc_dev_attr); + + if (!soc_bus_registered) { + if (early_soc_dev_attr) + return ERR_PTR(-EBUSY); + early_soc_dev_attr = soc_dev_attr; + return NULL; + } + + soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL); + if (!soc_dev) { + ret = -ENOMEM; + goto out1; + } + + soc_dev->attr = soc_dev_attr; + soc_dev->dev.bus = &soc_bus_type; + soc_dev->dev.id = DEVICE_ID_DYNAMIC; + + dev_set_name(&soc_dev->dev, "soc"); + + ret = device_register(&soc_dev->dev); + if (ret) { + put_device(&soc_dev->dev); + goto out2; + } + + soc_device_add_params(soc_dev); + + return soc_dev; + +out2: + kfree(soc_dev); +out1: + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(soc_device_register); + +/* Ensure soc_dev->attr is freed after calling soc_device_unregister. */ +void soc_device_unregister(struct soc_device *soc_dev) +{ + device_unregister(&soc_dev->dev); + kfree(soc_dev); + early_soc_dev_attr = NULL; +} +EXPORT_SYMBOL_GPL(soc_device_unregister); + +static int __init soc_bus_register(void) +{ + int ret; + + ret = bus_register(&soc_bus_type); + if (ret) + return ret; + soc_bus_registered = true; + + if (early_soc_dev_attr) + return PTR_ERR(soc_device_register(early_soc_dev_attr)); + + return 0; +} +core_initcall(soc_bus_register); diff --git a/drivers/ddr/imx/imx8m_ddr_init.c b/drivers/ddr/imx/imx8m_ddr_init.c index 8b829645c0..d9a5d589f2 100644 --- a/drivers/ddr/imx/imx8m_ddr_init.c +++ b/drivers/ddr/imx/imx8m_ddr_init.c @@ -219,9 +219,9 @@ enum ddr_rate { DDR_3720, DDR_3200, DDR_3000, - DDR_2600, /* Unused */ + DDR_2600, DDR_2400, - DDR_2376, /* Unused */ + DDR_2376, DDR_1600, DDR_1000, /* Unused */ DDR_1066, @@ -450,7 +450,9 @@ static void ddrphy_init_set_dfi_clk(struct dram_controller *dram, unsigned int d case 3720: drate = DDR_3720; break; case 3200: drate = DDR_3200; break; case 3000: drate = DDR_3000; break; + case 2600: drate = DDR_2600; break; case 2400: drate = DDR_2400; break; + case 2376: drate = DDR_2376; break; case 1600: drate = DDR_1600; break; case 1066: drate = DDR_1066; break; case 667: drate = DDR_667; break; diff --git a/drivers/hab/hab.c b/drivers/hab/hab.c index 75a8cca71e..ed091058d8 100644 --- a/drivers/hab/hab.c +++ b/drivers/hab/hab.c @@ -13,6 +13,9 @@ #include <mach/imx/imx25-fusemap.h> #include <mach/imx/ocotp.h> #include <mach/imx/imx6-fusemap.h> +#include <mach/imx/ele.h> + +#include "hab.h" bool imx_hab_srk_hash_valid(const void *buf) { @@ -94,7 +97,7 @@ static int imx_hab_permanent_write_enable_iim(int enable) return imx_iim_permanent_write(enable); } -static int imx_hab_lockdown_device_iim(void) +static int imx_hab_lockdown_device_iim(unsigned flags) { return imx_iim_write_field(IMX25_IIM_HAB_TYPE, 3); } @@ -150,7 +153,7 @@ static int imx_hab_permanent_write_enable_ocotp(int enable) return imx_ocotp_permanent_write(enable); } -static int imx6_hab_lockdown_device_ocotp(void) +static int imx6_hab_lockdown_device_ocotp(unsigned flags) { int ret; @@ -161,7 +164,7 @@ static int imx6_hab_lockdown_device_ocotp(void) return imx_ocotp_write_field(OCOTP_SEC_CONFIG_1, 1); } -static int imx8m_hab_lockdown_device_ocotp(void) +static int imx8m_hab_lockdown_device_ocotp(unsigned flags) { int ret; @@ -204,8 +207,9 @@ struct imx_hab_ops { int (*write_srk_hash)(const u8 *srk, unsigned flags); int (*read_srk_hash)(u8 *srk); int (*permanent_write_enable)(int enable); - int (*lockdown_device)(void); + int (*lockdown_device)(unsigned flags); int (*device_locked_down)(void); + int (*print_status)(void); }; static struct imx_hab_ops imx_hab_ops_iim = { @@ -214,6 +218,7 @@ static struct imx_hab_ops imx_hab_ops_iim = { .lockdown_device = imx_hab_lockdown_device_iim, .device_locked_down = imx_hab_device_locked_down_iim, .permanent_write_enable = imx_hab_permanent_write_enable_iim, + .print_status = imx25_hab_print_status, }; static struct imx_hab_ops imx6_hab_ops_ocotp = { @@ -222,6 +227,7 @@ static struct imx_hab_ops imx6_hab_ops_ocotp = { .lockdown_device = imx6_hab_lockdown_device_ocotp, .device_locked_down = imx6_hab_device_locked_down_ocotp, .permanent_write_enable = imx_hab_permanent_write_enable_ocotp, + .print_status = imx6_hab_print_status, }; static struct imx_hab_ops imx8m_hab_ops_ocotp = { @@ -230,6 +236,105 @@ static struct imx_hab_ops imx8m_hab_ops_ocotp = { .lockdown_device = imx8m_hab_lockdown_device_ocotp, .device_locked_down = imx8m_hab_device_locked_down_ocotp, .permanent_write_enable = imx_hab_permanent_write_enable_ocotp, + .print_status = imx8m_hab_print_status, +}; + +static int imx_ahab_write_srk_hash(const u8 *__newsrk, unsigned flags) +{ + u32 *newsrk = (u32 *)__newsrk; + u32 resp; + int ret, i; + + if (!(flags & IMX_SRK_HASH_WRITE_PERMANENT)) { + pr_err("Cannot write fuses temporarily\n"); + return -EPERM; + } + + for (i = 0; i < 32 / sizeof(u32); i++) { + ret = ele_write_fuse(0x80 + i, newsrk[i], false, &resp); + if (ret) + pr_err("Writing fuse index 0x%02x failed with %d, response 0x%08x\n", + i, ret, resp); + } + + return 0; +} + +static int imx_ahab_read_srk_hash(u8 *__srk) +{ + u32 *srk = (u32 *)__srk; + u32 resp; + int ret, i; + + for (i = 0; i < SRK_HASH_SIZE / sizeof(uint32_t); i++) { + ret = ele_read_common_fuse(0x80 + i, &srk[i], &resp); + if (ret < 0) + return ret; + } + + return 0; +} + +static int imx_ahab_permanent_write_enable(int enable) +{ + return 0; +} + +static int imx_ahab_lockdown_device(unsigned flags) +{ + unsigned int lc; + int ret; + + if (!(flags & IMX_SRK_HASH_WRITE_PERMANENT)) { + pr_err("Cannot write fuses temporarily\n"); + return -EPERM; + } + + lc = imx93_ahab_read_lifecycle(); + if (lc == ELE_LIFECYCLE_OEM_CLOSED) { + pr_info("already OEM closed\n"); + return 0; + } + + if (lc != ELE_LIFECYCLE_OEM_OPEN) { + pr_err("Current lifecycle is NOT OEM open, can't move to OEM closed\n"); + return -EPERM; + } + + ret = ele_forward_lifecycle(ELE_LIFECYCLE_OEM_CLOSED, NULL); + if (ret) { + printf("failed to forward lifecycle to OEM closed\n"); + return ret; + } + + printf("Change to OEM closed successfully\n"); + + return 0; +} + +static int imx_ahab_device_locked_down(void) +{ + return imx93_ahab_read_lifecycle() != ELE_LIFECYCLE_OEM_OPEN; +} + +static int imx_ahab_print_status(void) +{ + int ret; + + ret = ele_print_events(); + if (ret) + pr_err("Cannot read ELE events: %pe\n", ERR_PTR(ret)); + + return ret; +} + +static struct imx_hab_ops imx93_ahab_ops = { + .write_srk_hash = imx_ahab_write_srk_hash, + .read_srk_hash = imx_ahab_read_srk_hash, + .lockdown_device = imx_ahab_lockdown_device, + .device_locked_down = imx_ahab_device_locked_down, + .permanent_write_enable = imx_ahab_permanent_write_enable, + .print_status = imx_ahab_print_status, }; static struct imx_hab_ops *imx_get_hab_ops(void) @@ -239,12 +344,14 @@ static struct imx_hab_ops *imx_get_hab_ops(void) if (ops) return ops; - if (IS_ENABLED(CONFIG_HABV3) && (cpu_is_mx25() || cpu_is_mx35())) + if (IS_ENABLED(CONFIG_HABV3) && cpu_is_mx25()) ops = &imx_hab_ops_iim; else if (IS_ENABLED(CONFIG_HABV4) && cpu_is_mx6()) ops = &imx6_hab_ops_ocotp; else if (IS_ENABLED(CONFIG_HABV4) && cpu_is_mx8m()) ops = &imx8m_hab_ops_ocotp; + else if (IS_ENABLED(CONFIG_AHAB) && cpu_is_mx93()) + ops = &imx93_ahab_ops; else return NULL; @@ -366,7 +473,7 @@ int imx_hab_lockdown_device(unsigned flags) return ret; } - ret = ops->lockdown_device(); + ret = ops->lockdown_device(flags); if (flags & IMX_SRK_HASH_WRITE_PERMANENT) ops->permanent_write_enable(0); @@ -383,3 +490,21 @@ int imx_hab_device_locked_down(void) return ops->device_locked_down(); } + +int imx_hab_print_status(void) +{ + struct imx_hab_ops *ops = imx_get_hab_ops(); + + if (!ops) + return -ENOSYS; + + return ops->print_status(); +} + +static int init_imx_hab_print_status(void) +{ + imx_hab_print_status(); + + return 0; +} +postmmu_initcall(init_imx_hab_print_status); diff --git a/drivers/hab/hab.h b/drivers/hab/hab.h new file mode 100644 index 0000000000..7be0e8386b --- /dev/null +++ b/drivers/hab/hab.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#ifndef __DRIVER_HAB_HAB_H +#define __DRIVER_HAB_HAB_H + +int imx25_hab_print_status(void); +int imx6_hab_print_status(void); +int imx8m_hab_print_status(void); + +#endif /* __DRIVER_HAB_HAB_H */ diff --git a/drivers/hab/habv3.c b/drivers/hab/habv3.c index 4818dae7d1..e28e9998d7 100644 --- a/drivers/hab/habv3.c +++ b/drivers/hab/habv3.c @@ -69,11 +69,7 @@ static int imx_habv3_get_status(uint32_t status) return -EPERM; } -int imx25_hab_get_status(void) +int imx25_hab_print_status(void) { - if (!cpu_is_mx25()) - return 0; - return imx_habv3_get_status(readl(IOMEM(0x780018d4))); } -postmmu_initcall(imx25_hab_get_status); diff --git a/drivers/hab/habv4.c b/drivers/hab/habv4.c index c60a658b89..a1d823ed25 100644 --- a/drivers/hab/habv4.c +++ b/drivers/hab/habv4.c @@ -20,7 +20,8 @@ #include <mach/imx/generic.h> #include <mach/imx/imx8mq.h> -#define HABV4_RVT_IMX28 0xffff8af8 +#include "hab.h" + #define HABV4_RVT_IMX6_OLD 0x00000094 #define HABV4_RVT_IMX6_NEW 0x00000098 #define HABV4_RVT_IMX6UL 0x00000100 @@ -147,9 +148,11 @@ struct hab_header { typedef enum hab_status hab_loader_callback_fn(void **start, size_t *bytes, const void *boot_data); typedef void hab_image_entry_fn(void); -/* This table is constructed from the NXP manual "High Assurance Boot Version 4 - * Application Programming Interface Reference Manual", section 4.5 ROM vector - * table. Revision 1.4 */ +/* + * This table is constructed from the NXP manual "High Assurance Boot + * Version 4 Application Programming Interface Reference Manual", + * section 4.5 ROM vector table. Revision 1.4 + */ struct habv4_rvt { struct hab_header header; enum hab_status (*entry)(void); @@ -169,9 +172,11 @@ struct habv4_rvt { #define FSL_SIP_HAB 0xC2000007 -/* These values correspondent to the jump table found in the upstream TF-A - * version 2.10 `imx_hab_handler`, not all HAB rom functions are supported yet. - * */ +/* + * These values correspondent to the jump table found in the upstream + * TF-A version 2.10 `imx_hab_handler`, not all HAB rom functions are + * supported yet. + */ enum hab_sip_cmd { FSL_SIP_HAB_AUTHENTICATE = 0x00, FSL_SIP_HAB_ENTRY = 0x01, @@ -643,7 +648,7 @@ static int habv4_get_status(const struct habv4_rvt *rvt) return -EPERM; } -int imx6_hab_get_status(void) +static int imx6_hab_get_status(void) { const struct habv4_rvt *rvt; @@ -667,41 +672,19 @@ int imx6_hab_get_status(void) return -EINVAL; } -static int imx8m_hab_get_status(void) -{ - return habv4_get_status(&hab_smc_ops); -} - -static int init_imx8m_hab_get_status(void) +int imx8m_hab_print_status(void) { - if (!cpu_is_mx8m()) - /* can happen in multi-image builds and is not an error */ - return 0; - pr_info("ROM version: 0x%x\n", hab_sip_get_version()); - /* - * Nobody will check the return value if there were HAB errors, but the - * initcall will fail spectaculously with a strange error message. - */ - imx8m_hab_get_status(); + habv4_get_status(&hab_smc_ops); return 0; } -postmmu_initcall(init_imx8m_hab_get_status); -static int init_imx6_hab_get_status(void) +int imx6_hab_print_status(void) { - if (!cpu_is_mx6()) - /* can happen in multi-image builds and is not an error */ - return 0; - remap_range(0x0, SZ_1M, MAP_CACHED); - /* - * Nobody will check the return value if there were HAB errors, but the - * initcall will fail spectaculously with a strange error message. - */ imx6_hab_get_status(); zero_page_faulting(); @@ -709,32 +692,3 @@ static int init_imx6_hab_get_status(void) return 0; } - -/* - * Need to run before MMU setup because i.MX6 ROM code is mapped near 0x0, - * which will no longer be accessible when the MMU sets the zero page to - * faulting. - */ -postmmu_initcall(init_imx6_hab_get_status); - -int imx28_hab_get_status(void) -{ - const struct habv4_rvt *rvt = (void *)HABV4_RVT_IMX28; - - return habv4_get_status(rvt); -} - -static int init_imx28_hab_get_status(void) -{ - if (!cpu_is_mx28()) - /* can happen in multi-image builds and is not an error */ - return 0; - - - /* nobody will check the return value if there were HAB errors, but the - * initcall will fail spectaculously with a strange error message. */ - imx28_hab_get_status(); - return 0; -} -/* i.MX28 ROM code can be run after MMU setup to make use of caching */ -postmmu_initcall(init_imx28_hab_get_status); diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 48f9b5be04..b4225995c0 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_I2C_BCM283X) += i2c-bcm283x.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_IMX) += i2c-imx.o lwl-$(CONFIG_I2C_IMX_EARLY) += i2c-imx-early.o -obj-$(CONFIG_I2C_IMX_LPI2C) += i2c-imx-lpi2c.o +obj-pbl-$(CONFIG_I2C_IMX_LPI2C) += i2c-imx-lpi2c.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_OMAP) += i2c-omap.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index f28a445601..a7d52fb1b1 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -19,6 +19,7 @@ #include <pinctrl.h> #include <of_gpio.h> #include <of_device.h> +#include <pbl/i2c.h> #include <io.h> #include <i2c/i2c.h> @@ -93,6 +94,7 @@ enum lpi2c_imx_pincfg { struct lpi2c_imx_struct { struct i2c_adapter adapter; + struct pbl_i2c pbl_i2c; int num_clks; struct clk_bulk_data *clks; void __iomem *base; @@ -104,6 +106,7 @@ struct lpi2c_imx_struct { unsigned int txfifosize; unsigned int rxfifosize; enum lpi2c_imx_mode mode; + unsigned long clk_rate; }; static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx, @@ -115,7 +118,7 @@ static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx, static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx) { unsigned int temp; - u64 start = get_time_ns(); + unsigned int timeout = 500000; while (1) { temp = readl(lpi2c_imx->base + LPI2C_MSR); @@ -129,7 +132,8 @@ static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx) if (temp & (MSR_BBF | MSR_MBF)) break; - if (is_timeout(start, 500 * MSECOND)) { + udelay(1); + if (!timeout--) { dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n"); return -ETIMEDOUT; } @@ -176,7 +180,7 @@ static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx, static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx) { unsigned int temp; - u64 start = get_time_ns(); + unsigned int timeout = 500000; writel(GEN_STOP << 8, lpi2c_imx->base + LPI2C_MTDR); @@ -185,7 +189,8 @@ static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx) if (temp & MSR_SDF) break; - if (is_timeout(start, 500 * MSECOND)) { + udelay(1); + if (!timeout--) { dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n"); break; } @@ -197,23 +202,19 @@ static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx) static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx) { u8 prescale, filt, sethold, datavd; - unsigned int clk_rate, clk_cycle, clkhi, clklo; + unsigned int clk_cycle, clkhi, clklo; enum lpi2c_imx_pincfg pincfg; unsigned int temp; lpi2c_imx_set_mode(lpi2c_imx); - clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk); - if (!clk_rate) - return -EINVAL; - if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST) filt = 0; else filt = 2; for (prescale = 0; prescale <= 7; prescale++) { - clk_cycle = clk_rate / ((1 << prescale) * lpi2c_imx->bitrate) + clk_cycle = lpi2c_imx->clk_rate / ((1 << prescale) * lpi2c_imx->bitrate) - 3 - (filt >> 1); clkhi = DIV_ROUND_UP(clk_cycle, I2C_CLK_RATIO + 1); clklo = clk_cycle - clkhi; @@ -287,7 +288,7 @@ static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx) static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx) { u32 txcnt; - u64 start = get_time_ns(); + unsigned int timeout = 500000; do { txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff; @@ -297,7 +298,8 @@ static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx) return -EIO; } - if (is_timeout(start, 500 * MSECOND)) { + udelay(1); + if (!timeout--) { dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n"); return -ETIMEDOUT; } @@ -329,12 +331,13 @@ static void lpi2c_imx_set_rx_watermark(struct lpi2c_imx_struct *lpi2c_imx) static int lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx) { unsigned int data, remaining; - uint64_t start = get_time_ns(); + unsigned int timeout = 100000;; do { u32 cnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff; if (cnt == lpi2c_imx->txfifosize) { - if (is_timeout(start, 100 * MSECOND)) + udelay(1); + if (!timeout--) return -EIO; continue; } @@ -352,12 +355,13 @@ static int lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx) { unsigned int remaining; unsigned int data; - uint64_t start = get_time_ns(); + unsigned int timeout = 100000;; do { data = readl(lpi2c_imx->base + LPI2C_MRDR); if (data & MRDR_RXEMPTY) { - if (is_timeout(start, 100 * MSECOND)) + udelay(1); + if (!timeout--) return -EIO; continue; } @@ -453,6 +457,36 @@ disable: return (result < 0) ? result : num; } +#ifdef __PBL__ + +static int lpi2c_pbl_imx_xfer(struct pbl_i2c *lpi2c, struct i2c_msg *msgs, int num) +{ + struct lpi2c_imx_struct *lpi2c_imx = container_of(lpi2c, struct lpi2c_imx_struct, pbl_i2c); + + return lpi2c_imx_xfer(&lpi2c_imx->adapter, msgs, num); +} + +struct pbl_i2c *imx93_i2c_early_init(void __iomem *regs) +{ + static struct lpi2c_imx_struct lpi2c; + u32 temp; + + lpi2c.base = regs; + + temp = readl(lpi2c.base + LPI2C_PARAM); + printf("%s: 0x%08x\n", __func__, temp); + lpi2c.txfifosize = 1 << (temp & 0x0f); + lpi2c.rxfifosize = 1 << ((temp >> 8) & 0x0f); + lpi2c.bitrate = 100000; + lpi2c.clk_rate = 24000000; + + lpi2c.pbl_i2c.xfer = lpi2c_pbl_imx_xfer; + + return &lpi2c.pbl_i2c; +} + +#else + static const struct of_device_id lpi2c_imx_of_match[] = { { .compatible = "fsl,imx7ulp-lpi2c" }, { }, @@ -493,6 +527,8 @@ static int lpi2c_imx_probe(struct device *dev) if (ret) return ret; + lpi2c_imx->clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk); + temp = readl(lpi2c_imx->base + LPI2C_PARAM); lpi2c_imx->txfifosize = 1 << (temp & 0x0f); lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f); @@ -513,6 +549,8 @@ static struct driver lpi2c_imx_driver = { }; coredevice_platform_driver(lpi2c_imx_driver); +#endif + MODULE_AUTHOR("Gao Pan <pandy.gao@nxp.com>"); MODULE_DESCRIPTION("I2C adapter driver for LPI2C bus"); MODULE_LICENSE("GPL"); diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c index b748a30b1f..9708d3f4bb 100644 --- a/drivers/nvmem/imx-ocotp-ele.c +++ b/drivers/nvmem/imx-ocotp-ele.c @@ -9,6 +9,10 @@ #include <linux/nvmem-provider.h> #include <linux/regmap.h> #include <mach/imx/ele.h> +#include <machine_id.h> + +#define UNIQUE_ID_NUM 4 +#define OCOTP_UNIQUE_ID(n) (0xc0 + (n) * 4) enum fuse_type { FUSE_FSB = 1, @@ -113,7 +117,20 @@ static int imx_ocotp_cell_pp(void *context, const char *id, unsigned int offset, static struct regmap_bus imx_ocotp_regmap_bus = { .reg_read = imx_ocotp_reg_read, -}; +}; + +static void imx_ocotp_set_unique_machine_id(struct imx_ocotp_priv *priv) +{ + uint32_t unique_id_parts[UNIQUE_ID_NUM]; + int i; + + for (i = 0; i < UNIQUE_ID_NUM; i++) + if (imx_ocotp_reg_read(priv, OCOTP_UNIQUE_ID(i), + &unique_id_parts[i])) + return; + + machine_id_set_hashable(unique_id_parts, sizeof(unique_id_parts)); +} static int imx_ele_ocotp_probe(struct device *dev) { @@ -145,6 +162,9 @@ static int imx_ele_ocotp_probe(struct device *dev) if (IS_ERR(priv->map)) return PTR_ERR(priv->map); + if (IS_ENABLED(CONFIG_MACHINE_ID)) + imx_ocotp_set_unique_machine_id(priv); + nvmem = nvmem_regmap_register_with_pp(priv->map, "imx-ocotp", imx_ocotp_cell_pp); if (IS_ERR(nvmem)) diff --git a/drivers/nvmem/ocotp.c b/drivers/nvmem/ocotp.c index 28c121152e..c282efefa8 100644 --- a/drivers/nvmem/ocotp.c +++ b/drivers/nvmem/ocotp.c @@ -53,12 +53,12 @@ #define OCOTP_READ_CTRL 0x30 #define OCOTP_READ_FUSE_DATA 0x40 -#define MX7_OCOTP_DATA0 0x20 -#define MX7_OCOTP_DATA1 0x30 -#define MX7_OCOTP_DATA2 0x40 -#define MX7_OCOTP_DATA3 0x50 -#define MX7_OCOTP_READ_CTRL 0x60 -#define MX7_OCOTP_READ_FUSE_DATA0 0x70 +#define MX7_OCOTP_DATA0 0x20 +#define MX7_OCOTP_DATA1 0x30 +#define MX7_OCOTP_DATA2 0x40 +#define MX7_OCOTP_DATA3 0x50 +#define MX7_OCOTP_READ_CTRL 0x60 +#define MX7_OCOTP_READ_FUSE_DATA0 0x70 #define MX7_OCOTP_READ_FUSE_DATA1 0x80 #define MX7_OCOTP_READ_FUSE_DATA2 0x90 #define MX7_OCOTP_READ_FUSE_DATA3 0xA0 @@ -67,27 +67,29 @@ #define DEF_STROBE_PROG 10000 /* IPG clocks */ /* OCOTP Registers bits and masks */ -#define OCOTP_CTRL_ADDR GENMASK(7, 0) -#define OCOTP_CTRL_BUSY BIT(8) -#define OCOTP_CTRL_ERROR BIT(9) -#define OCOTP_CTRL_RELOAD_SHADOWS BIT(10) -#define OCOTP_CTRL_WR_UNLOCK GENMASK(31, 16) -#define OCOTP_CTRL_WR_UNLOCK_KEY 0x3E77 - -/* i.MX8MP OCOTP CTRL has a different layout. See RM Rev.1 06/2021 Section - * 6.3.5.1.2.4 */ -#define OCOTP_CTRL_ADDR_8MP GENMASK(8, 0) -#define OCOTP_CTRL_BUSY_8MP BIT(9) -#define OCOTP_CTRL_ERROR_8MP BIT(10) -#define OCOTP_CTRL_RELOAD_SHADOWS_8MP BIT(11) -#define OCOTP_CTRL_WR_UNLOCK_8MP GENMASK(31, 16) - -#define OCOTP_TIMING_STROBE_READ GENMASK(21, 16) -#define OCOTP_TIMING_RELAX GENMASK(15, 12) -#define OCOTP_TIMING_STROBE_PROG GENMASK(11, 0) -#define OCOTP_TIMING_WAIT GENMASK(27, 22) - -#define OCOTP_READ_CTRL_READ_FUSE BIT(1) +#define OCOTP_CTRL_ADDR GENMASK(7, 0) +#define OCOTP_CTRL_BUSY BIT(8) +#define OCOTP_CTRL_ERROR BIT(9) +#define OCOTP_CTRL_RELOAD_SHADOWS BIT(10) +#define OCOTP_CTRL_WR_UNLOCK GENMASK(31, 16) +#define OCOTP_CTRL_WR_UNLOCK_KEY 0x3E77 + +/* + * i.MX8MP OCOTP CTRL has a different layout. See RM Rev.1 06/2021 + * Section 6.3.5.1.2.4 + */ +#define OCOTP_CTRL_ADDR_8MP GENMASK(8, 0) +#define OCOTP_CTRL_BUSY_8MP BIT(9) +#define OCOTP_CTRL_ERROR_8MP BIT(10) +#define OCOTP_CTRL_RELOAD_SHADOWS_8MP BIT(11) +#define OCOTP_CTRL_WR_UNLOCK_8MP GENMASK(31, 16) + +#define OCOTP_TIMING_STROBE_READ GENMASK(21, 16) +#define OCOTP_TIMING_RELAX GENMASK(15, 12) +#define OCOTP_TIMING_STROBE_PROG GENMASK(11, 0) +#define OCOTP_TIMING_WAIT GENMASK(27, 22) + +#define OCOTP_READ_CTRL_READ_FUSE BIT(1) #define OCOTP_OFFSET_TO_ADDR(o) (OCOTP_OFFSET_TO_INDEX(o) * 4) @@ -273,11 +275,11 @@ static int imx6_ocotp_prepare(struct ocotp_priv *priv) static int imx6_fuse_read_addr(struct ocotp_priv *priv, u32 addr, u32 *pdata) { + const u32 bm_ctrl_error = priv->data->ctrl->bm_error; + const u32 bm_ctrl_addr = priv->data->ctrl->bm_addr; + const u32 bm_ctrl_wr_unlock = priv->data->ctrl->bm_wr_unlock; u32 ctrl_reg; int ret; - u32 bm_ctrl_error = priv->data->ctrl->bm_error; - u32 bm_ctrl_addr = priv->data->ctrl->bm_addr; - u32 bm_ctrl_wr_unlock = priv->data->ctrl->bm_wr_unlock; writel(bm_ctrl_error, priv->base + OCOTP_CTRL_CLR); @@ -302,13 +304,13 @@ static int imx6_fuse_read_addr(struct ocotp_priv *priv, u32 addr, u32 *pdata) static int imx7_fuse_read_addr(struct ocotp_priv *priv, u32 index, u32 *pdata) { + const u32 bm_ctrl_error = priv->data->ctrl->bm_error; + const u32 bm_ctrl_addr = priv->data->ctrl->bm_addr; + const u32 bm_ctrl_wr_unlock = priv->data->ctrl->bm_wr_unlock; u32 ctrl_reg; u32 bank_addr; u16 word; int ret; - u32 bm_ctrl_error = priv->data->ctrl->bm_error; - u32 bm_ctrl_addr = priv->data->ctrl->bm_addr; - u32 bm_ctrl_wr_unlock = priv->data->ctrl->bm_wr_unlock; word = index & 0x3; bank_addr = index >> 2; @@ -389,10 +391,10 @@ static int imx_ocotp_reg_read(void *ctx, unsigned int reg, unsigned int *val) static void imx_ocotp_clear_unlock(struct ocotp_priv *priv, u32 index) { + const u32 bm_ctrl_error = priv->data->ctrl->bm_error; + const u32 bm_ctrl_addr = priv->data->ctrl->bm_addr; + const u32 bm_ctrl_wr_unlock = priv->data->ctrl->bm_wr_unlock; u32 ctrl_reg; - u32 bm_ctrl_error = priv->data->ctrl->bm_error; - u32 bm_ctrl_addr = priv->data->ctrl->bm_addr; - u32 bm_ctrl_wr_unlock = priv->data->ctrl->bm_wr_unlock; writel(bm_ctrl_error, priv->base + OCOTP_CTRL_CLR); @@ -406,8 +408,8 @@ static void imx_ocotp_clear_unlock(struct ocotp_priv *priv, u32 index) static int imx6_fuse_blow_addr(struct ocotp_priv *priv, u32 index, u32 value) { + const u32 bm_ctrl_error = priv->data->ctrl->bm_error; int ret; - u32 bm_ctrl_error = priv->data->ctrl->bm_error; imx_ocotp_clear_unlock(priv, index); @@ -472,7 +474,7 @@ static int imx7_fuse_blow_addr(struct ocotp_priv *priv, u32 index, u32 value) static int imx6_ocotp_reload_shadow(struct ocotp_priv *priv) { - u32 bm_ctrl_reload_shadows = priv->data->ctrl->bm_reload_shadows; + const u32 bm_ctrl_reload_shadows = priv->data->ctrl->bm_reload_shadows; dev_info(&priv->dev, "reloading shadow registers...\n"); writel(bm_ctrl_reload_shadows, priv->base + OCOTP_CTRL_SET); @@ -484,8 +486,8 @@ static int imx6_ocotp_reload_shadow(struct ocotp_priv *priv) static int imx6_ocotp_blow_one_u32(struct ocotp_priv *priv, u32 index, u32 data, u32 *pfused_value) { + const u32 bm_ctrl_error = priv->data->ctrl->bm_error; int ret; - u32 bm_ctrl_error = priv->data->ctrl->bm_error; ret = imx6_ocotp_prepare(priv); if (ret) { diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile index 54d8002a58..65b2677f7a 100644 --- a/drivers/soc/imx/Makefile +++ b/drivers/soc/imx/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_IMX8M_FEATCTRL) += imx8m-featctrl.o +obj-$(CONFIG_ARCH_IMX8M) += soc-imx8m.o diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c new file mode 100644 index 0000000000..48b42a1b17 --- /dev/null +++ b/drivers/soc/imx/soc-imx8m.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: 2024 Marco Felsch, Pengutronix +/* + * Based on Linux drivers/soc/imx/soc-imx8m.c: + * Copyright 2019 NXP. + */ + +#include <init.h> +#include <of.h> +#include <of_address.h> +#include <pm_domain.h> + +#include <asm/optee.h> +#include <asm-generic/memory_layout.h> + +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/sys_soc.h> +#include <linux/arm-smccc.h> +#include <linux/clk.h> + +#include <mach/imx/generic.h> +#include <mach/imx/imx8m-regs.h> +#include <mach/imx/reset-reason.h> +#include <mach/imx/revision.h> +#include <mach/imx/scratch.h> +#include <mach/imx/tzasc.h> + +#include <tee/optee.h> + +#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 + +#define IMX8MP_OCOTP_UID_OFFSET 0x10 + +/* Same as ANADIG_DIGPROG_IMX7D */ +#define ANADIG_DIGPROG_IMX8MM 0x800 + +struct imx8_soc_data { + char *name; + u32 (*soc_revision)(void); + void (*save_boot_loc)(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; + struct clk *clk; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp"); + if (!np) + return 0; + + ocotp_base = of_iomap(np, 0); + WARN_ON(!ocotp_base); + clk = of_clk_get_by_name(np, NULL); + if (IS_ERR(clk)) { + WARN_ON(IS_ERR(clk)); + return 0; + } + + clk_prepare_enable(clk); + + /* + * 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); + + /* Keep the OCOTP clk on for the TF-A else the CPU stuck */ + of_node_put(np); + + return rev; +} + +static void __init imx8mm_soc_uid(void) +{ + void __iomem *ocotp_base; + struct device_node *np; + struct clk *clk; + u32 offset = of_machine_is_compatible("fsl,imx8mp") ? + IMX8MP_OCOTP_UID_OFFSET : 0; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-ocotp"); + if (!np) + return; + + ocotp_base = of_iomap(np, 0); + WARN_ON(!ocotp_base); + clk = of_clk_get_by_name(np, NULL); + if (IS_ERR(clk)) { + WARN_ON(IS_ERR(clk)); + return; + } + + clk_prepare_enable(clk); + + soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH + offset); + soc_uid <<= 32; + soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW + offset); + + /* Keep the OCOTP clk on for the TF-A else the CPU stuck */ + 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); + + 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, + .save_boot_loc = imx8mq_boot_save_loc, +}; + +static const struct imx8_soc_data imx8mm_soc_data = { + .name = "i.MX8MM", + .soc_revision = imx8mm_soc_revision, + .save_boot_loc = imx8mm_boot_save_loc, +}; + +static const struct imx8_soc_data imx8mn_soc_data = { + .name = "i.MX8MN", + .soc_revision = imx8mm_soc_revision, + .save_boot_loc = imx8mn_boot_save_loc, +}; + +static const struct imx8_soc_data imx8mp_soc_data = { + .name = "i.MX8MP", + .soc_revision = imx8mm_soc_revision, + .save_boot_loc = imx8mp_boot_save_loc, +}; + +static __maybe_unused 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, }, + { } +}; + +static int imx8_soc_imx8m_init(struct soc_device_attribute *soc_dev_attr) +{ + void __iomem *src = IOMEM(MX8M_SRC_BASE_ADDR); + const char *uid = soc_dev_attr->serial_number; + const char *cputypestr = soc_dev_attr->soc_id; + + genpd_activate(); + + /* + * Reset reasons seem to be identical to that of i.MX7 + */ + imx_set_reset_reason(src + IMX7_SRC_SRSR, imx7_reset_reasons); + pr_info("%s unique ID: %s\n", cputypestr, uid); + + if (IS_ENABLED(CONFIG_PBL_OPTEE) && tzc380_is_enabled()) { + static struct of_optee_fixup_data optee_fixup_data = { + .shm_size = OPTEE_SHM_SIZE, + .method = "smc", + }; + + optee_set_membase(imx_scratch_get_optee_hdr()); + of_optee_fixup(of_get_root_node(), &optee_fixup_data); + of_register_fixup(of_optee_fixup, &optee_fixup_data); + } + + return 0; +} + +#define imx8_revision(soc_rev) \ + soc_rev ? \ + xasprintf("%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \ + "unknown" + +static int __init imx8_soc_init(void) +{ + struct device_node *of_root = of_get_root_node(); + 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; + + id = of_match_node(imx8_soc_match, of_root); + if (!id) + return 0; + + 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; + + data = id->data; + if (data) { + soc_dev_attr->soc_id = data->name; + if (data->soc_revision) + soc_rev = data->soc_revision(); + if (data->save_boot_loc) + data->save_boot_loc(); + } + + soc_dev_attr->revision = imx8_revision(soc_rev); + if (!soc_dev_attr->revision) { + ret = -ENOMEM; + goto free_soc; + } + + soc_dev_attr->serial_number = xasprintf("%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; + } + + imx_set_silicon_revision(soc_dev_attr->soc_id, soc_rev); + + return imx8_soc_imx8m_init(soc_dev_attr); + +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; +} +/* Aligned with imx_init() to not cause regressions */ +postcore_initcall(imx8_soc_init); +MODULE_LICENSE("GPL"); |