diff options
| author | Tom Rini <[email protected]> | 2025-12-19 10:30:26 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2025-12-19 10:30:26 -0600 |
| commit | adbbf5982d26801224b10cd847dc468f8b5e4095 (patch) | |
| tree | edb0eb14bfb2b16e7b92141a64f0d122259eb660 /drivers | |
| parent | 930eff5416ea98ebd09cec73f5d06a7033b4d52e (diff) | |
| parent | 6e844dd4df6765e5e772b5606a675c16fe98d9ac (diff) | |
Merge tag 'u-boot-amlogic-next-20251219' of https://source.denx.de/u-boot/custodians/u-boot-amlogic into next
- Add u-boot SPL support for GX SoCs
- meson_gx_mmc: reduce maximum frequency
- Add support for EFI capsule updates on all Amlogic boards
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/mmc/meson_gx_mmc.c | 79 | ||||
| -rw-r--r-- | drivers/serial/serial.c | 2 | ||||
| -rw-r--r-- | drivers/serial/serial_meson.c | 119 |
3 files changed, 198 insertions, 2 deletions
diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c index 5852b24c6d2..76af3873e15 100644 --- a/drivers/mmc/meson_gx_mmc.c +++ b/drivers/mmc/meson_gx_mmc.c @@ -16,6 +16,7 @@ #include <linux/log2.h> #include "meson_gx_mmc.h" +#if CONFIG_IS_ENABLED(DM_MMC) bool meson_gx_mmc_is_compatible(struct udevice *dev, enum meson_gx_mmc_compatible family) { @@ -23,6 +24,7 @@ bool meson_gx_mmc_is_compatible(struct udevice *dev, return compat == family; } +#endif static inline void *get_regbase(const struct mmc *mmc) { @@ -67,10 +69,14 @@ static void meson_mmc_config_clock(struct mmc *mmc) * Other SoCs use CLK_CO_PHASE_180 by default. * It needs to find what is a proper value about each SoCs. */ +#if CONFIG_IS_ENABLED(DM_MMC) if (meson_gx_mmc_is_compatible(mmc->dev, MMC_COMPATIBLE_SM1)) meson_mmc_clk |= CLK_CO_PHASE_270; else meson_mmc_clk |= CLK_CO_PHASE_180; +#else /* U-Boot SPL on GX SoCs */ + meson_mmc_clk |= CLK_CO_PHASE_180; +#endif /* 180 phase tx clock */ meson_mmc_clk |= CLK_TX_PHASE_000; @@ -82,9 +88,14 @@ static void meson_mmc_config_clock(struct mmc *mmc) meson_write(mmc, meson_mmc_clk, MESON_SD_EMMC_CLOCK); } +#if CONFIG_IS_ENABLED(DM_MMC) static int meson_dm_mmc_set_ios(struct udevice *dev) { struct mmc *mmc = mmc_get_mmc_dev(dev); +#else /* U-Boot SPL */ +static int meson_legacy_mmc_set_ios(struct mmc *mmc) +{ +#endif uint32_t meson_mmc_cfg; meson_mmc_config_clock(mmc); @@ -193,10 +204,16 @@ static void meson_mmc_read_response(struct mmc *mmc, struct mmc_cmd *cmd) } } +#if CONFIG_IS_ENABLED(DM_MMC) static int meson_dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { struct mmc *mmc = mmc_get_mmc_dev(dev); +#else /* U-Boot SPL */ +static int meson_legacy_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, + struct mmc_data *data) +{ +#endif struct meson_mmc_plat *pdata = mmc->priv; uint32_t status; ulong start; @@ -235,6 +252,59 @@ static int meson_dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, return ret; } +#if !CONFIG_IS_ENABLED(DM_MMC) /* Non-DM MMC driver for use in U-Boot SPL */ +struct meson_mmc_plat mmc_plat[2]; + +static int meson_legacy_mmc_init(struct mmc *mmc) +{ + /* reset all status bits */ + meson_write(mmc, STATUS_MASK, MESON_SD_EMMC_STATUS); + + /* disable interrupts */ + meson_write(mmc, 0, MESON_SD_EMMC_IRQ_EN); + + return 0; +} + +static const struct mmc_ops meson_mmc_ops = { + .send_cmd = meson_legacy_mmc_send_cmd, + .set_ios = meson_legacy_mmc_set_ios, + .init = meson_legacy_mmc_init, +}; + +struct mmc *meson_mmc_init(int mmc_no) +{ + struct meson_mmc_plat *pdata = &mmc_plat[mmc_no]; + struct mmc_config *cfg = &pdata->cfg; + + cfg->voltages = MMC_VDD_33_34 | MMC_VDD_32_33 | + MMC_VDD_31_32 | MMC_VDD_165_195; + cfg->host_caps = MMC_MODE_8BIT | MMC_MODE_4BIT; + cfg->f_min = DIV_ROUND_UP(SD_EMMC_CLKSRC_24M, CLK_MAX_DIV); + cfg->f_max = 6000000; /* 6 MHz */ + cfg->b_max = 127; /* max 128 - 1 block */ + cfg->name = "Meson SD/eMMC"; + cfg->ops = &meson_mmc_ops; + + if (mmc_no == 0) /* MMC1: SD card */ + pdata->regbase = (void *)0xd0072000; + else if (mmc_no == 1) /* MMC2: eMMC */ + pdata->regbase = (void *)0xd0074000; + +#if CONFIG_IS_ENABLED(MMC_PWRSEQ) + /* Enable power if needed */ + ret = mmc_pwrseq_get_power(dev, cfg); + if (!ret) { + ret = pwrseq_set_power(cfg->pwr_dev, true); + if (ret) + return ret; + } +#endif + + return mmc_create(cfg, pdata); +} + +#else /* DM-based driver for use in U-Boot proper */ static const struct dm_mmc_ops meson_dm_mmc_ops = { .send_cmd = meson_dm_mmc_send_cmd, .set_ios = meson_dm_mmc_set_ios, @@ -278,10 +348,16 @@ static int meson_mmc_probe(struct udevice *dev) cfg->host_caps = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS; cfg->f_min = DIV_ROUND_UP(SD_EMMC_CLKSRC_24M, CLK_MAX_DIV); - cfg->f_max = 100000000; /* 100 MHz */ + cfg->f_max = 40000000; /* 40 MHz */ cfg->b_max = 511; /* max 512 - 1 blocks */ cfg->name = dev->name; + if (IS_ENABLED(CONFIG_SPL_BUILD)) { + cfg->host_caps &= ~(MMC_MODE_HS_52MHz | MMC_MODE_HS); + cfg->f_max = 6000000; /* 6 MHz */ + cfg->b_max = 127; /* max 128 - 1 block */ + } + mmc->priv = pdata; upriv->mmc = mmc; @@ -336,3 +412,4 @@ U_BOOT_DRIVER(meson_mmc) = { .of_to_plat = meson_mmc_of_to_plat, .plat_auto = sizeof(struct meson_mmc_plat), }; +#endif /* CONFIG_IS_ENABLED(DM_MMC) */ diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index e10ca6eef76..c0b1eb30561 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -129,6 +129,7 @@ serial_initfunc(pxa_serial_initialize); serial_initfunc(smh_serial_initialize); serial_initfunc(sh_serial_initialize); serial_initfunc(mtk_serial_initialize); +serial_initfunc(meson_serial_initialize); /** * serial_register() - Register serial driver with serial driver core @@ -167,6 +168,7 @@ int serial_initialize(void) smh_serial_initialize(); sh_serial_initialize(); mtk_serial_initialize(); + meson_serial_initialize(); serial_assign(default_serial_console()->name); diff --git a/drivers/serial/serial_meson.c b/drivers/serial/serial_meson.c index bb79b972957..cc71381f87e 100644 --- a/drivers/serial/serial_meson.c +++ b/drivers/serial/serial_meson.c @@ -3,9 +3,11 @@ * (C) Copyright 2016 Beniamino Galvani <[email protected]> */ +#if CONFIG_IS_ENABLED(DM_SERIAL) #include <dm.h> -#include <errno.h> #include <fdtdec.h> +#endif +#include <errno.h> #include <linux/kernel.h> #include <linux/bitops.h> #include <linux/compiler.h> @@ -25,6 +27,15 @@ struct meson_serial_plat { struct meson_uart *reg; }; +#if !CONFIG_IS_ENABLED(DM_SERIAL) +/* UART base address */ +#if defined(CONFIG_MESON_GX) +#define AML_UART_BASE 0xc81004c0 +#else /* G12A, AXG, ... */ +#define AML_UART_BASE 0xff803000 +#endif +#endif + /* AML_UART_STATUS bits */ #define AML_UART_PARITY_ERR BIT(16) #define AML_UART_FRAME_ERR BIT(17) @@ -51,6 +62,7 @@ struct meson_serial_plat { #define AML_UART_REG5_USE_NEW_BAUD BIT(23) /* default 1 (use new baud rate register) */ #define AML_UART_REG5_BAUD_MASK 0x7fffff +#if CONFIG_IS_ENABLED(DM_SERIAL) static u32 meson_calc_baud_divisor(ulong src_rate, u32 baud) { /* @@ -245,6 +257,111 @@ U_BOOT_DRIVER(serial_meson) = { .plat_auto = sizeof(struct meson_serial_plat), }; +#else + +static int meson_serial_init(void) +{ + struct meson_uart *const uart = (struct meson_uart *)AML_UART_BASE; + u32 val; + + val = readl(&uart->control); + val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR); + writel(val, &uart->control); + val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR); + writel(val, &uart->control); + val |= (AML_UART_RX_EN | AML_UART_TX_EN); + writel(val, &uart->control); + + return 0; +} + +static int meson_serial_stop(void) +{ + return 0; +} + +static void meson_serial_setbrg(void) +{ +} + +static void meson_serial_putc(const char ch) +{ + struct meson_uart *uart = (struct meson_uart *)AML_UART_BASE; + + /* On '\n' also do '\r' */ + if (ch == '\n') + meson_serial_putc('\r'); + + while (readl(&uart->status) & AML_UART_TX_FULL) + ; + + writel(ch, &uart->wfifo); +} + +static void meson_serial_puts(const char *s) +{ + while (*s) + meson_serial_putc(*s++); +} + +static int meson_serial_getc(void) +{ + struct meson_uart *const uart = (struct meson_uart *)AML_UART_BASE; + uint32_t status = readl(&uart->status); + + if (status & AML_UART_RX_EMPTY) + return -EAGAIN; + + if (status & AML_UART_ERR) { + u32 val = readl(&uart->control); + + /* Clear error */ + val |= AML_UART_CLR_ERR; + writel(val, &uart->control); + val &= ~AML_UART_CLR_ERR; + writel(val, &uart->control); + + /* Remove spurious byte from fifo */ + readl(&uart->rfifo); + return -EIO; + } + + return readl(&uart->rfifo) & 0xff; +} + +static int meson_serial_tstc(void) +{ + struct meson_uart *const uart = (struct meson_uart *)AML_UART_BASE; + uint32_t status = readl(&uart->status); + + if (status & AML_UART_RX_EMPTY) + return 0; + return 1; +} + +struct serial_device meson_serial_device = { + .name = "meson_serial", + .start = meson_serial_init, + .stop = meson_serial_stop, + .setbrg = meson_serial_setbrg, + .getc = meson_serial_getc, + .tstc = meson_serial_tstc, + .putc = meson_serial_putc, + .puts = meson_serial_puts, +}; + +void meson_serial_initialize(void) +{ + serial_register(&meson_serial_device); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &meson_serial_device; +} + +#endif + #ifdef CONFIG_DEBUG_UART_MESON #include <debug_uart.h> |
