summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2025-12-19 10:30:26 -0600
committerTom Rini <[email protected]>2025-12-19 10:30:26 -0600
commitadbbf5982d26801224b10cd847dc468f8b5e4095 (patch)
treeedb0eb14bfb2b16e7b92141a64f0d122259eb660 /drivers
parent930eff5416ea98ebd09cec73f5d06a7033b4d52e (diff)
parent6e844dd4df6765e5e772b5606a675c16fe98d9ac (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.c79
-rw-r--r--drivers/serial/serial.c2
-rw-r--r--drivers/serial/serial_meson.c119
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>