summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2026-02-07 07:50:05 -0600
committerTom Rini <[email protected]>2026-02-07 07:50:05 -0600
commit717cd8d54c81f16c2c062a4ac80463956628d4c1 (patch)
treee40228615d856862b10b7b37647f44c05b8f33c5 /drivers
parente5e75ea8c7b8e6d9ce1ca8ec7a25fa8b3f6029a9 (diff)
parent470ea759aa60890271fba0b8d0bcc7bb29e0b459 (diff)
Merge tag 'u-boot-imx-master-20260206' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
CI: https://source.denx.de/u-boot/custodians/u-boot-imx/-/pipelines/29216 - Convert imx8mn_var_som to OF_UPSTREAM and several cleanups. - Fix ele_ahab buid error on imx93_qsb. - Add i.MX95 EVK remoteproc support. - Several i.MX8/9 EVK cleanups.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/fec_mxc.c4
-rw-r--r--drivers/remoteproc/imx_rproc.c189
-rw-r--r--drivers/remoteproc/imx_rproc.h3
4 files changed, 190 insertions, 8 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 4fda1b0c28c..eb6a1cab565 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -423,7 +423,7 @@ config FEC_MXC_MDIO_BASE
config FEC_MXC
bool "FEC Ethernet controller"
- depends on MX28 || MX5 || MX6 || MX7 || IMX8 || IMX8M || IMX8ULP || IMX93 || VF610
+ depends on MX28 || MX5 || MX6 || MX7 || IMX8 || IMX8M || IMX8ULP || IMX91 || IMX93 || VF610
help
This driver supports the 10/100 Fast Ethernet controller for
NXP i.MX processors.
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c
index fee9973c4dc..1c51e936b5b 100644
--- a/drivers/net/fec_mxc.c
+++ b/drivers/net/fec_mxc.c
@@ -594,7 +594,7 @@ static int fecmxc_init(struct udevice *dev)
/* Do not access reserved register */
if (!is_mx6ul() && !is_mx6ull() && !is_imx8() && !is_imx8m() && !is_imx8ulp() &&
- !is_imx93()) {
+ !is_imx91() && !is_imx93()) {
/* clear MIB RAM */
for (i = mib_ptr; i <= mib_ptr + 0xfc; i += 4)
writel(0, i);
@@ -1236,7 +1236,7 @@ static int fecmxc_set_ref_clk(struct clk *clk_ref, phy_interface_t interface)
interface == PHY_INTERFACE_MODE_RGMII_RXID ||
interface == PHY_INTERFACE_MODE_RGMII_TXID) {
freq = 125000000;
- if (is_imx93())
+ if (is_imx91() || is_imx93())
freq = freq << 1;
} else {
return -EINVAL;
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 9bb55327998..3f8cea127ec 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -11,6 +11,7 @@
#include <linux/types.h>
#include <regmap.h>
#include <remoteproc.h>
+#include <scmi_nxp_protocols.h>
#include <syscon.h>
#include "imx_rproc.h"
@@ -37,15 +38,32 @@
#define IMX_SIP_RPROC_STARTED 0x01
#define IMX_SIP_RPROC_STOP 0x02
+/* Must align with System Manager Firmware */
+#define IMX95_M7_CPUID 1
+#define IMX95_M7_LMID 1
+
+/* Logical Machine API Operation */
+#define IMX_RPROC_FLAGS_SM_LMM_OP BIT(0)
+/* CPU API Operation */
+#define IMX_RPROC_FLAGS_SM_CPU_OP BIT(1)
+/* Linux has permission to handle the Logical Machine of remote cores */
+#define IMX_RPROC_FLAGS_SM_LMM_AVAIL BIT(2)
+
struct imx_rproc {
const struct imx_rproc_dcfg *dcfg;
struct regmap *regmap;
+ u32 flags;
+ /* For System Manager based system */
+ struct udevice *lmm_dev;
+ struct udevice *cpu_dev;
+ ulong reset_vector;
};
/* att flags: lower 16 bits specifying core, higher 16 bits for flags */
/* M4 own area. Can be mapped at probe */
#define ATT_OWN BIT(31)
#define ATT_IOMEM BIT(30)
+#define ATT_ECC BIT(29)
static int imx_rproc_arm_smc_start(struct udevice *dev)
{
@@ -64,6 +82,41 @@ static int imx_rproc_mmio_start(struct udevice *dev)
return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_start);
}
+static int imx_rproc_sm_start(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ int ret;
+
+ if (priv->flags & IMX_RPROC_FLAGS_SM_CPU_OP) {
+ ret = scmi_imx_cpu_reset_vector_set(priv->cpu_dev, dcfg->cpuid, 0,
+ priv->reset_vector, true, false, false);
+ if (ret) {
+ dev_err(dev, "Failed to set reset vector cpuid(%u): %d\n",
+ dcfg->cpuid, ret);
+ return ret;
+ }
+
+ return scmi_imx_cpu_start(priv->cpu_dev, dcfg->cpuid, true);
+ }
+
+ ret = scmi_imx_lmm_reset_vector_set(priv->lmm_dev, dcfg->lmid, dcfg->cpuid, 0,
+ priv->reset_vector);
+ if (ret) {
+ dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): %d\n",
+ dcfg->lmid, dcfg->cpuid, ret);
+ return ret;
+ }
+
+ ret = scmi_imx_lmm_power_boot(priv->lmm_dev, dcfg->lmid, true);
+ if (ret) {
+ dev_err(dev, "Failed to boot lmm(%d): %d\n", ret, dcfg->lmid);
+ return ret;
+ }
+
+ return 0;
+}
+
static int imx_rproc_start(struct udevice *dev)
{
struct imx_rproc *priv = dev_get_priv(dev);
@@ -99,6 +152,17 @@ static int imx_rproc_mmio_stop(struct udevice *dev)
return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_stop);
}
+static int imx_rproc_sm_stop(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+
+ if (priv->flags & IMX_RPROC_FLAGS_SM_CPU_OP)
+ return scmi_imx_cpu_start(priv->cpu_dev, dcfg->cpuid, false);
+
+ return scmi_imx_lmm_shutdown(priv->lmm_dev, dcfg->lmid, 0);
+}
+
static int imx_rproc_stop(struct udevice *dev)
{
struct imx_rproc *priv = dev_get_priv(dev);
@@ -145,6 +209,20 @@ static int imx_rproc_mmio_is_running(struct udevice *dev)
return 1;
}
+static int imx_rproc_sm_is_running(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ int ret;
+ bool started = false;
+
+ ret = scmi_imx_cpu_started(priv->cpu_dev, dcfg->cpuid, &started);
+ if (ret || !started)
+ return 1;
+
+ return 0;
+}
+
static int imx_rproc_is_running(struct udevice *dev)
{
struct imx_rproc *priv = dev_get_priv(dev);
@@ -202,6 +280,34 @@ static void *imx_rproc_device_to_virt(struct udevice *dev, ulong da, ulong size,
static int imx_rproc_load(struct udevice *dev, ulong addr, ulong size)
{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ int i;
+
+ if (IS_ENABLED(CONFIG_IMX_SM_LMM)) {
+ if (!(priv->flags & (IMX_RPROC_FLAGS_SM_LMM_AVAIL | IMX_RPROC_FLAGS_SM_CPU_OP)))
+ return -EACCES;
+ }
+
+ /* Only used for SM based System */
+ priv->reset_vector = rproc_elf_get_boot_addr(dev, addr) & GENMASK(31, 16);
+
+ /*
+ * Before loading elf, need do ECC initialization by clearing the memory
+ * region, if ATT_ECC is set.
+ */
+ for (i = 0; i < dcfg->att_size; i++) {
+ const struct imx_rproc_att *att = &dcfg->att[i];
+
+ if (!(att->flags & ATT_ECC))
+ continue;
+
+ if (att->flags & ATT_IOMEM)
+ memset_io((void __iomem *)(long)att->sa, 0, att->size);
+ else
+ memset((void *)(long)att->sa, 0, att->size);
+ }
+
return rproc_elf_load_image(dev, addr, size);
}
@@ -218,19 +324,65 @@ static int imx_rproc_probe(struct udevice *dev)
{
struct imx_rproc *priv = dev_get_priv(dev);
struct imx_rproc_dcfg *dcfg = (struct imx_rproc_dcfg *)dev_get_driver_data(dev);
+ struct scmi_imx_lmm_info info;
ofnode node;
+ int ret;
node = dev_ofnode(dev);
priv->dcfg = dcfg;
- if (dcfg->method != IMX_RPROC_MMIO)
+ if (dcfg->method == IMX_RPROC_MMIO) {
+ priv->regmap = syscon_regmap_lookup_by_phandle(dev, "syscon");
+ if (IS_ERR(priv->regmap)) {
+ dev_err(dev, "No syscon: %ld\n", PTR_ERR(priv->regmap));
+ return PTR_ERR(priv->regmap);
+ }
return 0;
+ } else {
+ if (IS_ENABLED(CONFIG_IMX_SM_LMM)) {
+ struct udevice *lmm_dev;
+
+ ret = uclass_get_device_by_name(UCLASS_SCMI_BASE, "protocol@80", &lmm_dev);
+ if (ret) {
+ dev_err(dev, "Failed to get SM LMM protocol dev\n");
+ return ret;
+ }
+
+ priv->lmm_dev = lmm_dev;
- priv->regmap = syscon_regmap_lookup_by_phandle(dev, "syscon");
- if (IS_ERR(priv->regmap)) {
- dev_err(dev, "No syscon: %ld\n", PTR_ERR(priv->regmap));
- return PTR_ERR(priv->regmap);
+ ret = scmi_imx_lmm_info(lmm_dev, LMM_ID_DISCOVER, &info);
+ if (ret) {
+ dev_err(dev, "Failed to get lmm info\n");
+ return ret;
+ }
+
+ if (dcfg->lmid != info.lmid) {
+ ret = scmi_imx_lmm_power_boot(lmm_dev, dcfg->lmid, false);
+ if (ret == -EACCES) {
+ dev_err(dev, "Remoteproc not under U-boot control: only support detect running\n");
+ } else if (ret) {
+ dev_err(dev, "power on lmm fail:%d\n", ret);
+ return ret;
+ } else {
+ priv->flags |= IMX_RPROC_FLAGS_SM_LMM_AVAIL;
+ }
+ } else {
+ priv->flags |= IMX_RPROC_FLAGS_SM_CPU_OP;
+ }
+ }
+
+ if (IS_ENABLED(CONFIG_IMX_SM_CPU)) {
+ struct udevice *cpu_dev;
+
+ ret = uclass_get_device_by_name(UCLASS_SCMI_BASE, "protocol@82", &cpu_dev);
+ if (ret) {
+ dev_err(dev, "Failed to get SM LMM protocol dev\n");
+ return ret;
+ }
+
+ priv->cpu_dev = cpu_dev;
+ }
}
return 0;
@@ -351,12 +503,39 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = {
.ops = &imx_rproc_ops_arm_smc,
};
+static const struct imx_rproc_att imx_rproc_att_imx95_m7[] = {
+ /* dev addr , sys addr , size , flags */
+ /* TCM CODE NON-SECURE */
+ { 0x00000000, 0x203C0000, 0x00040000, ATT_OWN | ATT_IOMEM | ATT_ECC },
+
+ /* TCM SYS NON-SECURE*/
+ { 0x20000000, 0x20400000, 0x00040000, ATT_OWN | ATT_IOMEM | ATT_ECC },
+
+ /* DDR */
+ { 0x80000000, 0x80000000, 0x50000000, 0 },
+};
+
+static const struct imx_rproc_plat_ops imx_rproc_ops_sm = {
+ .start = imx_rproc_sm_start,
+ .stop = imx_rproc_sm_stop,
+ .is_running = imx_rproc_sm_is_running,
+};
+
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = {
+ .att = imx_rproc_att_imx95_m7,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx95_m7),
+ .ops = &imx_rproc_ops_sm,
+ .cpuid = IMX95_M7_CPUID,
+ .lmid = IMX95_M7_LMID,
+};
+
static const struct udevice_id imx_rproc_ids[] = {
{ .compatible = "fsl,imx8mm-cm4", .data = (ulong)&imx_rproc_cfg_imx8mq },
{ .compatible = "fsl,imx8mn-cm7", .data = (ulong)&imx_rproc_cfg_imx8mn, },
{ .compatible = "fsl,imx8mp-cm7", .data = (ulong)&imx_rproc_cfg_imx8mn, },
{ .compatible = "fsl,imx8mq-cm4", .data = (ulong)&imx_rproc_cfg_imx8mq },
{ .compatible = "fsl,imx93-cm33", .data = (ulong)&imx_rproc_cfg_imx93 },
+ { .compatible = "fsl,imx95-cm7", .data = (ulong)&imx_rproc_cfg_imx95_m7 },
{}
};
diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
index 7a82dc4a195..1629bc7f6e7 100644
--- a/drivers/remoteproc/imx_rproc.h
+++ b/drivers/remoteproc/imx_rproc.h
@@ -51,6 +51,9 @@ struct imx_rproc_dcfg {
enum imx_rproc_method method;
u32 flags;
const struct imx_rproc_plat_ops *ops;
+ /* For System Manager(SM) based SoCs, the IDs are from SM firmware */
+ u32 cpuid;
+ u32 lmid;
};
#endif /* _IMX_RPROC_H */