diff options
author | Tom Rini <trini@konsulko.com> | 2025-03-13 16:45:19 -0600 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2025-03-13 16:45:19 -0600 |
commit | bbfabe290138d76e78e0dac28fec93c32e3964eb (patch) | |
tree | 86fe61d09018049f8e21f3a940b98eb5c8df7952 | |
parent | 9805321dfdeb5225fe5c5e0721abf49c0875637e (diff) | |
parent | 21a4ac55c0d4eba836a45345d011093ffdc85b5c (diff) |
Merge tag 'u-boot-imx-next-20250313' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx into next
CI: https://source.denx.de/u-boot/custodians/u-boot-imx/-/pipelines/25142
- Support Toradex i.MX6 Apalis/Colibri v1.2 SoM.
- Guard tee.bin inclusion on imx9,
- Remove unneeded regulator entry on DH i.MX6 DHCOM DRC02 devicetree.
- Add i.MX mailbox driver
- Convert ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE to Kconfig.
- Cope with existing optee node on imx8m.
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | arch/arm/dts/imx6qdl-dhcom-u-boot.dtsi | 5 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8m/soc.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx9/container.cfg | 2 | ||||
-rw-r--r-- | arch/powerpc/include/asm/config_mpc85xx.h | 3 | ||||
-rw-r--r-- | board/toradex/apalis_imx6/apalis_imx6.c | 31 | ||||
-rw-r--r-- | board/toradex/colibri_imx6/colibri_imx6.c | 31 | ||||
-rw-r--r-- | configs/apalis_imx6_defconfig | 2 | ||||
-rw-r--r-- | configs/colibri_imx6_defconfig | 2 | ||||
-rw-r--r-- | drivers/mailbox/Kconfig | 7 | ||||
-rw-r--r-- | drivers/mailbox/Makefile | 1 | ||||
-rw-r--r-- | drivers/mailbox/imx-mailbox.c | 443 | ||||
-rw-r--r-- | drivers/mmc/Kconfig | 6 | ||||
-rw-r--r-- | drivers/mmc/fsl_esdhc_imx.c | 8 | ||||
-rw-r--r-- | include/configs/imxrt1020-evk.h | 2 | ||||
-rw-r--r-- | include/configs/imxrt1050-evk.h | 2 | ||||
-rw-r--r-- | include/configs/imxrt1170-evk.h | 2 |
17 files changed, 527 insertions, 24 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index e2339ecd2d0..92d4a158fd0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -315,6 +315,7 @@ F: board/freescale/*mx*/ F: board/freescale/common/ F: common/spl/spl_imx_container.c F: doc/imx/ +F: drivers/mailbox/imx-mailbox.c F: drivers/serial/serial_mxc.c F: include/imx_container.h diff --git a/arch/arm/dts/imx6qdl-dhcom-u-boot.dtsi b/arch/arm/dts/imx6qdl-dhcom-u-boot.dtsi index 740a24d96ec..300e355c8ef 100644 --- a/arch/arm/dts/imx6qdl-dhcom-u-boot.dtsi +++ b/arch/arm/dts/imx6qdl-dhcom-u-boot.dtsi @@ -27,11 +27,6 @@ }; }; -®_usb_otg_vbus { - gpio = <&gpio3 31 GPIO_ACTIVE_HIGH>; - enable-active-high; -}; - &wdog1 { bootph-pre-ram; }; diff --git a/arch/arm/mach-imx/imx8m/soc.c b/arch/arm/mach-imx/imx8m/soc.c index 85dc8b51a14..567e8e9e81a 100644 --- a/arch/arm/mach-imx/imx8m/soc.c +++ b/arch/arm/mach-imx/imx8m/soc.c @@ -1270,8 +1270,9 @@ static int ft_add_optee_node(void *fdt, struct bd_info *bd) } } + /* Locate the optee node if it exists or create it. */ subpath = "optee"; - offs = fdt_add_subnode(fdt, offs, subpath); + offs = fdt_find_or_add_subnode(fdt, offs, subpath); if (offs < 0) { printf("Could not create %s node.\n", subpath); return offs; diff --git a/arch/arm/mach-imx/imx9/container.cfg b/arch/arm/mach-imx/imx9/container.cfg index 91a973161d1..a018c365c82 100644 --- a/arch/arm/mach-imx/imx9/container.cfg +++ b/arch/arm/mach-imx/imx9/container.cfg @@ -12,4 +12,6 @@ IMAGE A55 bl31.bin 0x204C0000 IMAGE A55 bl31.bin 0x204E0000 #endif IMAGE A55 u-boot.bin CONFIG_TEXT_BASE +#ifdef CONFIG_OPTEE IMAGE A55 tee.bin 0x96000000 +#endif diff --git a/arch/powerpc/include/asm/config_mpc85xx.h b/arch/powerpc/include/asm/config_mpc85xx.h index 819250f0090..abdaffbe00b 100644 --- a/arch/powerpc/include/asm/config_mpc85xx.h +++ b/arch/powerpc/include/asm/config_mpc85xx.h @@ -133,7 +133,6 @@ #define CFG_FM_PLAT_CLK_DIV 1 #define CFG_SYS_FM1_CLK CFG_FM_PLAT_CLK_DIV #define CFG_SYS_FM_MURAM_SIZE 0x30000 -#define ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE #define QE_MURAM_SIZE 0x6000UL #define MAX_QE_RISC 1 #define QE_NUM_OF_SNUM 28 @@ -146,7 +145,6 @@ #define CFG_SYS_FM1_CLK 0 #define CFG_QBMAN_CLK_DIV 1 #define CFG_SYS_FM_MURAM_SIZE 0x30000 -#define ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE #define QE_MURAM_SIZE 0x6000UL #define MAX_QE_RISC 1 #define QE_NUM_OF_SNUM 28 @@ -165,7 +163,6 @@ #define CFG_SYS_PME_CLK CFG_PME_PLAT_CLK_DIV #define CFG_SYS_FM1_CLK 0 #define CFG_SYS_FM_MURAM_SIZE 0x28000 -#define ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE #elif defined(CONFIG_ARCH_C29X) #define CFG_SYS_FSL_SEC_IDX_OFFSET 0x20000 diff --git a/board/toradex/apalis_imx6/apalis_imx6.c b/board/toradex/apalis_imx6/apalis_imx6.c index ec0f223c4aa..e0a7c661270 100644 --- a/board/toradex/apalis_imx6/apalis_imx6.c +++ b/board/toradex/apalis_imx6/apalis_imx6.c @@ -36,6 +36,7 @@ #include <dwc_ahsata.h> #include <env.h> #include <fsl_esdhc_imx.h> +#include <i2c.h> #include <imx_thermal.h> #include <micrel.h> #include <miiphy.h> @@ -77,6 +78,8 @@ DECLARE_GLOBAL_DATA_PTR; #define APALIS_IMX6_SATA_INIT_RETRIES 10 +#define I2C_PWR 1 + int dram_init(void) { /* use the DDR controllers configured size */ @@ -689,6 +692,32 @@ int board_init(void) return 0; } +static bool is_som_variant_1_2(void) +{ + struct udevice *bus; + struct udevice *i2c_dev; + int ret; + + ret = uclass_get_device_by_seq(UCLASS_I2C, I2C_PWR, &bus); + if (ret) { + printf("Failed to get I2C_PWR\n"); + return false; + } + + /* V1.2 uses the TLA2024 at 0x49 instead of the STMPE811 at 0x41 */ + ret = dm_i2c_probe(bus, 0x49, 0, &i2c_dev); + + return (bool)!ret; +} + +static void select_dt_from_module_version(void) +{ + if (is_som_variant_1_2()) + env_set("variant", "-v1.2"); + else + env_set("variant", ""); +} + #ifdef CONFIG_BOARD_LATE_INIT int board_late_init(void) { @@ -696,6 +725,8 @@ int board_late_init(void) char env_str[256]; u32 rev; + select_dt_from_module_version(); + rev = get_board_revision(); snprintf(env_str, ARRAY_SIZE(env_str), "%.4x", rev); env_set("board_rev", env_str); diff --git a/board/toradex/colibri_imx6/colibri_imx6.c b/board/toradex/colibri_imx6/colibri_imx6.c index 64cf99e9cfc..69a3c5f3dfd 100644 --- a/board/toradex/colibri_imx6/colibri_imx6.c +++ b/board/toradex/colibri_imx6/colibri_imx6.c @@ -33,6 +33,7 @@ #include <cpu.h> #include <dm/platform_data/serial_mxc.h> #include <fsl_esdhc_imx.h> +#include <i2c.h> #include <imx_thermal.h> #include <miiphy.h> #include <netdev.h> @@ -71,6 +72,8 @@ DECLARE_GLOBAL_DATA_PTR; #define OUTPUT_RGB (PAD_CTL_SPEED_MED|PAD_CTL_DSE_60ohm|PAD_CTL_SRE_FAST) +#define I2C_PWR 1 + int dram_init(void) { /* use the DDR controllers configured size */ @@ -609,6 +612,32 @@ int board_init(void) return 0; } +static bool is_som_variant_1_2(void) +{ + struct udevice *bus; + struct udevice *i2c_dev; + int ret; + + ret = uclass_get_device_by_seq(UCLASS_I2C, I2C_PWR, &bus); + if (ret) { + printf("Failed to get I2C_PWR\n"); + return false; + } + + /* V1.2 uses the TLA2024 at 0x49 instead of the STMPE811 at 0x41 */ + ret = dm_i2c_probe(bus, 0x49, 0, &i2c_dev); + + return (bool)!ret; +} + +static void select_dt_from_module_version(void) +{ + if (is_som_variant_1_2()) + env_set("variant", "-v1.2"); + else + env_set("variant", ""); +} + #ifdef CONFIG_BOARD_LATE_INIT int board_late_init(void) { @@ -616,6 +645,8 @@ int board_late_init(void) char env_str[256]; u32 rev; + select_dt_from_module_version(); + rev = get_board_revision(); snprintf(env_str, ARRAY_SIZE(env_str), "%.4x", rev); env_set("board_rev", env_str); diff --git a/configs/apalis_imx6_defconfig b/configs/apalis_imx6_defconfig index a3f65c5c026..f51386d10a8 100644 --- a/configs/apalis_imx6_defconfig +++ b/configs/apalis_imx6_defconfig @@ -31,7 +31,7 @@ CONFIG_DISTRO_DEFAULTS=y CONFIG_BOOTDELAY=1 CONFIG_BOOTCOMMAND="run distro_bootcmd; usb start; setenv stdout serial,vidconsole; setenv stdin serial,usbkbd" CONFIG_USE_PREBOOT=y -CONFIG_PREBOOT="test -n ${fdtfile} || setenv fdtfile imx6q-apalis-${fdt_board}.dtb" +CONFIG_PREBOOT="test -n ${fdtfile} || setenv fdtfile imx6q-apalis${variant}-${fdt_board}.dtb" CONFIG_SYS_CBSIZE=1024 CONFIG_SYS_PBSIZE=1055 CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE=y diff --git a/configs/colibri_imx6_defconfig b/configs/colibri_imx6_defconfig index 4c6ba80789b..9fc844b3269 100644 --- a/configs/colibri_imx6_defconfig +++ b/configs/colibri_imx6_defconfig @@ -30,7 +30,7 @@ CONFIG_DISTRO_DEFAULTS=y CONFIG_BOOTDELAY=1 CONFIG_BOOTCOMMAND="run distro_bootcmd; usb start; setenv stdout serial,vidconsole; setenv stdin serial,usbkbd" CONFIG_USE_PREBOOT=y -CONFIG_PREBOOT="test -n ${fdtfile} || setenv fdtfile imx6dl-colibri-${fdt_board}.dtb" +CONFIG_PREBOOT="test -n ${fdtfile} || setenv fdtfile imx6dl-colibri${variant}-${fdt_board}.dtb" CONFIG_SYS_CBSIZE=1024 CONFIG_SYS_PBSIZE=1056 CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE=y diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 67d5ac1a742..4d9f004ebad 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -21,6 +21,13 @@ config APPLE_MBOX such as the System Management Controller (SMC) and NVMe and this driver is required to get that functionality up and running. +config IMX_MU_MBOX + bool "Enable i.MX MU MBOX support" + depends on DM_MAILBOX + help + Enable support for i.MX Messaging Unit for communication with other + processors on the SoC using mailbox interface + config SANDBOX_MBOX bool "Enable the sandbox mailbox test driver" depends on DM_MAILBOX && SANDBOX diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 6072fa1956b..574add60005 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_$(XPL_)DM_MAILBOX) += mailbox-uclass.o obj-$(CONFIG_APPLE_MBOX) += apple-mbox.o +obj-$(CONFIG_IMX_MU_MBOX) += imx-mailbox.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c new file mode 100644 index 00000000000..b1e0465e7a8 --- /dev/null +++ b/drivers/mailbox/imx-mailbox.c @@ -0,0 +1,443 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2025 NXP + */ + +#include <asm/io.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <mailbox-uclass.h> +#include <linux/bitfield.h> +#include <linux/bug.h> +#include <linux/iopoll.h> +#include <linux/compat.h> + +/* This driver only exposes the status bits to keep with the + * polling methodology of u-boot. + */ +DECLARE_GLOBAL_DATA_PTR; + +#define IMX_MU_CHANS 24 + +#define IMX_MU_V2_PAR_OFF 0x4 +#define IMX_MU_V2_TR_MASK GENMASK(7, 0) +#define IMX_MU_V2_RR_MASK GENMASK(15, 8) + +enum imx_mu_chan_type { + IMX_MU_TYPE_TX = 0, /* Tx */ + IMX_MU_TYPE_RX = 1, /* Rx */ + IMX_MU_TYPE_TXDB = 2, /* Tx doorbell */ + IMX_MU_TYPE_RXDB = 3, /* Rx doorbell */ + IMX_MU_TYPE_RST = 4, /* Reset */ + IMX_MU_TYPE_TXDB_V2 = 5, /* Tx doorbell with S/W ACK */ +}; + +enum imx_mu_xcr { + IMX_MU_CR, + IMX_MU_GIER, + IMX_MU_GCR, + IMX_MU_TCR, + IMX_MU_RCR, + IMX_MU_xCR_MAX, +}; + +enum imx_mu_xsr { + IMX_MU_SR, + IMX_MU_GSR, + IMX_MU_TSR, + IMX_MU_RSR, + IMX_MU_xSR_MAX, +}; + +struct imx_mu_con_priv { + unsigned int idx; + enum imx_mu_chan_type type; + struct mbox_chan *chan; +}; + +enum imx_mu_type { + IMX_MU_V1, + IMX_MU_V2 = BIT(1), + IMX_MU_V2_S4 = BIT(15), + IMX_MU_V2_IRQ = BIT(16), +}; + +struct imx_mu { + void __iomem *base; + const struct imx_mu_dcfg *dcfg; + u32 num_tr; + u32 num_rr; + /* use pointers to channel as a way to reserve channels */ + struct mbox_chan *channels[IMX_MU_CHANS]; + struct imx_mu_con_priv con_priv[IMX_MU_CHANS]; +}; + +struct imx_mu_dcfg { + int (*tx)(struct imx_mu *plat, struct imx_mu_con_priv *cp, const void *data); + int (*rx)(struct imx_mu *plat, struct imx_mu_con_priv *cp); + int (*rxdb)(struct imx_mu *plat, struct imx_mu_con_priv *cp); + int (*init)(struct imx_mu *plat); + int (*of_xlate)(struct mbox_chan *chan, struct ofnode_phandle_args *args); + enum imx_mu_type type; + u32 xTR; /* Transmit Register0 */ + u32 xRR; /* Receive Register0 */ + u32 xSR[IMX_MU_xSR_MAX]; /* Status Registers */ + u32 xCR[IMX_MU_xCR_MAX]; /* Control Registers */ +}; + +#define IMX_MU_xSR_GIPn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x)))) +#define IMX_MU_xSR_RFn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x)))) +#define IMX_MU_xSR_TEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x)))) + +/* General Purpose Interrupt Enable */ +#define IMX_MU_xCR_GIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x)))) +/* Receive Interrupt Enable */ +#define IMX_MU_xCR_RIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x)))) +/* Transmit Interrupt Enable */ +#define IMX_MU_xCR_TIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x)))) +/* General Purpose Interrupt Request */ +#define IMX_MU_xCR_GIRn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(16 + (3 - (x)))) +/* MU reset */ +#define IMX_MU_xCR_RST(type) (type & IMX_MU_V2 ? BIT(0) : BIT(5)) +#define IMX_MU_xSR_RST(type) (type & IMX_MU_V2 ? BIT(0) : BIT(7)) + +static void imx_mu_write(struct imx_mu *plat, u32 val, u32 offs) +{ + iowrite32(val, plat->base + offs); +} + +static u32 imx_mu_read(struct imx_mu *plat, u32 offs) +{ + return ioread32(plat->base + offs); +} + +static u32 imx_mu_xcr_rmw(struct imx_mu *plat, enum imx_mu_xcr type, u32 set, u32 clr) +{ + u32 val; + + val = imx_mu_read(plat, plat->dcfg->xCR[type]); + val &= ~clr; + val |= set; + imx_mu_write(plat, val, plat->dcfg->xCR[type]); + + return val; +} + +/* check that the channel is open or owned by caller */ +static int imx_mu_check_channel(struct mbox_chan *chan) +{ + struct imx_mu *plat = dev_get_plat(chan->dev); + + if (plat->channels[chan->id]) { + /* if reserved check that caller owns */ + if (plat->channels[chan->id] == chan) + return 1; /* caller owns the channel */ + + return -EACCES; + } + + return 0; /* channel empty */ +} + +static int imx_mu_chan_request(struct mbox_chan *chan) +{ + struct imx_mu *plat = dev_get_plat(chan->dev); + struct imx_mu_con_priv *cp; + enum imx_mu_chan_type type; + int idx; + + type = chan->id / 4; + idx = chan->id % 4; + + if (imx_mu_check_channel(chan) < 0) /* check if channel already in use */ + return -EPERM; + + plat->channels[chan->id] = chan; + chan->con_priv = kcalloc(1, sizeof(struct imx_mu_con_priv), 0); + if (!chan->con_priv) + return -ENOMEM; + cp = chan->con_priv; + cp->idx = idx; + cp->type = type; + cp->chan = chan; + + switch (type) { + case IMX_MU_TYPE_RX: + imx_mu_xcr_rmw(plat, IMX_MU_RCR, IMX_MU_xCR_RIEn(plat->dcfg->type, idx), 0); + break; + case IMX_MU_TYPE_TXDB_V2: + case IMX_MU_TYPE_TXDB: + case IMX_MU_TYPE_RXDB: + imx_mu_xcr_rmw(plat, IMX_MU_GIER, IMX_MU_xCR_GIEn(plat->dcfg->type, idx), 0); + break; + default: + break; + } + + return 0; +} + +static int imx_mu_chan_free(struct mbox_chan *chan) +{ + struct imx_mu *plat = dev_get_plat(chan->dev); + struct imx_mu_con_priv *cp = chan->con_priv; + + if (imx_mu_check_channel(chan) <= 0) /* check that the channel is also not empty */ + return -EINVAL; + + /* if you own channel and channel is NOT empty */ + plat->channels[chan->id] = NULL; + switch (cp->type) { + case IMX_MU_TYPE_TX: + imx_mu_xcr_rmw(plat, IMX_MU_TCR, 0, IMX_MU_xCR_TIEn(plat->dcfg->type, cp->idx)); + break; + case IMX_MU_TYPE_RX: + imx_mu_xcr_rmw(plat, IMX_MU_RCR, 0, IMX_MU_xCR_RIEn(plat->dcfg->type, cp->idx)); + break; + case IMX_MU_TYPE_TXDB_V2: + case IMX_MU_TYPE_TXDB: + case IMX_MU_TYPE_RXDB: + imx_mu_xcr_rmw(plat, IMX_MU_GIER, 0, IMX_MU_xCR_GIEn(plat->dcfg->type, cp->idx)); + break; + default: + break; + } + + kfree(cp); + + return 0; +} + +static int imx_mu_send(struct mbox_chan *chan, const void *data) +{ + struct imx_mu *plat = dev_get_plat(chan->dev); + struct imx_mu_con_priv *cp = chan->con_priv; + + if (imx_mu_check_channel(chan) < 1) /* return if channel isn't owned */ + return -EPERM; + + return plat->dcfg->tx(plat, cp, data); +} + +static int imx_mu_recv(struct mbox_chan *chan, void *data) +{ + struct imx_mu *plat = dev_get_plat(chan->dev); + struct imx_mu_con_priv *cp = chan->con_priv; + u32 ctrl, val; + + if (imx_mu_check_channel(chan) < 1) /* return if channel isn't owned */ + return -EPERM; + + switch (cp->type) { + case IMX_MU_TYPE_TXDB_V2: + case IMX_MU_TYPE_RXDB: + /* check if GSR[GIRn] bit is set */ + if (readx_poll_timeout(ioread32, plat->base + plat->dcfg->xSR[IMX_MU_GSR], + val, val & BIT(cp->idx), 1000000) < 0) + return -EBUSY; + + ctrl = imx_mu_read(plat, plat->dcfg->xCR[IMX_MU_GIER]); + val = imx_mu_read(plat, plat->dcfg->xSR[IMX_MU_GSR]); + val &= IMX_MU_xSR_GIPn(plat->dcfg->type, cp->idx) & + (ctrl & IMX_MU_xCR_GIEn(plat->dcfg->type, cp->idx)); + break; + default: + dev_warn(chan->dev, "Unhandled channel type %d\n", cp->type); + return -EOPNOTSUPP; + }; + + if (val == IMX_MU_xSR_GIPn(plat->dcfg->type, cp->idx)) + plat->dcfg->rxdb(plat, cp); + + return 0; +} + +static int imx_mu_of_to_plat(struct udevice *dev) +{ + struct imx_mu *plat = dev_get_plat(dev); + fdt_addr_t addr; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -ENODEV; + + plat->base = (struct mu_type *)addr; + + return 0; +} + +static int imx_mu_init_generic(struct imx_mu *plat) +{ + unsigned int i; + unsigned int val; + + if (plat->num_rr > 4 || plat->num_tr > 4) { + WARN_ONCE(true, "%s not support TR/RR larger than 4\n", __func__); + return -EOPNOTSUPP; + } + + /* Set default MU configuration */ + for (i = 0; i < IMX_MU_xCR_MAX; i++) + imx_mu_write(plat, 0, plat->dcfg->xCR[i]); + + /* Clear any pending GIP */ + val = imx_mu_read(plat, plat->dcfg->xSR[IMX_MU_GSR]); + imx_mu_write(plat, val, plat->dcfg->xSR[IMX_MU_GSR]); + + /* Clear any pending RSR */ + for (i = 0; i < plat->num_rr; i++) + imx_mu_read(plat, plat->dcfg->xRR + i * 4); + + return 0; +} + +static int imx_mu_generic_of_xlate(struct mbox_chan *chan, struct ofnode_phandle_args *args) +{ + enum imx_mu_chan_type type; + int idx, cid; + + if (args->args_count != 2) { + dev_err(chan->dev, "Invalid argument count %d\n", args->args_count); + return -EINVAL; + } + + type = args->args[0]; /* channel type */ + idx = args->args[1]; /* index */ + + cid = type * 4 + idx; + if (cid >= IMX_MU_CHANS) { + dev_err(chan->dev, "Not supported channel number: %d. (type: %d, idx: %d)\n", + cid, type, idx); + return -EINVAL; + } + + chan->id = cid; + + return 0; +} + +static int imx_mu_generic_tx(struct imx_mu *plat, struct imx_mu_con_priv *cp, + const void *data) +{ + switch (cp->type) { + case IMX_MU_TYPE_TXDB_V2: + imx_mu_xcr_rmw(plat, IMX_MU_GCR, IMX_MU_xCR_GIRn(plat->dcfg->type, cp->idx), 0); + break; + default: + dev_warn(cp->chan->dev, "Send data on wrong channel type: %d\n", cp->type); + return -EINVAL; + } + + return 0; +} + +static int imx_mu_generic_rxdb(struct imx_mu *plat, struct imx_mu_con_priv *cp) +{ + imx_mu_write(plat, IMX_MU_xSR_GIPn(plat->dcfg->type, cp->idx), + plat->dcfg->xSR[IMX_MU_GSR]); + + return 0; +} + +static const struct imx_mu_dcfg imx_mu_cfg_imx6sx = { + .tx = imx_mu_generic_tx, + .rxdb = imx_mu_generic_rxdb, + .init = imx_mu_init_generic, + .of_xlate = imx_mu_generic_of_xlate, + .type = IMX_MU_V1, + .xTR = 0x0, + .xRR = 0x10, + .xSR = {0x20, 0x20, 0x20, 0x20}, + .xCR = {0x24, 0x24, 0x24, 0x24, 0x24}, +}; + +static const struct imx_mu_dcfg imx_mu_cfg_imx7ulp = { + .tx = imx_mu_generic_tx, + .rxdb = imx_mu_generic_rxdb, + .init = imx_mu_init_generic, + .of_xlate = imx_mu_generic_of_xlate, + .type = IMX_MU_V1, + .xTR = 0x20, + .xRR = 0x40, + .xSR = {0x60, 0x60, 0x60, 0x60}, + .xCR = {0x64, 0x64, 0x64, 0x64, 0x64}, +}; + +static const struct imx_mu_dcfg imx_mu_cfg_imx95 = { + .tx = imx_mu_generic_tx, + .rxdb = imx_mu_generic_rxdb, + .init = imx_mu_init_generic, + .of_xlate = imx_mu_generic_of_xlate, + .type = IMX_MU_V2, + .xTR = 0x200, + .xRR = 0x280, + .xSR = {0xC, 0x118, 0x124, 0x12C}, + .xCR = {0x8, 0x110, 0x114, 0x120, 0x128}, +}; + +static const struct udevice_id ids[] = { + { .compatible = "fsl,imx6sx-mu", .data = (ulong)&imx_mu_cfg_imx6sx }, + { .compatible = "fsl,imx7ulp-mu", .data = (ulong)&imx_mu_cfg_imx7ulp }, + { .compatible = "fsl,imx95-mu", .data = (ulong)&imx_mu_cfg_imx95 }, + { } +}; + +int imx_mu_of_xlate(struct mbox_chan *chan, struct ofnode_phandle_args *args) +{ + struct imx_mu *plat = dev_get_plat(chan->dev); + + return plat->dcfg->of_xlate(chan, args); +} + +struct mbox_ops imx_mu_ops = { + .of_xlate = imx_mu_of_xlate, + .request = imx_mu_chan_request, + .rfree = imx_mu_chan_free, + .send = imx_mu_send, + .recv = imx_mu_recv, +}; + +static void imx_mu_get_tr_rr(struct imx_mu *plat) +{ + u32 val; + + if (plat->dcfg->type & IMX_MU_V2) { + val = imx_mu_read(plat, IMX_MU_V2_PAR_OFF); + plat->num_tr = FIELD_GET(IMX_MU_V2_TR_MASK, val); + plat->num_rr = FIELD_GET(IMX_MU_V2_RR_MASK, val); + } else { + plat->num_tr = 4; + plat->num_rr = 4; + } +} + +static int imx_mu_probe(struct udevice *dev) +{ + struct imx_mu *plat = dev_get_plat(dev); + int ret; + + debug("%s(dev=%p)\n", __func__, dev); + + plat->dcfg = (void *)dev_get_driver_data(dev); + + imx_mu_get_tr_rr(plat); + + ret = plat->dcfg->init(plat); + if (ret) { + dev_err(dev, "Failed to init MU\n"); + return ret; + } + + return 0; +} + +U_BOOT_DRIVER(imx_mu) = { + .name = "imx-mu", + .id = UCLASS_MAILBOX, + .of_match = ids, + .of_to_plat = imx_mu_of_to_plat, + .plat_auto = sizeof(struct imx_mu), + .probe = imx_mu_probe, + .ops = &imx_mu_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index ab56bd3939f..6740591a653 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -928,6 +928,12 @@ config ESDHC_DETECT_QUIRK bool "QIXIS-based eSDHC quirk detection" depends on FSL_ESDHC && FSL_QIXIS +config ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE + bool + depends on FSL_ESDHC || FSL_ESDHC_IMX + def_bool y if ARCH_T1024 || ARCH_T1040 || ARCH_T1042 || ARCH_T2080 \ + || FSL_ESDHC_IMX + config FSL_ESDHC_IMX bool "Freescale/NXP i.MX eSDHC controller support" help diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index d7a45ef0ad0..926113f79d3 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -40,12 +40,6 @@ #include <linux/iopoll.h> #include <linux/dma-mapping.h> -#ifndef ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE -#ifdef CONFIG_FSL_USDHC -#define ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE 1 -#endif -#endif - DECLARE_GLOBAL_DATA_PTR; #define SDHCI_IRQ_EN_BITS (IRQSTATEN_CC | IRQSTATEN_TC | \ @@ -376,7 +370,7 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, (timeout == 4 || timeout == 8 || timeout == 12)) timeout++; - if (IS_ENABLED(ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE)) + if (IS_ENABLED(CONFIG_ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE)) timeout = 0xE; esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); diff --git a/include/configs/imxrt1020-evk.h b/include/configs/imxrt1020-evk.h index cd6af93454b..aec12082b95 100644 --- a/include/configs/imxrt1020-evk.h +++ b/include/configs/imxrt1020-evk.h @@ -9,8 +9,6 @@ #include <asm/arch/imx-regs.h> -#define ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE 1 - #define PHYS_SDRAM 0x80000000 #define PHYS_SDRAM_SIZE (32 * 1024 * 1024) diff --git a/include/configs/imxrt1050-evk.h b/include/configs/imxrt1050-evk.h index c520c2fc203..5b8d6a7ac05 100644 --- a/include/configs/imxrt1050-evk.h +++ b/include/configs/imxrt1050-evk.h @@ -9,8 +9,6 @@ #include <asm/arch/imx-regs.h> -#define ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE 1 - #define PHYS_SDRAM 0x80000000 #define PHYS_SDRAM_SIZE (32 * 1024 * 1024) diff --git a/include/configs/imxrt1170-evk.h b/include/configs/imxrt1170-evk.h index 1ccaa15bc11..f821212765c 100644 --- a/include/configs/imxrt1170-evk.h +++ b/include/configs/imxrt1170-evk.h @@ -10,8 +10,6 @@ #include <asm/arch/imx-regs.h> -#define ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE 1 - /* * Configuration of the external SDRAM memory */ |