summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2025-11-04 13:06:26 -0600
committerTom Rini <[email protected]>2025-11-04 13:06:26 -0600
commit1c250e444ad3b15315ee8b0fcb3fc3acc26449e2 (patch)
tree47cd432ccfc396c9fabd4631566289f120c01605 /drivers
parentef34776f21969a71594dc6224d0e54cf5a2a980c (diff)
parent2b7892255bd617dfc523cfe8455dbf386a3dfaf5 (diff)
Merge tag 'u-boot-imx-master-20251104' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
CI: https://source.denx.de/u-boot/custodians/u-boot-imx/-/pipelines/28144 - Extend USB support for the i.MX9 family. - Update memory controller for imx6ulz_smm_m2. - Add remoteproc support for several i.MX boards. - Add support for iMX95 15x15 EVK.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/Kconfig5
-rw-r--r--drivers/net/fsl_enetc_mdio.c25
-rw-r--r--drivers/net/fsl_enetc_netc_blk_ctrl.c329
-rw-r--r--drivers/phy/Kconfig14
-rw-r--r--drivers/phy/Makefile2
-rw-r--r--drivers/remoteproc/Kconfig7
-rw-r--r--drivers/remoteproc/Makefile1
-rw-r--r--drivers/remoteproc/imx_rproc.c370
-rw-r--r--drivers/remoteproc/imx_rproc.h56
-rw-r--r--drivers/remoteproc/renesas_apmu.c3
-rw-r--r--drivers/remoteproc/rproc-elf-loader.c95
-rw-r--r--drivers/remoteproc/sandbox_testproc.c3
-rw-r--r--drivers/remoteproc/stm32_copro.c3
-rw-r--r--drivers/remoteproc/ti_k3_dsp_rproc.c2
-rw-r--r--drivers/remoteproc/ti_k3_m4_rproc.c2
-rw-r--r--drivers/remoteproc/ti_k3_r5f_rproc.c2
-rw-r--r--drivers/usb/gadget/f_sdp.c2
-rw-r--r--drivers/usb/host/Kconfig6
18 files changed, 872 insertions, 55 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index c9b35b5a2ff..913670ce412 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1006,8 +1006,9 @@ config FSL_ENETC
config FSL_ENETC_NETC_BLK_CTRL
bool "NXP ENETC NETC blocks control driver"
- depends on FSL_ENETC && IMX95
- default y if IMX95
+ depends on FSL_ENETC
+ depends on IMX95 || IMX94
+ default y if IMX95 || IMX94
help
This driver configures Integrated Endpoint Register Block (IERB) and
Privileged Register Block (PRB) of NETC. For i.MX platforms, it also
diff --git a/drivers/net/fsl_enetc_mdio.c b/drivers/net/fsl_enetc_mdio.c
index c1d491f2c5a..3d76d92a62a 100644
--- a/drivers/net/fsl_enetc_mdio.c
+++ b/drivers/net/fsl_enetc_mdio.c
@@ -11,6 +11,8 @@
#include <asm/io.h>
#include <asm/processor.h>
#include <miiphy.h>
+#include <linux/delay.h>
+#include <power/regulator.h>
#include "fsl_enetc.h"
@@ -135,6 +137,8 @@ static int enetc_mdio_probe(struct udevice *dev)
struct pci_child_plat *pplat = dev_get_parent_plat(dev);
struct enetc_mdio_priv *priv = dev_get_priv(dev);
u16 cmd = PCI_COMMAND_MEMORY;
+ int ret;
+ struct udevice *supply = NULL;
priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, 0);
if (!priv->regs_base) {
@@ -144,6 +148,27 @@ static int enetc_mdio_probe(struct udevice *dev)
priv->regs_base += ENETC_MDIO_BASE;
+ if (CONFIG_IS_ENABLED(DM_REGULATOR)) {
+ ret = device_get_supply_regulator(dev, "phy-supply",
+ &supply);
+ if (ret && ret != -ENOENT) {
+ printf("%s: device_get_supply_regulator failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (supply) {
+ regulator_set_enable(supply, false);
+ mdelay(100);
+
+ ret = regulator_set_enable_if_allowed(supply, true);
+ if (ret) {
+ printf("%s: Error enabling phy supply\n", dev->name);
+ return ret;
+ }
+ }
+ }
+
if (pplat->vendor == PCI_VENDOR_ID_PHILIPS) /* i.MX95 */
cmd |= PCI_COMMAND_MASTER;
diff --git a/drivers/net/fsl_enetc_netc_blk_ctrl.c b/drivers/net/fsl_enetc_netc_blk_ctrl.c
index fecd66eb15a..8577bb75632 100644
--- a/drivers/net/fsl_enetc_netc_blk_ctrl.c
+++ b/drivers/net/fsl_enetc_netc_blk_ctrl.c
@@ -43,6 +43,18 @@
#define PCS_PROT_SFI BIT(4)
#define PCS_PROT_10G_SXGMII BIT(6)
+#define IMX94_MISC_SOC_CONTROL 0x0
+#define SEL_XPCS_1 BIT(1)
+#define IMX94_XPCS_PORT_0 0x0
+#define IMX94_XPCS_PORT_1 0x1
+
+#define IMX94_EXT_PIN_CONTROL 0x10
+#define MAC2_MAC3_SEL BIT(1)
+
+#define IMX94_NETC_LINK_CFG(a) (0x4c + (a) * 4)
+#define NETC_LINK_CFG_MII_PROT GENMASK(3, 0)
+#define NETC_LINK_CFG_IO_VAR GENMASK(19, 16)
+
/* NETC privileged register block register */
#define PRB_NETCRR 0x100
#define NETCRR_SR BIT(0)
@@ -55,6 +67,7 @@
/* NETC integrated endpoint register block register */
#define IERB_EMDIOFAUXR 0x344
#define IERB_T0FAUXR 0x444
+#define IERB_ETBCR(a) (0x300c + 0x100 * (a))
#define IERB_EFAUXR(a) (0x3044 + 0x100 * (a))
#define IERB_VFAUXR(a) (0x4004 + 0x40 * (a))
#define FAUXR_LDID GENMASK(3, 0)
@@ -64,6 +77,26 @@
#define IMX95_ENETC1_BUS_DEVFN 0x40
#define IMX95_ENETC2_BUS_DEVFN 0x80
+#define IMX94_ENETC3_BUS_DEVFN 0x0
+#define IMX94_TIMER0_BUS_DEVFN 0x1
+#define IMX94_SWITCH_BUS_DEVFN 0x2
+#define IMX94_ENETC0_BUS_DEVFN 0x100
+#define IMX94_TIMER1_BUS_DEVFN 0x101
+#define IMX94_ENETC1_BUS_DEVFN 0x140
+#define IMX94_ENETC2_BUS_DEVFN 0x180
+#define IMX94_TIMER2_BUS_DEVFN 0x181
+#define IMX94_ENETC0_LINK 3
+#define IMX94_ENETC1_LINK 4
+#define IMX94_ENETC2_LINK 5
+#define IMX94_ENETC0_OFFSET 0
+#define IMX94_ENETC1_OFFSET 1
+#define IMX94_ENETC2_OFFSET 2
+#define IMX94_SWITCH_PORT2 2
+#define IMX94_SWITCH_CPU_PORT 3
+#define IMX94_TIMER0_ID 0
+#define IMX94_TIMER1_ID 1
+#define IMX94_TIMER2_ID 2
+
/* Flags for different platforms */
#define NETC_HAS_NETCMIX BIT(0)
@@ -73,6 +106,15 @@ struct netc_blk_ctrl {
void __iomem *netcmix;
};
+struct netc_devinfo {
+ int (*netcmix_init)(struct udevice *dev);
+ int (*ierb_init)(struct udevice *dev);
+ void (*xpcs_port_init)(struct netc_blk_ctrl *priv, int port);
+};
+
+static struct netc_blk_ctrl *netc_bc;
+static struct netc_devinfo *netc_di;
+
static void netc_reg_write(void __iomem *base, u32 offset, u32 val)
{
writel(val, base + offset);
@@ -183,6 +225,142 @@ static int imx95_netcmix_init(struct udevice *dev)
return 0;
}
+static int imx94_enetc_get_link_num(ofnode np)
+{
+ int bus_devfn;
+
+ bus_devfn = netc_of_pci_get_bus_devfn(np);
+ if (bus_devfn < 0)
+ return -EINVAL;
+
+ /* Parse ENETC link number */
+ switch (bus_devfn) {
+ case IMX94_ENETC0_BUS_DEVFN:
+ return IMX94_ENETC0_LINK;
+ case IMX94_ENETC1_BUS_DEVFN:
+ return IMX94_ENETC1_LINK;
+ case IMX94_ENETC2_BUS_DEVFN:
+ return IMX94_ENETC2_LINK;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int imx94_link_config(struct netc_blk_ctrl *priv,
+ ofnode np, int link_id)
+{
+ phy_interface_t interface;
+ int mii_proto;
+ u32 val;
+
+ interface = ofnode_read_phy_mode(np);
+ if (interface == -1)
+ return -EINVAL;
+
+ mii_proto = netc_get_link_mii_protocol(interface);
+ if (mii_proto < 0)
+ return -EINVAL;
+
+ val = mii_proto & NETC_LINK_CFG_MII_PROT;
+ if (mii_proto == MII_PROT_SERIAL)
+ val = u32_replace_bits(val, IO_VAR_16FF_16G_SERDES,
+ NETC_LINK_CFG_IO_VAR);
+
+ netc_reg_write(priv->netcmix, IMX94_NETC_LINK_CFG(link_id), val);
+
+ if (link_id == IMX94_ENETC0_LINK) {
+ val = netc_reg_read(priv->netcmix, IMX94_EXT_PIN_CONTROL);
+ val |= MAC2_MAC3_SEL;
+ netc_reg_write(priv->netcmix, IMX94_EXT_PIN_CONTROL, val);
+ }
+
+ return 0;
+}
+
+static int imx94_enetc_link_config(struct netc_blk_ctrl *priv,
+ ofnode np, bool *enetc0_en)
+{
+ int link_id;
+
+ link_id = imx94_enetc_get_link_num(np);
+ if (link_id < 0)
+ return -EINVAL;
+
+ if (link_id == IMX94_ENETC0_LINK)
+ *enetc0_en = true;
+
+ return imx94_link_config(priv, np, link_id);
+}
+
+static int imx94_switch_link_config(struct netc_blk_ctrl *priv,
+ ofnode np, bool *swp2_en)
+{
+ ofnode ports, child;
+ int port_id, err = 0;
+
+ ports = ofnode_find_subnode(np, "ports");
+ if (!ofnode_valid(ports))
+ ports = ofnode_find_subnode(np, "ethernet-ports");
+ if (!ofnode_valid(ports))
+ return -ENODEV;
+
+ ofnode_for_each_subnode(child, ports) {
+ if (ofnode_read_u32(child, "reg", &port_id) < 0) {
+ err = -ENODEV;
+ goto end;
+ }
+
+ if (port_id == IMX94_SWITCH_CPU_PORT)
+ continue;
+
+ if (port_id == IMX94_SWITCH_PORT2)
+ *swp2_en = true;
+
+ err = imx94_link_config(priv, child, port_id);
+ if (err)
+ goto end;
+ }
+
+end:
+ return err;
+}
+
+static int imx94_netcmix_init(struct udevice *dev)
+{
+ struct netc_blk_ctrl *priv = dev_get_priv(dev);
+ ofnode child, gchild;
+ bool enetc0_en = false, swp2_en = false;
+ int err;
+
+ dev_for_each_subnode(child, dev) {
+ if (!ofnode_is_enabled(child))
+ continue;
+
+ ofnode_for_each_subnode(gchild, child) {
+ if (!ofnode_is_enabled(gchild))
+ continue;
+
+ if (ofnode_device_is_compatible(gchild, "pci1131,e101")) {
+ err = imx94_enetc_link_config(priv, gchild, &enetc0_en);
+ if (err)
+ return err;
+ } else if (ofnode_device_is_compatible(gchild, "pci1131,eef2")) {
+ err = imx94_switch_link_config(priv, gchild, &swp2_en);
+ if (err)
+ return err;
+ }
+ }
+ }
+
+ if (enetc0_en && swp2_en) {
+ dev_err(dev, "Cannot enable swp2 and enetc0 at the same time\n");
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static bool netc_ierb_is_locked(struct netc_blk_ctrl *priv)
{
return !!(netc_reg_read(priv->prb, PRB_NETCRR) & NETCRR_LOCK);
@@ -238,9 +416,99 @@ static int imx95_ierb_init(struct udevice *dev)
return 0;
}
+static int imx94_enetc_get_enetc_offset(ofnode np)
+{
+ int bus_devfn;
+
+ bus_devfn = netc_of_pci_get_bus_devfn(np);
+ if (bus_devfn < 0)
+ return -EINVAL;
+
+ /* Parse ENETC offset */
+ switch (bus_devfn) {
+ case IMX94_ENETC0_BUS_DEVFN:
+ return IMX94_ENETC0_OFFSET;
+ case IMX94_ENETC1_BUS_DEVFN:
+ return IMX94_ENETC1_OFFSET;
+ case IMX94_ENETC2_BUS_DEVFN:
+ return IMX94_ENETC2_OFFSET;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int imx94_enetc_get_timer_id(ofnode np)
+{
+ int bus_devfn;
+
+ bus_devfn = netc_of_pci_get_bus_devfn(np);
+ if (bus_devfn < 0)
+ return -EINVAL;
+
+ /* Parse ENETC PTP timer ID */
+ switch (bus_devfn) {
+ case IMX94_TIMER0_BUS_DEVFN:
+ return IMX94_TIMER0_ID;
+ case IMX94_TIMER1_BUS_DEVFN:
+ return IMX94_TIMER1_ID;
+ case IMX94_TIMER2_BUS_DEVFN:
+ return IMX94_TIMER2_ID;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int imx94_enetc_update_tid(struct netc_blk_ctrl *priv, ofnode pf_np)
+{
+ ofnode timer_np;
+ int offset, tid;
+
+ offset = imx94_enetc_get_enetc_offset(pf_np);
+ if (offset < 0) {
+ printf("Find unknown PF node.\n");
+ return offset;
+ }
+
+ timer_np = ofnode_parse_phandle(pf_np, "nxp,ptp-timer", 0);
+ if (!ofnode_valid(timer_np)) {
+ /*
+ * If nxp,ptp-timer is not set, the first timer of the bus
+ * where enetc is located will be used as the default timer.
+ */
+ tid = IMX94_TIMER1_ID;
+ goto update_reg;
+ }
+
+ tid = imx94_enetc_get_timer_id(timer_np);
+ if (tid < 0) {
+ printf("Incorrect bus/devfn of ptp-timer.\n");
+ return tid;
+ }
+
+update_reg:
+ netc_reg_write(priv->ierb, IERB_ETBCR(offset), tid);
+
+ return 0;
+}
+
+static int imx94_ierb_init(struct udevice *dev)
+{
+ struct netc_blk_ctrl *priv = dev_get_priv(dev);
+ ofnode bus_np, pf_np;
+ int ret = 0;
+
+ dev_for_each_subnode(bus_np, dev)
+ ofnode_for_each_subnode(pf_np, bus_np)
+ if (ofnode_device_is_compatible(pf_np, "pci1131,e101"))
+ ret = imx94_enetc_update_tid(priv, pf_np);
+
+ return ret;
+}
+
static int netc_ierb_init(struct udevice *dev)
{
struct netc_blk_ctrl *priv = dev_get_priv(dev);
+ struct netc_devinfo *devinfo = (struct netc_devinfo *)dev_get_driver_data(dev);
int err;
if (netc_ierb_is_locked(priv)) {
@@ -251,9 +519,11 @@ static int netc_ierb_init(struct udevice *dev)
}
}
- err = imx95_ierb_init(dev);
- if (err)
- return err;
+ if (devinfo->ierb_init) {
+ err = devinfo->ierb_init(dev);
+ if (err)
+ return err;
+ }
err = netc_lock_ierb(priv);
if (err) {
@@ -264,6 +534,31 @@ static int netc_ierb_init(struct udevice *dev)
return 0;
}
+static void imx94_netc_xpcs_port_init(struct netc_blk_ctrl *priv, int port)
+{
+ u32 val;
+
+ val = netc_reg_read(priv->netcmix, IMX94_MISC_SOC_CONTROL);
+ if (port == IMX94_XPCS_PORT_1)
+ val |= SEL_XPCS_1;
+ else
+ val &= ~SEL_XPCS_1;
+ netc_reg_write(priv->netcmix, IMX94_MISC_SOC_CONTROL, val);
+}
+
+void netc_xpcs_port_init(int port)
+{
+ struct netc_blk_ctrl *priv = netc_bc;
+ struct netc_devinfo *devinfo;
+
+ if (!priv)
+ return;
+
+ devinfo = netc_di;
+ if (devinfo->xpcs_port_init)
+ devinfo->xpcs_port_init(priv, port);
+}
+
static int netc_prb_check_error(struct netc_blk_ctrl *priv)
{
if (netc_reg_read(priv->prb, PRB_NETCSR) & NETCSR_ERROR)
@@ -272,14 +567,27 @@ static int netc_prb_check_error(struct netc_blk_ctrl *priv)
return 0;
}
+static const struct netc_devinfo imx95_devinfo = {
+ .netcmix_init = imx95_netcmix_init,
+ .ierb_init = imx95_ierb_init,
+};
+
+static const struct netc_devinfo imx94_devinfo = {
+ .netcmix_init = imx94_netcmix_init,
+ .ierb_init = imx94_ierb_init,
+ .xpcs_port_init = imx94_netc_xpcs_port_init,
+};
+
static const struct udevice_id netc_blk_ctrl_match[] = {
- { .compatible = "nxp,imx95-netc-blk-ctrl" },
+ { .compatible = "nxp,imx95-netc-blk-ctrl", .data = (ulong)&imx95_devinfo },
+ { .compatible = "nxp,imx94-netc-blk-ctrl", .data = (ulong)&imx94_devinfo },
{},
};
static int netc_blk_ctrl_probe(struct udevice *dev)
{
struct netc_blk_ctrl *priv = dev_get_priv(dev);
+ struct netc_devinfo *devinfo = (struct netc_devinfo *)dev_get_driver_data(dev);
struct clk *ipg_clk;
fdt_addr_t regs;
int err;
@@ -318,10 +626,12 @@ static int netc_blk_ctrl_probe(struct udevice *dev)
priv->netcmix = (void __iomem *)regs;
- err = imx95_netcmix_init(dev);
- if (err) {
- dev_err(dev, "Initializing NETCMIX failed\n");
- return err;
+ if (devinfo->netcmix_init) {
+ err = devinfo->netcmix_init(dev);
+ if (err) {
+ dev_err(dev, "Initializing NETCMIX failed\n");
+ return err;
+ }
}
err = netc_ierb_init(dev);
@@ -333,6 +643,9 @@ static int netc_blk_ctrl_probe(struct udevice *dev)
if (netc_prb_check_error(priv) < 0)
dev_warn(dev, "The current IERB configuration is invalid\n");
+ netc_bc = priv;
+ netc_di = devinfo;
+
return 0;
}
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index d36a5f00ef8..420d7c7a44d 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -289,11 +289,19 @@ config PHY_NPCM_USB
Support the USB PHY in NPCM SoCs
config PHY_IMX8MQ_USB
- bool "NXP i.MX8MQ/i.MX8MP/i.MX95 USB PHY Driver"
+ bool "NXP i.MX8MQ/i.MX8MP/i.MX95/i.MX94 USB PHY Driver"
depends on PHY
- depends on IMX8MQ || IMX8MP || IMX95
+ depends on IMX8MQ || IMX8MP || IMX95 || IMX94
help
- Support the USB3.0 PHY in NXP i.MX8MQ, i.MX8MP, and i.MX95 SoC
+ Support the USB3.0 PHY in NXP i.MX8MQ, i.MX8MP, i.MX95, and i.MX94 SoCs.
+
+config SPL_PHY_IMX8MQ_USB
+ bool "Enable NXP i.MX8MQ/i.MX8MP/i.MX95/i.MX94 USB3.0 PHY Driver in SPL"
+ depends on SPL_PHY
+ depends on IMX8MQ || IMX8MP || IMX95 || IMX94
+ help
+ Enable support for the USB3.0 PHY in NXP i.MX8MQ, i.MX8MP, i.MX95, and
+ i.MX94 SoCs in SPL.
config PHY_IMX8M_PCIE
bool "NXP i.MX8MM/i.MX8MP PCIe PHY Driver"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 98c1ef8683b..5a6df0ecfeb 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -38,7 +38,7 @@ obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
obj-$(CONFIG_PHY_EXYNOS_USBDRD) += phy-exynos-usbdrd.o
obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o
-obj-$(CONFIG_PHY_IMX8MQ_USB) += phy-imx8mq-usb.o
+obj-$(CONFIG_$(PHASE_)PHY_IMX8MQ_USB) += phy-imx8mq-usb.o
obj-$(CONFIG_PHY_IMX8M_PCIE) += phy-imx8m-pcie.o
obj-$(CONFIG_PHY_XILINX_ZYNQMP) += phy-zynqmp.o
obj-y += cadence/
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index e9f19a69433..8056f210abc 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -33,6 +33,13 @@ config REMOTEPROC_ADI_SC5XX
Say 'y' here to add support for loading code onto SHARC cores in
an ADSP-SC5xx SoC from Analog Devices
+config REMOTEPROC_IMX
+ bool "Support for NXP i.MX remoteproc"
+ select REMOTEPROC
+ depends on DM && MACH_IMX && OF_CONTROL
+ help
+ Say 'y' here to add support for i.MX remoteproc.
+
config REMOTEPROC_RENESAS_APMU
bool "Support for Renesas R-Car Gen4 APMU start of CR52 processor"
select REMOTEPROC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 47bd57c7890..7ea8023c50b 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_$(PHASE_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
# Remote proc drivers - Please keep this list alphabetically sorted.
obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o
obj-$(CONFIG_REMOTEPROC_ADI_SC5XX) += adi_sc5xx_rproc.o
+obj-$(CONFIG_REMOTEPROC_IMX) += imx_rproc.o
obj-$(CONFIG_REMOTEPROC_RENESAS_APMU) += renesas_apmu.o
obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o
obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
new file mode 100644
index 00000000000..9bb55327998
--- /dev/null
+++ b/drivers/remoteproc/imx_rproc.c
@@ -0,0 +1,370 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/device_compat.h>
+#include <linux/arm-smccc.h>
+#include <linux/types.h>
+#include <regmap.h>
+#include <remoteproc.h>
+#include <syscon.h>
+
+#include "imx_rproc.h"
+
+#define IMX7D_SRC_SCR 0x0C
+#define IMX7D_ENABLE_M4 BIT(3)
+#define IMX7D_SW_M4P_RST BIT(2)
+#define IMX7D_SW_M4C_RST BIT(1)
+#define IMX7D_SW_M4C_NON_SCLR_RST BIT(0)
+
+#define IMX7D_M4_RST_MASK (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \
+ | IMX7D_SW_M4C_RST \
+ | IMX7D_SW_M4C_NON_SCLR_RST)
+
+#define IMX7D_M4_START (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \
+ | IMX7D_SW_M4C_RST)
+#define IMX7D_M4_STOP (IMX7D_ENABLE_M4 | IMX7D_SW_M4C_RST | \
+ IMX7D_SW_M4C_NON_SCLR_RST)
+
+#define IMX_RPROC_MEM_MAX 32
+
+#define IMX_SIP_RPROC 0xC2000005
+#define IMX_SIP_RPROC_START 0x00
+#define IMX_SIP_RPROC_STARTED 0x01
+#define IMX_SIP_RPROC_STOP 0x02
+
+struct imx_rproc {
+ const struct imx_rproc_dcfg *dcfg;
+ struct regmap *regmap;
+};
+
+/* 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)
+
+static int imx_rproc_arm_smc_start(struct udevice *dev)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res);
+
+ return res.a0;
+}
+
+static int imx_rproc_mmio_start(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+
+ return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_start);
+}
+
+static int imx_rproc_start(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ int ret;
+
+ if (!dcfg->ops || !dcfg->ops->start)
+ return -EOPNOTSUPP;
+
+ ret = dcfg->ops->start(dev);
+ if (ret)
+ dev_err(dev, "Failed to enable remote core!\n");
+
+ return ret;
+}
+
+static int imx_rproc_arm_smc_stop(struct udevice *dev)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res);
+ if (res.a1)
+ dev_info(dev, "Not in wfi, force stopped\n");
+
+ return res.a0;
+}
+
+static int imx_rproc_mmio_stop(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+
+ return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_stop);
+}
+
+static int imx_rproc_stop(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ int ret;
+
+ if (!dcfg->ops || !dcfg->ops->stop)
+ return -EOPNOTSUPP;
+
+ ret = dcfg->ops->stop(dev);
+ if (ret)
+ dev_err(dev, "Failed to stop remote core\n");
+
+ return ret;
+}
+
+static int imx_rproc_arm_smc_is_running(struct udevice *dev)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res);
+ if (res.a0)
+ return 0;
+
+ return 1;
+}
+
+static int imx_rproc_mmio_is_running(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ int ret;
+ u32 val;
+
+ ret = regmap_read(priv->regmap, dcfg->src_reg, &val);
+ if (ret) {
+ dev_err(dev, "Failed to read src\n");
+ return ret;
+ }
+
+ if ((val & dcfg->src_mask) != dcfg->src_stop)
+ return 0;
+
+ return 1;
+}
+
+static int imx_rproc_is_running(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+
+ if (!dcfg->ops || !dcfg->ops->is_running)
+ return 0;
+
+ return dcfg->ops->is_running(dev);
+}
+
+static int imx_rproc_init(struct udevice *dev)
+{
+ return 0;
+}
+
+static int imx_rproc_da_to_sys(struct udevice *dev, u64 da, size_t len, u64 *sys, bool *is_iomem)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ int i;
+
+ /* parse address translation table */
+ for (i = 0; i < dcfg->att_size; i++) {
+ const struct imx_rproc_att *att = &dcfg->att[i];
+
+ if (da >= att->da && da + len < att->da + att->size) {
+ unsigned int offset = da - att->da;
+
+ *sys = att->sa + offset;
+
+ if (is_iomem)
+ *is_iomem = att->flags & ATT_IOMEM;
+
+ return 0;
+ }
+ }
+
+ dev_err(dev, "Translation failed: da = 0x%llx len = 0x%zx\n", da, len);
+
+ return -ENOENT;
+}
+
+static void *imx_rproc_device_to_virt(struct udevice *dev, ulong da, ulong size, bool *is_iomem)
+{
+ u64 sys;
+
+ if (imx_rproc_da_to_sys(dev, da, size, &sys, is_iomem))
+ return NULL;
+
+ dev_dbg(dev, "da = 0x%lx len = 0x%lx sys = 0x%llx\n", da, size, sys);
+
+ return phys_to_virt(sys);
+}
+
+static int imx_rproc_load(struct udevice *dev, ulong addr, ulong size)
+{
+ return rproc_elf_load_image(dev, addr, size);
+}
+
+static const struct dm_rproc_ops imx_rproc_ops = {
+ .init = imx_rproc_init,
+ .start = imx_rproc_start,
+ .stop = imx_rproc_stop,
+ .load = imx_rproc_load,
+ .device_to_virt = imx_rproc_device_to_virt,
+ .is_running = imx_rproc_is_running,
+};
+
+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);
+ ofnode node;
+
+ node = dev_ofnode(dev);
+
+ priv->dcfg = dcfg;
+
+ if (dcfg->method != IMX_RPROC_MMIO)
+ return 0;
+
+ 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;
+}
+
+static const struct imx_rproc_att imx_rproc_att_imx8mn[] = {
+ /* dev addr , sys addr , size , flags */
+ /* ITCM */
+ { 0x00000000, 0x007E0000, 0x00020000, ATT_OWN | ATT_IOMEM },
+ /* OCRAM_S */
+ { 0x00180000, 0x00180000, 0x00009000, 0 },
+ /* OCRAM */
+ { 0x00900000, 0x00900000, 0x00020000, 0 },
+ /* OCRAM */
+ { 0x00920000, 0x00920000, 0x00020000, 0 },
+ /* OCRAM */
+ { 0x00940000, 0x00940000, 0x00050000, 0 },
+ /* QSPI Code - alias */
+ { 0x08000000, 0x08000000, 0x08000000, 0 },
+ /* DDR (Code) - alias */
+ { 0x10000000, 0x40000000, 0x0FFE0000, 0 },
+ /* DTCM */
+ { 0x20000000, 0x00800000, 0x00020000, ATT_OWN | ATT_IOMEM },
+ /* OCRAM_S - alias */
+ { 0x20180000, 0x00180000, 0x00008000, ATT_OWN },
+ /* OCRAM */
+ { 0x20200000, 0x00900000, 0x00020000, ATT_OWN },
+ /* OCRAM */
+ { 0x20220000, 0x00920000, 0x00020000, ATT_OWN },
+ /* OCRAM */
+ { 0x20240000, 0x00940000, 0x00040000, ATT_OWN },
+ /* DDR (Data) */
+ { 0x40000000, 0x40000000, 0x80000000, 0 },
+};
+
+static const struct imx_rproc_plat_ops imx_rproc_ops_arm_smc = {
+ .start = imx_rproc_arm_smc_start,
+ .stop = imx_rproc_arm_smc_stop,
+ .is_running = imx_rproc_arm_smc_is_running,
+};
+
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = {
+ .att = imx_rproc_att_imx8mn,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn),
+ .method = IMX_RPROC_SMC,
+ .ops = &imx_rproc_ops_arm_smc,
+};
+
+static const struct imx_rproc_att imx_rproc_att_imx8mq[] = {
+ /* dev addr , sys addr , size , flags */
+ /* TCML - alias */
+ { 0x00000000, 0x007e0000, 0x00020000, ATT_IOMEM},
+ /* OCRAM_S */
+ { 0x00180000, 0x00180000, 0x00008000, 0 },
+ /* OCRAM */
+ { 0x00900000, 0x00900000, 0x00020000, 0 },
+ /* OCRAM */
+ { 0x00920000, 0x00920000, 0x00020000, 0 },
+ /* QSPI Code - alias */
+ { 0x08000000, 0x08000000, 0x08000000, 0 },
+ /* DDR (Code) - alias */
+ { 0x10000000, 0x40000000, 0x0FFE0000, 0 },
+ /* TCML/U */
+ { 0x1FFE0000, 0x007E0000, 0x00040000, ATT_OWN | ATT_IOMEM},
+ /* OCRAM_S */
+ { 0x20180000, 0x00180000, 0x00008000, ATT_OWN },
+ /* OCRAM */
+ { 0x20200000, 0x00900000, 0x00020000, ATT_OWN },
+ /* OCRAM */
+ { 0x20220000, 0x00920000, 0x00020000, ATT_OWN },
+ /* DDR (Data) */
+ { 0x40000000, 0x40000000, 0x80000000, 0 },
+};
+
+static const struct imx_rproc_plat_ops imx_rproc_ops_mmio = {
+ .start = imx_rproc_mmio_start,
+ .stop = imx_rproc_mmio_stop,
+ .is_running = imx_rproc_mmio_is_running,
+};
+
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = {
+ .src_reg = IMX7D_SRC_SCR,
+ .src_mask = IMX7D_M4_RST_MASK,
+ .src_start = IMX7D_M4_START,
+ .src_stop = IMX7D_M4_STOP,
+ .att = imx_rproc_att_imx8mq,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq),
+ .method = IMX_RPROC_MMIO,
+ .ops = &imx_rproc_ops_mmio,
+};
+
+static const struct imx_rproc_att imx_rproc_att_imx93[] = {
+ /* dev addr , sys addr , size , flags */
+ /* TCM CODE NON-SECURE */
+ { 0x0FFC0000, 0x201C0000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+ /* TCM CODE SECURE */
+ { 0x1FFC0000, 0x201C0000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+ /* TCM SYS NON-SECURE*/
+ { 0x20000000, 0x20200000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+ /* TCM SYS SECURE*/
+ { 0x30000000, 0x20200000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+ /* DDR */
+ { 0x80000000, 0x80000000, 0x10000000, 0 },
+ { 0x90000000, 0x80000000, 0x10000000, 0 },
+
+ { 0xC0000000, 0xC0000000, 0x10000000, 0 },
+ { 0xD0000000, 0xC0000000, 0x10000000, 0 },
+};
+
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = {
+ .att = imx_rproc_att_imx93,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx93),
+ .method = IMX_RPROC_SMC,
+ .ops = &imx_rproc_ops_arm_smc,
+};
+
+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 },
+ {}
+};
+
+U_BOOT_DRIVER(imx_rproc) = {
+ .name = "imx_rproc",
+ .of_match = imx_rproc_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &imx_rproc_ops,
+ .probe = imx_rproc_probe,
+ .priv_auto = sizeof(struct imx_rproc),
+};
diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
new file mode 100644
index 00000000000..7a82dc4a195
--- /dev/null
+++ b/drivers/remoteproc/imx_rproc.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2017 Pengutronix, Oleksij Rempel <[email protected]>
+ * Copyright 2021 NXP
+ */
+
+#ifndef _IMX_RPROC_H
+#define _IMX_RPROC_H
+
+/* address translation table */
+struct imx_rproc_att {
+ u32 da; /* device address (From Cortex M4 view)*/
+ u32 sa; /* system bus address */
+ u32 size; /* size of reg range */
+ int flags;
+};
+
+/* Remote core start/stop method */
+enum imx_rproc_method {
+ IMX_RPROC_NONE,
+ /* Through syscon regmap */
+ IMX_RPROC_MMIO,
+ /* Through ARM SMCCC */
+ IMX_RPROC_SMC,
+ /* Through System Control Unit API */
+ IMX_RPROC_SCU_API,
+ /* Through Reset Controller API */
+ IMX_RPROC_RESET_CONTROLLER,
+ /* Through System Manager */
+ IMX_RPROC_SM,
+};
+
+/* dcfg flags */
+#define IMX_RPROC_NEED_SYSTEM_OFF BIT(0)
+
+struct imx_rproc_plat_ops {
+ int (*start)(struct udevice *dev);
+ int (*stop)(struct udevice *dev);
+ int (*is_running)(struct udevice *dev);
+};
+
+struct imx_rproc_dcfg {
+ u32 src_reg;
+ u32 src_mask;
+ u32 src_start;
+ u32 src_stop;
+ u32 gpr_reg;
+ u32 gpr_wait;
+ const struct imx_rproc_att *att;
+ size_t att_size;
+ enum imx_rproc_method method;
+ u32 flags;
+ const struct imx_rproc_plat_ops *ops;
+};
+
+#endif /* _IMX_RPROC_H */
diff --git a/drivers/remoteproc/renesas_apmu.c b/drivers/remoteproc/renesas_apmu.c
index 1a50cd3289b..91586a99e0d 100644
--- a/drivers/remoteproc/renesas_apmu.c
+++ b/drivers/remoteproc/renesas_apmu.c
@@ -170,11 +170,12 @@ static int renesas_apmu_rproc_init(struct udevice *dev)
* @dev: corresponding remote processor device
* @da: device address
* @size: Size of the memory region @da is pointing to
+ * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory
*
* Return: converted virtual address
*/
static void *renesas_apmu_rproc_device_to_virt(struct udevice *dev, ulong da,
- ulong size)
+ ulong size, bool *is_iomem)
{
/*
* The Cortex R52 and A76 share the same address space,
diff --git a/drivers/remoteproc/rproc-elf-loader.c b/drivers/remoteproc/rproc-elf-loader.c
index 0b3941b7798..83d70c2fb54 100644
--- a/drivers/remoteproc/rproc-elf-loader.c
+++ b/drivers/remoteproc/rproc-elf-loader.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ * Copyright 2025 NXP
*/
#include <cpu_func.h>
#include <dm.h>
@@ -9,6 +10,7 @@
#include <mapmem.h>
#include <remoteproc.h>
#include <asm/cache.h>
+#include <asm/io.h>
#include <dm/device_compat.h>
#include <linux/compat.h>
#include <linux/printk.h>
@@ -181,27 +183,38 @@ int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size)
for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
void *dst = (void *)(uintptr_t)phdr->p_paddr;
void *src = (void *)addr + phdr->p_offset;
+ bool is_iomem = false;
ulong dst_addr;
- if (phdr->p_type != PT_LOAD)
+ if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
continue;
if (ops->device_to_virt)
dst = ops->device_to_virt(dev, (ulong)dst,
- phdr->p_memsz);
+ phdr->p_memsz, &is_iomem);
dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
i, dst, phdr->p_filesz);
- if (phdr->p_filesz)
- memcpy(dst, src, phdr->p_filesz);
- if (phdr->p_filesz != phdr->p_memsz)
- memset(dst + phdr->p_filesz, 0x00,
- phdr->p_memsz - phdr->p_filesz);
+ if (phdr->p_filesz) {
+ if (is_iomem)
+ memcpy_toio(dst, src, phdr->p_filesz);
+ else
+ memcpy(dst, src, phdr->p_filesz);
+ }
+ if (phdr->p_filesz != phdr->p_memsz) {
+ if (is_iomem)
+ memset_io(dst + phdr->p_filesz, 0x00,
+ phdr->p_memsz - phdr->p_filesz);
+ else
+ memset(dst + phdr->p_filesz, 0x00,
+ phdr->p_memsz - phdr->p_filesz);
+ }
dst_addr = map_to_sysmem(dst);
- flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN),
- roundup(dst_addr + phdr->p_filesz,
- ARCH_DMA_MINALIGN) -
- rounddown(dst_addr, ARCH_DMA_MINALIGN));
+ if (!is_iomem) {
+ flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN),
+ roundup(dst_addr + phdr->p_filesz, ARCH_DMA_MINALIGN) -
+ rounddown(dst_addr, ARCH_DMA_MINALIGN));
+ }
}
return 0;
@@ -230,6 +243,7 @@ int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size)
memsz = phdr->p_memsz;
filesz = phdr->p_filesz;
offset = phdr->p_offset;
+ bool is_iomem = false;
if (phdr->p_type != PT_LOAD)
continue;
@@ -239,7 +253,7 @@ int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size)
ptr = (void *)(uintptr_t)da;
if (ops->device_to_virt) {
- ptr = ops->device_to_virt(dev, da, phdr->p_memsz);
+ ptr = ops->device_to_virt(dev, da, phdr->p_memsz, &is_iomem);
if (!ptr) {
dev_err(dev, "bad da 0x%llx mem 0x%llx\n", da,
memsz);
@@ -248,14 +262,24 @@ int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size)
}
}
- if (filesz)
- memcpy(ptr, (void *)addr + offset, filesz);
- if (filesz != memsz)
- memset(ptr + filesz, 0x00, memsz - filesz);
+ if (filesz) {
+ if (is_iomem)
+ memcpy_toio(ptr, (void *)addr + offset, filesz);
+ else
+ memcpy(ptr, (void *)addr + offset, filesz);
+ }
+ if (filesz != memsz) {
+ if (is_iomem)
+ memset_io(ptr + filesz, 0x00, memsz - filesz);
+ else
+ memset(ptr + filesz, 0x00, memsz - filesz);
+ }
- flush_cache(rounddown((ulong)ptr, ARCH_DMA_MINALIGN),
- roundup((ulong)ptr + filesz, ARCH_DMA_MINALIGN) -
- rounddown((ulong)ptr, ARCH_DMA_MINALIGN));
+ if (!is_iomem) {
+ flush_cache(rounddown((ulong)ptr, ARCH_DMA_MINALIGN),
+ roundup((ulong)ptr + filesz, ARCH_DMA_MINALIGN) -
+ rounddown((ulong)ptr, ARCH_DMA_MINALIGN));
+ }
}
return ret;
@@ -381,6 +405,7 @@ int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr,
Elf32_Shdr *shdr;
void *src, *dst;
ulong dst_addr;
+ bool is_iomem = false;
shdr = rproc_elf32_find_rsc_table(dev, fw_addr, fw_size);
if (!shdr)
@@ -394,18 +419,22 @@ int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr,
src = (void *)fw_addr + shdr->sh_offset;
if (ops->device_to_virt)
- dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size);
+ dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size, &is_iomem);
else
dst = (void *)rsc_addr;
dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n",
(ulong)dst, *rsc_size);
- memcpy(dst, src, *rsc_size);
- dst_addr = map_to_sysmem(dst);
- flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN),
- roundup(dst_addr + *rsc_size, ARCH_DMA_MINALIGN) -
- rounddown(dst_addr, ARCH_DMA_MINALIGN));
+ if (is_iomem) {
+ memcpy_toio(dst, src, *rsc_size);
+ } else {
+ memcpy(dst, src, *rsc_size);
+ dst_addr = map_to_sysmem(dst);
+ flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN),
+ roundup(dst_addr + *rsc_size, ARCH_DMA_MINALIGN) -
+ rounddown(dst_addr, ARCH_DMA_MINALIGN));
+ }
return 0;
}
@@ -490,6 +519,7 @@ int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr,
const struct dm_rproc_ops *ops;
Elf64_Shdr *shdr;
void *src, *dst;
+ bool is_iomem = false;
shdr = rproc_elf64_find_rsc_table(dev, fw_addr, fw_size);
if (!shdr)
@@ -503,18 +533,21 @@ int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr,
src = (void *)fw_addr + shdr->sh_offset;
if (ops->device_to_virt)
- dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size);
+ dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size, &is_iomem);
else
dst = (void *)rsc_addr;
dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n",
(ulong)dst, *rsc_size);
- memcpy(dst, src, *rsc_size);
- flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
- roundup((unsigned long)dst + *rsc_size,
- ARCH_DMA_MINALIGN) -
- rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
+ if (is_iomem) {
+ memcpy_toio(dst, src, *rsc_size);
+ } else {
+ memcpy(dst, src, *rsc_size);
+ flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
+ roundup((unsigned long)dst + *rsc_size, ARCH_DMA_MINALIGN) -
+ rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
+ }
return 0;
}
diff --git a/drivers/remoteproc/sandbox_testproc.c b/drivers/remoteproc/sandbox_testproc.c
index ad575a7c10f..7ed38e8656c 100644
--- a/drivers/remoteproc/sandbox_testproc.c
+++ b/drivers/remoteproc/sandbox_testproc.c
@@ -308,10 +308,11 @@ static int sandbox_testproc_ping(struct udevice *dev)
* @dev: device to operate upon
* @da: device address
* @size: Size of the memory region @da is pointing to
+ * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory
* Return: converted virtual address
*/
static void *sandbox_testproc_device_to_virt(struct udevice *dev, ulong da,
- ulong size)
+ ulong size, bool *is_iomem)
{
u64 paddr;
diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c
index f45da9a68ac..bf721e78bb3 100644
--- a/drivers/remoteproc/stm32_copro.c
+++ b/drivers/remoteproc/stm32_copro.c
@@ -61,10 +61,11 @@ static int stm32_copro_probe(struct udevice *dev)
* @dev: corresponding STM32 remote processor device
* @da: device address
* @size: Size of the memory region @da is pointing to
+ * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory
* Return: converted virtual address
*/
static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da,
- ulong size)
+ ulong size, bool *is_iomem)
{
fdt32_t in_addr = cpu_to_be32(da), end_addr;
u64 paddr;
diff --git a/drivers/remoteproc/ti_k3_dsp_rproc.c b/drivers/remoteproc/ti_k3_dsp_rproc.c
index 5a7d6377283..9275e1b241d 100644
--- a/drivers/remoteproc/ti_k3_dsp_rproc.c
+++ b/drivers/remoteproc/ti_k3_dsp_rproc.c
@@ -261,7 +261,7 @@ static int k3_dsp_reset(struct udevice *dev)
return 0;
}
-static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len)
+static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len, bool *is_iomem)
{
struct k3_dsp_privdata *dsp = dev_get_priv(dev);
phys_addr_t bus_addr, dev_addr;
diff --git a/drivers/remoteproc/ti_k3_m4_rproc.c b/drivers/remoteproc/ti_k3_m4_rproc.c
index 31b9de71579..f358788f07f 100644
--- a/drivers/remoteproc/ti_k3_m4_rproc.c
+++ b/drivers/remoteproc/ti_k3_m4_rproc.c
@@ -181,7 +181,7 @@ static int k3_m4_stop(struct udevice *dev)
return 0;
}
-static void *k3_m4_da_to_va(struct udevice *dev, ulong da, ulong len)
+static void *k3_m4_da_to_va(struct udevice *dev, ulong da, ulong len, bool *is_iomem)
{
struct k3_m4_privdata *m4 = dev_get_priv(dev);
phys_addr_t bus_addr, dev_addr;
diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c
index 48401bc6eb6..c738607c109 100644
--- a/drivers/remoteproc/ti_k3_r5f_rproc.c
+++ b/drivers/remoteproc/ti_k3_r5f_rproc.c
@@ -534,7 +534,7 @@ proc_release:
return ret;
}
-static void *k3_r5f_da_to_va(struct udevice *dev, ulong da, ulong size)
+static void *k3_r5f_da_to_va(struct udevice *dev, ulong da, ulong size, bool *is_iomem)
{
struct k3_r5f_core *core = dev_get_priv(dev);
void __iomem *va = NULL;
diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c
index 647001d8dd0..f72e27028b7 100644
--- a/drivers/usb/gadget/f_sdp.c
+++ b/drivers/usb/gadget/f_sdp.c
@@ -765,7 +765,7 @@ static ulong search_container_header(ulong p, int size)
for (i = 0; i < size; i += 4) {
hdr = (u8 *)(p + i);
- if (*(hdr + 3) == 0x87 && *hdr == 0)
+ if (*(hdr + 3) == 0x87 && (*hdr == 0 || *hdr == 2))
if (*(hdr + 1) != 0 || *(hdr + 2) != 0)
return p + i;
}
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 2cf687fc4f3..427b62e934b 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -210,10 +210,10 @@ config USB_EHCI_MX6
config USB_EHCI_MX7
bool "Support for i.MX7/i.MX8M/i.MX9 on-chip EHCI USB controller"
- depends on ARCH_MX7 || IMX8M || IMX93 || IMX95
+ depends on ARCH_MX7 || IMX8M || IMX9
select EHCI_HCD_INIT_AFTER_RESET if ARCH_MX7
- select PHY if IMX8M || IMX93 || IMX95
- select NOP_PHY if IMX8M || IMX93 || IMX95
+ select PHY if IMX8M || IMX9
+ select NOP_PHY if IMX8M || IMX9
default y
---help---
Enables support for the on-chip EHCI controller on i.MX7/i.MX8M/i.MX9 SoCs.