* [PATCH 1/9] clocksource: make available in PBL
2025-04-22 5:26 [PATCH 0/9] ARM: OMAP: beaglebone: add PBL SD xload support Ahmad Fatoum
@ 2025-04-22 5:26 ` Ahmad Fatoum
2025-04-22 5:26 ` [PATCH 2/9] clocksource: ti-dm: " Ahmad Fatoum
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2025-04-22 5:26 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We currently have some adhoc early_udelay implementations in PBL.
As the clocksource framework is already very lightweight, let's port it
to allow dropping early_udelay in future.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
common/Makefile | 1 +
common/clock.c | 5 ++++-
include/sched.h | 2 +-
pbl/Kconfig | 3 +++
4 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/common/Makefile b/common/Makefile
index 9b67187561bf..e12eef4691fe 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -5,6 +5,7 @@ obj-y += memory.o
obj-y += memory_display.o
pbl-$(CONFIG_PBL_CONSOLE) += memory_display.o
obj-y += clock.o
+pbl-$(CONFIG_PBL_CLOCKSOURCE) += clock.o
obj-y += console_common.o
obj-$(CONFIG_OFDEVICE) += deep-probe.o
obj-y += startup.o
diff --git a/common/clock.c b/common/clock.c
index b300e5798a16..15e26c67c887 100644
--- a/common/clock.c
+++ b/common/clock.c
@@ -34,7 +34,7 @@ static struct clocksource dummy_cs = {
.priority = -1,
};
-static struct clocksource *current_clock = &dummy_cs;
+static struct clocksource *current_clock = IN_PROPER ? &dummy_cs : NULL;
static int dummy_csrc_warn(void)
{
@@ -55,6 +55,9 @@ uint64_t get_time_ns(void)
uint64_t cycle_now, cycle_delta;
uint64_t ns_offset;
+ if (IN_PBL && !cs)
+ panic("No PBL clocksource has been initialized\n");
+
/* read clocksource: */
cycle_now = cs->read() & cs->mask;
diff --git a/include/sched.h b/include/sched.h
index 4dadff20696e..0b5e91f0be44 100644
--- a/include/sched.h
+++ b/include/sched.h
@@ -2,7 +2,7 @@
#ifndef __BAREBOX_SCHED_H_
#define __BAREBOX_SCHED_H_
-#ifdef CONFIG_HAS_SCHED
+#if defined CONFIG_HAS_SCHED && IN_PROPER
void resched(void);
#else
static inline void resched(void)
diff --git a/pbl/Kconfig b/pbl/Kconfig
index 98d71791454b..6e3581829d58 100644
--- a/pbl/Kconfig
+++ b/pbl/Kconfig
@@ -57,6 +57,9 @@ config PBL_VERIFY_PIGGY
depends on ARM || MIPS || RISCV
bool "Verify barebox proper hash before decompression" if COMPILE_TEST
+config PBL_CLOCKSOURCE
+ bool
+
config BOARD_GENERIC_DT
bool
select LIBFDT
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 2/9] clocksource: ti-dm: make available in PBL
2025-04-22 5:26 [PATCH 0/9] ARM: OMAP: beaglebone: add PBL SD xload support Ahmad Fatoum
2025-04-22 5:26 ` [PATCH 1/9] clocksource: make available in PBL Ahmad Fatoum
@ 2025-04-22 5:26 ` Ahmad Fatoum
2025-04-22 5:26 ` [PATCH 3/9] mci: move mci_setup_cmd definition into header Ahmad Fatoum
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2025-04-22 5:26 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Now that there's clocksource framework support in PBL, let's make
available the first clocksource driver for use by OMAP HSMMC.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/mach-omap/Kconfig | 1 +
drivers/clocksource/Makefile | 2 +-
drivers/clocksource/timer-ti-dm.c | 19 +++++++++++++------
include/mach/omap/am33xx-clock.h | 3 +++
4 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
index 6c4e9d748d61..e7a9b331125d 100644
--- a/arch/arm/mach-omap/Kconfig
+++ b/arch/arm/mach-omap/Kconfig
@@ -40,6 +40,7 @@ config ARCH_AM33XX
select CPU_V7
select GENERIC_GPIO
select CLOCKSOURCE_TI_DM
+ select PBL_CLOCKSOURCE
help
Say Y here if you are using Texas Instrument's AM33xx based platform
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index eceaa990d43d..dff825565072 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -20,7 +20,7 @@ endif
obj-$(CONFIG_CLOCKSOURCE_ARM_GLOBAL_TIMER) += arm_global_timer.o
obj-$(CONFIG_CLOCKSOURCE_IMX_GPT) += timer-imx-gpt.o
obj-$(CONFIG_CLOCKSOURCE_DW_APB_TIMER) += dw_apb_timer.o
-obj-$(CONFIG_CLOCKSOURCE_TI_DM) += timer-ti-dm.o
+obj-pbl-$(CONFIG_CLOCKSOURCE_TI_DM) += timer-ti-dm.o
obj-$(CONFIG_CLOCKSOURCE_TI_32K) += timer-ti-32k.o
obj-$(CONFIG_CLINT_TIMER) += timer-clint.o
obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o
diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c
index eb658402f58d..1090b96a0e94 100644
--- a/drivers/clocksource/timer-ti-dm.c
+++ b/drivers/clocksource/timer-ti-dm.c
@@ -69,6 +69,18 @@ struct omap_dmtimer_data {
int (*get_clock)(struct device *dev);
};
+int omap_dmtimer_init(void __iomem *mmio_start, unsigned clk_speed)
+{
+ base = mmio_start;
+
+ dmtimer_cs.mult = clocksource_hz2mult(clk_speed, dmtimer_cs.shift);
+
+ /* Enable counter */
+ writel(0x3, base + TCLR);
+
+ return init_clock(&dmtimer_cs);
+}
+
static int omap_dmtimer_probe(struct device *dev)
{
struct resource *iores;
@@ -90,12 +102,7 @@ static int omap_dmtimer_probe(struct device *dev)
if (clk_speed < 0)
return clk_speed;
- dmtimer_cs.mult = clocksource_hz2mult(clk_speed, dmtimer_cs.shift);
-
- /* Enable counter */
- writel(0x3, base + TCLR);
-
- return init_clock(&dmtimer_cs);
+ return omap_dmtimer_init(IOMEM(iores->start), clk_speed);
}
static int am335x_get_clock(struct device *dev)
diff --git a/include/mach/omap/am33xx-clock.h b/include/mach/omap/am33xx-clock.h
index af47a0f3e77a..b064337ac4f8 100644
--- a/include/mach/omap/am33xx-clock.h
+++ b/include/mach/omap/am33xx-clock.h
@@ -191,4 +191,7 @@ void am33xx_pll_init(int mpupll_M, int ddrpll_M);
void am33xx_enable_ddr_clocks(void);
int am33xx_get_osc_clock(void);
+int omap_dmtimer_init(void __iomem *mmio_start,
+ unsigned clk_speed);
+
#endif /* endif _AM33XX_CLOCKS_H_ */
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 3/9] mci: move mci_setup_cmd definition into header
2025-04-22 5:26 [PATCH 0/9] ARM: OMAP: beaglebone: add PBL SD xload support Ahmad Fatoum
2025-04-22 5:26 ` [PATCH 1/9] clocksource: make available in PBL Ahmad Fatoum
2025-04-22 5:26 ` [PATCH 2/9] clocksource: ti-dm: " Ahmad Fatoum
@ 2025-04-22 5:26 ` Ahmad Fatoum
2025-04-22 5:26 ` [PATCH 4/9] mci: add common PBL helper for chainloading after BootROM initialization Ahmad Fatoum
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2025-04-22 5:26 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
For use outside of mci-core, e.g. in PBL drivers, move the helper
function into the header.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/mci-core.c | 15 ---------------
include/mci.h | 16 ++++++++++++++++
2 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 5ab07d09c546..9a8e1ce656b5 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -97,21 +97,6 @@ static int mci_send_cmd_retry(struct mci *mci, struct mci_cmd *cmd,
return ret;
}
-/**
- * @param p Command definition to setup
- * @param cmd Valid SD/MMC command (refer MMC_CMD_* / SD_CMD_*)
- * @param arg Argument for the command (optional)
- * @param response Command's response type (refer MMC_RSP_*)
- *
- * Note: When calling, the 'response' must match command's requirements
- */
-static void mci_setup_cmd(struct mci_cmd *p, unsigned cmd, unsigned arg, unsigned response)
-{
- p->cmdidx = cmd;
- p->cmdarg = arg;
- p->resp_type = response;
-}
-
/**
* configure optional DSR value
* @param mci_dev MCI instance
diff --git a/include/mci.h b/include/mci.h
index 43a0b0131572..10bba878a8f9 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -480,6 +480,22 @@ struct mci_cmd {
unsigned response[4]; /**< card's response */
};
+/**
+ * @param p Command definition to setup
+ * @param cmd Valid SD/MMC command (refer MMC_CMD_* / SD_CMD_*)
+ * @param arg Argument for the command (optional)
+ * @param response Command's response type (refer MMC_RSP_*)
+ *
+ * Note: When calling, the 'response' must match command's requirements
+ */
+static inline void mci_setup_cmd(struct mci_cmd *p, unsigned cmd,
+ unsigned arg, unsigned response)
+{
+ p->cmdidx = cmd;
+ p->cmdarg = arg;
+ p->resp_type = response;
+}
+
/** data information to be used with some SD/MMC commands */
struct mci_data {
union {
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 4/9] mci: add common PBL helper for chainloading after BootROM initialization
2025-04-22 5:26 [PATCH 0/9] ARM: OMAP: beaglebone: add PBL SD xload support Ahmad Fatoum
` (2 preceding siblings ...)
2025-04-22 5:26 ` [PATCH 3/9] mci: move mci_setup_cmd definition into header Ahmad Fatoum
@ 2025-04-22 5:26 ` Ahmad Fatoum
2025-04-22 5:26 ` [PATCH 5/9] mci: pbl: add autodetection of BootROM-initialized standard capacity cards Ahmad Fatoum
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2025-04-22 5:26 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We have a number of PBL drivers that communicate directly with a
SD-Card or eMMC already initialized by the BootROM and put into
transfer state. This lets us skip having a stripped down MMC framework
in the prebootloader.
Instead of duplicating this code across drivers, let's put the duplicate
code into a common location.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/Makefile | 1 +
drivers/mci/mci-pbl.c | 110 ++++++++++++++++++++++++++++++++++++++++++
include/pbl/mci.h | 37 ++++++++++++++
3 files changed, 148 insertions(+)
create mode 100644 drivers/mci/mci-pbl.c
create mode 100644 include/pbl/mci.h
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index d3df4c1bb650..8f54107e46c1 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_MCI) += mci-core.o
+pbl-$(CONFIG_MCI) += mci-pbl.o
obj-$(CONFIG_MCI_MMC_RPMB) += rpmb.o
obj-$(CONFIG_MCI_AM654) += am654-sdhci.o
obj-$(CONFIG_MCI_ARASAN) += arasan-sdhci.o
diff --git a/drivers/mci/mci-pbl.c b/drivers/mci/mci-pbl.c
new file mode 100644
index 000000000000..b58cd8dafe84
--- /dev/null
+++ b/drivers/mci/mci-pbl.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * This code assumes that the SD/eMMC is already in transfer mode,
+ * because it card initialization has been done by the BootROM.
+ *
+ * In interest of reducing complexity, code size and boot time, we
+ * don't want to reset the card, but reuse it as-is.
+ *
+ * Full reinitialization of the card has to wait until we are
+ * in barebox proper (see mci-core.c).
+ */
+
+#define pr_fmt(fmt) "mci-pbl: " fmt
+
+#include <mci.h>
+#include <pbl/mci.h>
+#include <pbl/bio.h>
+#include <linux/minmax.h>
+#include <linux/bug.h>
+
+#define MCI_PBL_BLOCK_LEN 512
+
+static int pbl_mci_read_blocks(struct pbl_mci *mci, void *dst,
+ off_t start, unsigned int nblocks)
+{
+ struct mci_cmd cmd = {};
+ struct mci_data data;
+ int ret;
+
+ if (mci->capacity == PBL_MCI_STANDARD_CAPACITY)
+ start *= MCI_PBL_BLOCK_LEN;
+
+ mci_setup_cmd(&cmd, MMC_CMD_READ_SINGLE_BLOCK,
+ start, MMC_RSP_R1);
+ if (nblocks > 1)
+ cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
+
+ data.dest = dst;
+ data.flags = MMC_DATA_READ;
+ data.blocksize = MCI_PBL_BLOCK_LEN;
+ data.blocks = nblocks;
+
+ ret = pbl_mci_send_cmd(mci, &cmd, &data);
+ if (ret || nblocks > 1) {
+ mci_setup_cmd(&cmd, MMC_CMD_STOP_TRANSMISSION, 0,
+ MMC_RSP_R1b);
+ pbl_mci_send_cmd(mci, &cmd, NULL);
+ }
+
+ return ret;
+}
+
+static int pbl_bio_mci_read(struct pbl_bio *bio, off_t start,
+ void *buf, unsigned int nblocks)
+{
+ struct pbl_mci *mci = bio->priv;
+ unsigned int count = 0;
+ unsigned int block_len = MCI_PBL_BLOCK_LEN;
+ int ret;
+
+ while (count < nblocks) {
+ unsigned n = nblocks - count;
+
+ if (mci->max_blocks_per_read)
+ n = min(n, mci->max_blocks_per_read);
+
+ ret = pbl_mci_read_blocks(mci, buf, start, n);
+ if (ret < 0)
+ return ret;
+
+ count += n;
+ start += n;
+ buf += n *block_len;
+ }
+
+ return count;
+}
+
+static const char *capacity_tostr(enum pbl_mci_capacity capacity)
+{
+ switch (capacity) {
+ case PBL_MCI_STANDARD_CAPACITY:
+ return "standard";
+ case PBL_MCI_HIGH_CAPACITY:
+ return "high/extended";
+ case PBL_MCI_ULTRA_CAPACITY:
+ return "ultra";
+ case PBL_MCI_RESERVED_CAPACITY:
+ return "reserved";
+ case PBL_MCI_UNKNOWN_CAPACITY:
+ break;
+ }
+
+ return "unknown";
+}
+
+int pbl_mci_bio_init(struct pbl_mci *mci, struct pbl_bio *bio)
+{
+
+ if (mci->capacity == PBL_MCI_UNKNOWN_CAPACITY)
+ BUG();
+ else
+ pr_debug("assuming %s capacity card\n",
+ capacity_tostr(mci->capacity));
+
+ bio->priv = mci;
+ bio->read = pbl_bio_mci_read;
+
+ return 0;
+}
diff --git a/include/pbl/mci.h b/include/pbl/mci.h
new file mode 100644
index 000000000000..dd4fcac5412b
--- /dev/null
+++ b/include/pbl/mci.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __PBL_MCI_H__
+#define __PBL_MCI_H__
+
+#include <linux/types.h>
+#include <mci.h>
+
+struct mci_cmd;
+struct mci_data;
+struct pbl_bio;
+
+enum pbl_mci_capacity {
+ PBL_MCI_UNKNOWN_CAPACITY,
+ PBL_MCI_STANDARD_CAPACITY,
+ PBL_MCI_HIGH_CAPACITY, /* and extended */
+ PBL_MCI_ULTRA_CAPACITY,
+ PBL_MCI_RESERVED_CAPACITY,
+};
+
+struct pbl_mci {
+ void *priv;
+ enum pbl_mci_capacity capacity;
+ unsigned max_blocks_per_read;
+ int (*send_cmd)(struct pbl_mci *mci, struct mci_cmd *cmd,
+ struct mci_data *data);
+};
+
+static inline int pbl_mci_send_cmd(struct pbl_mci *mci,
+ struct mci_cmd *cmd,
+ struct mci_data *data)
+{
+ return mci->send_cmd(mci, cmd, data);
+}
+
+int pbl_mci_bio_init(struct pbl_mci *mci, struct pbl_bio *bio);
+
+#endif /* __PBL_MCI_H__ */
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 5/9] mci: pbl: add autodetection of BootROM-initialized standard capacity cards
2025-04-22 5:26 [PATCH 0/9] ARM: OMAP: beaglebone: add PBL SD xload support Ahmad Fatoum
` (3 preceding siblings ...)
2025-04-22 5:26 ` [PATCH 4/9] mci: add common PBL helper for chainloading after BootROM initialization Ahmad Fatoum
@ 2025-04-22 5:26 ` Ahmad Fatoum
2025-04-22 5:26 ` [PATCH 6/9] mci: omap_hsmmc: split out common code Ahmad Fatoum
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2025-04-22 5:26 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We more or less manage without driver model in PBL, because we reuse
hardware setup done by the BootROM.
In case of SD/eMMC cards, this presents one annoying problem: A card in
transfer state can't be asked whether it's standard or high capacity,
but we require this information to know whether we need to use a byte or
a block offset for the READ_MULTIPLE_BLOCK command.
We had a number of workaround for that:
- On i.MX, the bootloader is located raw near the start of the SD/MMC,
so we just read from offset 0 onwards and then jump to the correct
location
- On AT91SAM9, the BootROM supports only standard capacity SD-Cards,
so we hardcode that
- On older platforms, we have a separate configuration for the
first stage that can use the normal mci-core and reinitialized
the card with the downside of needing two builds.
- On everything else, we assume that we have a high capacity card.
Fortunately, at the modest cost of 4 commands, we can get out
of transmission mode, ask the card for its capacity and back,
so let's do that.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/mci-pbl.c | 108 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 105 insertions(+), 3 deletions(-)
diff --git a/drivers/mci/mci-pbl.c b/drivers/mci/mci-pbl.c
index b58cd8dafe84..610002b3d022 100644
--- a/drivers/mci/mci-pbl.c
+++ b/drivers/mci/mci-pbl.c
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2025 Ahmad Fatoum
/*
* This code assumes that the SD/eMMC is already in transfer mode,
* because it card initialization has been done by the BootROM.
@@ -16,7 +17,6 @@
#include <pbl/mci.h>
#include <pbl/bio.h>
#include <linux/minmax.h>
-#include <linux/bug.h>
#define MCI_PBL_BLOCK_LEN 512
@@ -76,6 +76,22 @@ static int pbl_bio_mci_read(struct pbl_bio *bio, off_t start,
return count;
}
+static enum pbl_mci_capacity capacity_decode(unsigned csd_struct_ver)
+{
+ switch (csd_struct_ver) {
+ case 0:
+ return PBL_MCI_STANDARD_CAPACITY;
+ case 1:
+ return PBL_MCI_HIGH_CAPACITY;
+ case 2:
+ return PBL_MCI_ULTRA_CAPACITY;
+ case 3:
+ return PBL_MCI_RESERVED_CAPACITY;
+ }
+
+ return PBL_MCI_UNKNOWN_CAPACITY;
+}
+
static const char *capacity_tostr(enum pbl_mci_capacity capacity)
{
switch (capacity) {
@@ -94,11 +110,97 @@ static const char *capacity_tostr(enum pbl_mci_capacity capacity)
return "unknown";
}
+/**
+ * pbl_mci_check_high_capacity() - Determine what type of card we have
+ * @mci: already initialized MCI card
+ *
+ * Standard capacity cards use a byte offset for the READ_MULTIPLE_BLOCK
+ * command argument, which high capacity uses a block offset.
+ *
+ * As we haven't set up the card ourselves here, we do not have
+ * this information directly available.
+ *
+ * A workaround is reading from address 0 onwards, which works for raw
+ * second stage barebox located near start of the card, but is not so
+ * good when we need to load barebox from a file system.
+ *
+ * This function implements the necessary state transitions, so we
+ * can reread the CSD and determine, which the card is high capacity
+ * or not.
+ *
+ * Refer to Part1_Physical_Layer_Simplified_Specification_Ver9.00.pdf
+ * "Figure 4-13 : SD Memory Card State Diagram (data transfer mode)"
+ * for a visualization of how this works.
+ *
+ * Return: 0 when capacity type could be determined and
+ * mci->high_capacity was updated or a negative return code upon error.
+ */
+static int pbl_mci_check_high_capacity(struct pbl_mci *mci)
+{
+ struct mci_cmd cmd = {};
+ unsigned rca_arg = 0; /* RCA shifted up by 16 bis */
+ int ret, ret2;
+
+ /* CMD7: Deselect all cards and move into standby mode */
+ mci_setup_cmd(&cmd, MMC_CMD_SELECT_CARD, 0, MMC_RSP_NONE);
+ ret = pbl_mci_send_cmd(mci, &cmd, NULL);
+ if (ret) {
+ pr_debug("deselecting cards failed: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * CMD3: Need to get RCA for SDs, so we can use it to communicate
+ * with the correct SD (argument to CMD9)
+ *
+ * TODO: What to do about eMMCs? These would get a
+ * MMC_CMD_SET_RELATIVE_ADDR here
+ *
+ * Figure 27 — e•MMC state diagram (data transfer mode) n
+ * JESD84-B51.pdf doesn't list CMD3 as allowed command while
+ * in stand-by mode
+ */
+ mci_setup_cmd(&cmd, SD_CMD_SEND_RELATIVE_ADDR, 0, MMC_RSP_R6);
+ ret = pbl_mci_send_cmd(mci, &cmd, NULL);
+ if (ret) {
+ pr_debug("sending relative address failed: %d\n", ret);
+ goto out;
+ }
+
+ rca_arg = cmd.response[0] & GENMASK(31, 16);
+
+ /* CMD9: Get the Card-Specific Data */
+ mci_setup_cmd(&cmd, MMC_CMD_SEND_CSD, rca_arg, MMC_RSP_R2);
+ ret = pbl_mci_send_cmd(mci, &cmd, NULL);
+ if (ret) {
+ pr_err("sending CSD failed: %d\n", ret);
+ goto out;
+ }
+
+ /* Check CSD version */
+ mci->capacity = capacity_decode(cmd.response[0] >> 30);
+ pr_debug("detect %s capacity\n", capacity_tostr(mci->capacity));
+
+out:
+ /* CMD7: now let's got get back to transfer mode */
+ mci_setup_cmd(&cmd, MMC_CMD_SELECT_CARD, rca_arg, MMC_RSP_R1b);
+ ret2 = pbl_mci_send_cmd(mci, &cmd, NULL);
+ if (ret2) {
+ pr_err("reselecting card with %x failed: %d\n", rca_arg, ret2);
+ return ret2;
+ }
+
+ return ret;
+}
+
int pbl_mci_bio_init(struct pbl_mci *mci, struct pbl_bio *bio)
{
-
+ /*
+ * There's no useful recovery possible here, so we try to continue
+ * after having printed an error
+ */
if (mci->capacity == PBL_MCI_UNKNOWN_CAPACITY)
- BUG();
+ (void)pbl_mci_check_high_capacity(mci);
else
pr_debug("assuming %s capacity card\n",
capacity_tostr(mci->capacity));
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 6/9] mci: omap_hsmmc: split out common code
2025-04-22 5:26 [PATCH 0/9] ARM: OMAP: beaglebone: add PBL SD xload support Ahmad Fatoum
` (4 preceding siblings ...)
2025-04-22 5:26 ` [PATCH 5/9] mci: pbl: add autodetection of BootROM-initialized standard capacity cards Ahmad Fatoum
@ 2025-04-22 5:26 ` Ahmad Fatoum
2025-04-22 5:26 ` [PATCH 7/9] ARM: OMAP: add am33xx_hsmmc_start_image for PBL Ahmad Fatoum
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2025-04-22 5:26 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
In preparation for calling into the OMAP HSMMC driver at prebootloader
time, separate the driver model bits from the actual hardware driver.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/Makefile | 2 +-
drivers/mci/omap_hsmmc.c | 509 +-----------------------------
drivers/mci/omap_hsmmc.h | 17 +
drivers/mci/omap_hsmmc_common.c | 530 ++++++++++++++++++++++++++++++++
4 files changed, 553 insertions(+), 505 deletions(-)
create mode 100644 drivers/mci/omap_hsmmc.h
create mode 100644 drivers/mci/omap_hsmmc_common.c
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index 8f54107e46c1..b209a86d8873 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -15,7 +15,7 @@ obj-$(CONFIG_MCI_IMX) += imx.o
obj-$(CONFIG_MCI_IMX_ESDHC) += imx-esdhc.o imx-esdhc-common.o
pbl-$(CONFIG_MCI_IMX_ESDHC_PBL) += imx-esdhc-pbl.o imx-esdhc-common.o
obj-$(CONFIG_MCI_MXS) += mxs.o
-obj-$(CONFIG_MCI_OMAP_HSMMC) += omap_hsmmc.o
+obj-$(CONFIG_MCI_OMAP_HSMMC) += omap_hsmmc.o omap_hsmmc_common.o
obj-$(CONFIG_MCI_PXA) += pxamci.o
obj-$(CONFIG_MCI_ROCKCHIP_DWCMSHC) += rockchip-dwcmshc-sdhci.o
obj-$(CONFIG_MCI_TEGRA) += tegra-sdmmc.o
diff --git a/drivers/mci/omap_hsmmc.c b/drivers/mci/omap_hsmmc.c
index 7a5135131cda..616d57bffdac 100644
--- a/drivers/mci/omap_hsmmc.c
+++ b/drivers/mci/omap_hsmmc.c
@@ -12,6 +12,8 @@
#include <io.h>
#include <linux/err.h>
+#include "omap_hsmmc.h"
+
#include <mach/omap/omap_hsmmc.h>
#if defined(CONFIG_MFD_TWL6030) && \
@@ -20,30 +22,6 @@
#include <mach/omap/omap4_twl6030_mmc.h>
#endif
-struct hsmmc {
- unsigned char res1[0x10];
- unsigned int sysconfig; /* 0x10 */
- unsigned int sysstatus; /* 0x14 */
- unsigned char res2[0x14];
- unsigned int con; /* 0x2C */
- unsigned char res3[0xD4];
- unsigned int blk; /* 0x104 */
- unsigned int arg; /* 0x108 */
- unsigned int cmd; /* 0x10C */
- unsigned int rsp10; /* 0x110 */
- unsigned int rsp32; /* 0x114 */
- unsigned int rsp54; /* 0x118 */
- unsigned int rsp76; /* 0x11C */
- unsigned int data; /* 0x120 */
- unsigned int pstate; /* 0x124 */
- unsigned int hctl; /* 0x128 */
- unsigned int sysctl; /* 0x12C */
- unsigned int stat; /* 0x130 */
- unsigned int ie; /* 0x134 */
- unsigned char res4[0x8];
- unsigned int capa; /* 0x140 */
-};
-
struct omap_mmc_driver_data {
unsigned long reg_ofs;
};
@@ -56,164 +34,11 @@ static struct omap_mmc_driver_data omap4_data = {
.reg_ofs = 0x100,
};
-/*
- * OMAP HS MMC Bit definitions
- */
-#define MMC_SOFTRESET (0x1 << 1)
-#define RESETDONE (0x1 << 0)
-#define NOOPENDRAIN (0x0 << 0)
-#define OPENDRAIN (0x1 << 0)
-#define OD (0x1 << 0)
-#define INIT_NOINIT (0x0 << 1)
-#define INIT_INITSTREAM (0x1 << 1)
-#define HR_NOHOSTRESP (0x0 << 2)
-#define STR_BLOCK (0x0 << 3)
-#define MODE_FUNC (0x0 << 4)
-#define DW8_1_4BITMODE (0x0 << 5)
-#define MIT_CTO (0x0 << 6)
-#define CDP_ACTIVEHIGH (0x0 << 7)
-#define WPP_ACTIVEHIGH (0x0 << 8)
-#define RESERVED_MASK (0x3 << 9)
-#define CTPL_MMC_SD (0x0 << 11)
-#define BLEN_512BYTESLEN (0x200 << 0)
-#define NBLK_STPCNT (0x0 << 16)
-#define DE_DISABLE (0x0 << 0)
-#define BCE_DISABLE (0x0 << 1)
-#define BCE_ENABLE (0x1 << 1)
-#define ACEN_DISABLE (0x0 << 2)
-#define DDIR_OFFSET (4)
-#define DDIR_MASK (0x1 << 4)
-#define DDIR_WRITE (0x0 << 4)
-#define DDIR_READ (0x1 << 4)
-#define MSBS_SGLEBLK (0x0 << 5)
-#define MSBS_MULTIBLK (0x1 << 5)
-#define RSP_TYPE_OFFSET (16)
-#define RSP_TYPE_MASK (0x3 << 16)
-#define RSP_TYPE_NORSP (0x0 << 16)
-#define RSP_TYPE_LGHT136 (0x1 << 16)
-#define RSP_TYPE_LGHT48 (0x2 << 16)
-#define RSP_TYPE_LGHT48B (0x3 << 16)
-#define CCCE_NOCHECK (0x0 << 19)
-#define CCCE_CHECK (0x1 << 19)
-#define CICE_NOCHECK (0x0 << 20)
-#define CICE_CHECK (0x1 << 20)
-#define DP_OFFSET (21)
-#define DP_MASK (0x1 << 21)
-#define DP_NO_DATA (0x0 << 21)
-#define DP_DATA (0x1 << 21)
-#define CMD_TYPE_NORMAL (0x0 << 22)
-#define INDEX_OFFSET (24)
-#define INDEX_MASK (0x3f << 24)
-#define INDEX(i) (i << 24)
-#define DATI_MASK (0x1 << 1)
-#define DATI_CMDDIS (0x1 << 1)
-#define DTW_1_BITMODE (0x0 << 1)
-#define DTW_4_BITMODE (0x1 << 1)
-#define DTW_8_BITMODE (0x1 << 5) /* CON[DW8]*/
-#define SDBP_PWROFF (0x0 << 8)
-#define SDBP_PWRON (0x1 << 8)
-#define SDVS_1V8 (0x5 << 9)
-#define SDVS_3V0 (0x6 << 9)
-#define ICE_MASK (0x1 << 0)
-#define ICE_STOP (0x0 << 0)
-#define ICS_MASK (0x1 << 1)
-#define ICS_NOTREADY (0x0 << 1)
-#define ICE_OSCILLATE (0x1 << 0)
-#define CEN_MASK (0x1 << 2)
-#define CEN_DISABLE (0x0 << 2)
-#define CEN_ENABLE (0x1 << 2)
-#define CLKD_OFFSET (6)
-#define CLKD_MASK (0x3FF << 6)
-#define DTO_MASK (0xF << 16)
-#define DTO_15THDTO (0xE << 16)
-#define SOFTRESETALL (0x1 << 24)
-#define CC_MASK (0x1 << 0)
-#define TC_MASK (0x1 << 1)
-#define BWR_MASK (0x1 << 4)
-#define BRR_MASK (0x1 << 5)
-#define ERRI_MASK (0x1 << 15)
-#define IE_CC (0x01 << 0)
-#define IE_TC (0x01 << 1)
-#define IE_BWR (0x01 << 4)
-#define IE_BRR (0x01 << 5)
-#define IE_CTO (0x01 << 16)
-#define IE_CCRC (0x01 << 17)
-#define IE_CEB (0x01 << 18)
-#define IE_CIE (0x01 << 19)
-#define IE_DTO (0x01 << 20)
-#define IE_DCRC (0x01 << 21)
-#define IE_DEB (0x01 << 22)
-#define IE_CERR (0x01 << 28)
-#define IE_BADA (0x01 << 29)
-
-#define VS30_3V0SUP (1 << 25)
-#define VS18_1V8SUP (1 << 26)
-
-/* Driver definitions */
-#define MMCSD_SECTOR_SIZE 512
-#define MMC_CARD 0
-#define SD_CARD 1
-#define BYTE_MODE 0
-#define SECTOR_MODE 1
-#define CLK_INITSEQ 0
-#define CLK_400KHZ 1
-#define CLK_MISC 2
-
-#define RSP_TYPE_NONE (RSP_TYPE_NORSP | CCCE_NOCHECK | CICE_NOCHECK)
-#define MMC_CMD0 (INDEX(0) | RSP_TYPE_NONE | DP_NO_DATA | DDIR_WRITE)
-
-/* Clock Configurations and Macros */
-#define MMC_CLOCK_REFERENCE 96 /* MHz */
-
-#define mmc_reg_out(addr, mask, val)\
- writel((readl(addr) & (~(mask))) | ((val) & (mask)), (addr))
-
-struct omap_hsmmc {
- struct mci_host mci;
- struct device *dev;
- struct hsmmc *base;
- void __iomem *iobase;
-};
-
#define to_hsmmc(mci) container_of(mci, struct omap_hsmmc, mci)
-static int mmc_init_stream(struct omap_hsmmc *hsmmc)
-{
- uint64_t start;
- struct hsmmc *mmc_base = hsmmc->base;
-
- writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con);
-
- writel(MMC_CMD0, &mmc_base->cmd);
- start = get_time_ns();
- while (!(readl(&mmc_base->stat) & CC_MASK)) {
- if (is_timeout(start, SECOND)) {
- dev_dbg(hsmmc->dev, "timedout waiting for cc!\n");
- return -ETIMEDOUT;
- }
- }
- writel(CC_MASK, &mmc_base->stat);
- writel(MMC_CMD0, &mmc_base->cmd);
-
- start = get_time_ns();
- while (!(readl(&mmc_base->stat) & CC_MASK)) {
- if (is_timeout(start, SECOND)) {
- dev_dbg(hsmmc->dev, "timedout waiting for cc2!\n");
- return -ETIMEDOUT;
- }
- }
- writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con);
-
- return 0;
-}
-
static int mmc_init_setup(struct mci_host *mci, struct device *dev)
{
struct omap_hsmmc *hsmmc = to_hsmmc(mci);
- struct hsmmc *mmc_base = hsmmc->base;
- unsigned int reg_val;
- unsigned int dsor;
- uint64_t start;
/*
* Fix voltage for mmc, if booting from nand.
@@ -226,346 +51,22 @@ static int mmc_init_setup(struct mci_host *mci, struct device *dev)
set_up_mmc_voltage_omap4();
#endif
- writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET,
- &mmc_base->sysconfig);
-
- start = get_time_ns();
- while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) {
- if (is_timeout(start, SECOND)) {
- dev_dbg(hsmmc->dev, "timeout waiting for reset done\n");
- return -ETIMEDOUT;
- }
- }
-
- writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl);
-
- start = get_time_ns();
- while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0) {
- if (is_timeout(start, SECOND)) {
- dev_dbg(hsmmc->dev, "timedout waiting for softresetall!\n");
- return -ETIMEDOUT;
- }
- }
-
- writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl);
- writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP,
- &mmc_base->capa);
-
- reg_val = readl(&mmc_base->con) & RESERVED_MASK;
-
- writel(CTPL_MMC_SD | reg_val | WPP_ACTIVEHIGH | CDP_ACTIVEHIGH |
- MIT_CTO | DW8_1_4BITMODE | MODE_FUNC | STR_BLOCK |
- HR_NOHOSTRESP | INIT_NOINIT | NOOPENDRAIN, &mmc_base->con);
-
- dsor = 240;
- mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
- (ICE_STOP | DTO_15THDTO | CEN_DISABLE));
- mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
- (dsor << CLKD_OFFSET) | ICE_OSCILLATE);
-
- start = get_time_ns();
- while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
- if (is_timeout(start, SECOND)) {
- dev_dbg(hsmmc->dev, "timedout waiting for ics!\n");
- return -ETIMEDOUT;
- }
- }
-
- writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
-
- writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl);
-
- writel(IE_BADA | IE_CERR | IE_DEB | IE_DCRC | IE_DTO | IE_CIE |
- IE_CEB | IE_CCRC | IE_CTO | IE_BRR | IE_BWR | IE_TC | IE_CC,
- &mmc_base->ie);
-
- return mmc_init_stream(hsmmc);
-}
-
-static int mmc_read_data(struct omap_hsmmc *hsmmc, char *buf, unsigned int size)
-{
- struct hsmmc *mmc_base = hsmmc->base;
- unsigned int *output_buf = (unsigned int *)buf;
- unsigned int mmc_stat;
- unsigned int count;
-
- /*
- * Start Polled Read
- */
- count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
- count /= 4;
-
- while (size) {
- uint64_t start = get_time_ns();
- do {
- mmc_stat = readl(&mmc_base->stat);
- if (is_timeout(start, SECOND)) {
- dev_err(hsmmc->dev, "timedout waiting for status!\n");
- return -ETIMEDOUT;
- }
- } while (mmc_stat == 0);
-
- if ((mmc_stat & ERRI_MASK) != 0) {
- dev_err(hsmmc->dev, "Error while reading data. status: 0x%08x\n",
- mmc_stat);
- return -EIO;
- }
-
- if (mmc_stat & BRR_MASK) {
- unsigned int k;
-
- writel(readl(&mmc_base->stat) | BRR_MASK,
- &mmc_base->stat);
- for (k = 0; k < count; k++) {
- *output_buf = readl(&mmc_base->data);
- output_buf++;
- }
- size -= (count*4);
- }
-
- if (mmc_stat & BWR_MASK)
- writel(readl(&mmc_base->stat) | BWR_MASK,
- &mmc_base->stat);
-
- if (mmc_stat & TC_MASK) {
- writel(readl(&mmc_base->stat) | TC_MASK,
- &mmc_base->stat);
- break;
- }
- }
- return 0;
-}
-
-static int mmc_write_data(struct omap_hsmmc *hsmmc, const char *buf, unsigned int size)
-{
- struct hsmmc *mmc_base = hsmmc->base;
- unsigned int *input_buf = (unsigned int *)buf;
- unsigned int mmc_stat;
- unsigned int count;
-
- /*
- * Start Polled Read
- */
- count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
- count /= 4;
-
- while (size) {
- uint64_t start = get_time_ns();
- do {
- mmc_stat = readl(&mmc_base->stat);
- if (is_timeout(start, SECOND)) {
- dev_dbg(hsmmc->dev, "timedout waiting for status!\n");
- return -ETIMEDOUT;
- }
- } while (mmc_stat == 0);
-
- if ((mmc_stat & ERRI_MASK) != 0) {
- dev_err(hsmmc->dev, "Error while reading data. status: 0x%08x\n",
- mmc_stat);
- return -EIO;
- }
-
- if (mmc_stat & BWR_MASK) {
- unsigned int k;
-
- writel(readl(&mmc_base->stat) | BWR_MASK,
- &mmc_base->stat);
- for (k = 0; k < count; k++) {
- writel(*input_buf, &mmc_base->data);
- input_buf++;
- }
- size -= (count * 4);
- }
-
- if (mmc_stat & BRR_MASK)
- writel(readl(&mmc_base->stat) | BRR_MASK,
- &mmc_base->stat);
-
- if (mmc_stat & TC_MASK) {
- writel(readl(&mmc_base->stat) | TC_MASK,
- &mmc_base->stat);
- break;
- }
- }
- return 0;
+ return omap_hsmmc_init(hsmmc);
}
static int mmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
struct mci_data *data)
{
struct omap_hsmmc *hsmmc = to_hsmmc(mci);
- struct hsmmc *mmc_base = hsmmc->base;
- unsigned int flags, mmc_stat;
- uint64_t start;
- start = get_time_ns();
- while ((readl(&mmc_base->pstate) & DATI_MASK) == DATI_CMDDIS) {
- if (is_timeout(start, SECOND)) {
- dev_dbg(hsmmc->dev, "timedout waiting for cmddis!\n");
- return -ETIMEDOUT;
- }
- }
-
- writel(0xFFFFFFFF, &mmc_base->stat);
- start = get_time_ns();
- while (readl(&mmc_base->stat)) {
- if (is_timeout(start, SECOND)) {
- dev_dbg(hsmmc->dev, "timedout waiting for stat!\n");
- return -ETIMEDOUT;
- }
- }
-
- /*
- * CMDREG
- * CMDIDX[13:8] : Command index
- * DATAPRNT[5] : Data Present Select
- * ENCMDIDX[4] : Command Index Check Enable
- * ENCMDCRC[3] : Command CRC Check Enable
- * RSPTYP[1:0]
- * 00 = No Response
- * 01 = Length 136
- * 10 = Length 48
- * 11 = Length 48 Check busy after response
- */
- /* Delay added before checking the status of frq change
- * retry not supported by mmc.c(core file)
- */
- if (cmd->cmdidx == SD_CMD_APP_SEND_SCR)
- udelay(50000); /* wait 50 ms */
-
- if (!(cmd->resp_type & MMC_RSP_PRESENT))
- flags = 0;
- else if (cmd->resp_type & MMC_RSP_136)
- flags = RSP_TYPE_LGHT136 | CICE_NOCHECK;
- else if (cmd->resp_type & MMC_RSP_BUSY)
- flags = RSP_TYPE_LGHT48B;
- else
- flags = RSP_TYPE_LGHT48;
-
- /* enable default flags */
- flags = flags | (CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK |
- MSBS_SGLEBLK | ACEN_DISABLE | BCE_DISABLE | DE_DISABLE);
-
- if (cmd->resp_type & MMC_RSP_CRC)
- flags |= CCCE_CHECK;
- if (cmd->resp_type & MMC_RSP_OPCODE)
- flags |= CICE_CHECK;
-
- if (data) {
- if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) ||
- (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) {
- flags |= (MSBS_MULTIBLK | BCE_ENABLE);
- data->blocksize = 512;
- writel(data->blocksize | (data->blocks << 16),
- &mmc_base->blk);
- } else
- writel(data->blocksize | NBLK_STPCNT, &mmc_base->blk);
-
- if (data->flags & MMC_DATA_READ)
- flags |= (DP_DATA | DDIR_READ);
- else
- flags |= (DP_DATA | DDIR_WRITE);
- }
-
- writel(cmd->cmdarg, &mmc_base->arg);
- writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);
-
- start = get_time_ns();
- do {
- mmc_stat = readl(&mmc_base->stat);
- if (is_timeout(start, SECOND)) {
- dev_dbg(hsmmc->dev, "timeout: No status update\n");
- return -ETIMEDOUT;
- }
- } while (!mmc_stat);
-
- if ((mmc_stat & IE_CTO) != 0)
- return -ETIMEDOUT;
- else if ((mmc_stat & ERRI_MASK) != 0)
- return -1;
-
- if (mmc_stat & CC_MASK) {
- writel(CC_MASK, &mmc_base->stat);
- if (cmd->resp_type & MMC_RSP_PRESENT) {
- if (cmd->resp_type & MMC_RSP_136) {
- /* response type 2 */
- cmd->response[3] = readl(&mmc_base->rsp10);
- cmd->response[2] = readl(&mmc_base->rsp32);
- cmd->response[1] = readl(&mmc_base->rsp54);
- cmd->response[0] = readl(&mmc_base->rsp76);
- } else
- /* response types 1, 1b, 3, 4, 5, 6 */
- cmd->response[0] = readl(&mmc_base->rsp10);
- }
- }
-
- if (!data)
- return 0;
-
- if (data->flags & MMC_DATA_READ)
- return mmc_read_data(hsmmc, data->dest,
- data->blocksize * data->blocks);
-
- if (IS_ENABLED(CONFIG_MCI_WRITE))
- return mmc_write_data(hsmmc, data->src,
- data->blocksize * data->blocks);
-
- return -ENOSYS;
+ return omap_hsmmc_send_cmd(hsmmc, cmd, data);
}
static void mmc_set_ios(struct mci_host *mci, struct mci_ios *ios)
{
struct omap_hsmmc *hsmmc = to_hsmmc(mci);
- struct hsmmc *mmc_base = hsmmc->base;
- unsigned int dsor = 0;
- uint64_t start;
- /* configue bus width */
- switch (ios->bus_width) {
- case MMC_BUS_WIDTH_8:
- writel(readl(&mmc_base->con) | DTW_8_BITMODE,
- &mmc_base->con);
- break;
-
- case MMC_BUS_WIDTH_4:
- writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
- &mmc_base->con);
- writel(readl(&mmc_base->hctl) | DTW_4_BITMODE,
- &mmc_base->hctl);
- break;
-
- case MMC_BUS_WIDTH_1:
- writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
- &mmc_base->con);
- writel(readl(&mmc_base->hctl) & ~DTW_4_BITMODE,
- &mmc_base->hctl);
- break;
- default:
- return;
- }
-
- /* configure clock with 96Mhz system clock.
- */
- if (ios->clock != 0) {
- dsor = (MMC_CLOCK_REFERENCE * 1000000 / ios->clock);
- if ((MMC_CLOCK_REFERENCE * 1000000) / dsor > ios->clock)
- dsor++;
- }
-
- mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
- (ICE_STOP | DTO_15THDTO | CEN_DISABLE));
-
- mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
- (dsor << CLKD_OFFSET) | ICE_OSCILLATE);
-
- start = get_time_ns();
- while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
- if (is_timeout(start, SECOND)) {
- dev_dbg(hsmmc->dev, "timedout waiting for ics!\n");
- return;
- }
- }
- writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
+ return omap_hsmmc_set_ios(hsmmc, ios);
}
static const struct mci_ops omap_mmc_ops = {
diff --git a/drivers/mci/omap_hsmmc.h b/drivers/mci/omap_hsmmc.h
new file mode 100644
index 000000000000..2de3f8f31d8c
--- /dev/null
+++ b/drivers/mci/omap_hsmmc.h
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <mci.h>
+
+struct omap_hsmmc {
+ struct mci_host mci;
+ struct device *dev;
+ struct hsmmc *base;
+ void __iomem *iobase;
+};
+
+int omap_hsmmc_init(struct omap_hsmmc *hsmmc);
+
+int omap_hsmmc_send_cmd(struct omap_hsmmc *hsmmc, struct mci_cmd *cmd,
+ struct mci_data *data);
+
+void omap_hsmmc_set_ios(struct omap_hsmmc *hsmmc, struct mci_ios *ios);
diff --git a/drivers/mci/omap_hsmmc_common.c b/drivers/mci/omap_hsmmc_common.c
new file mode 100644
index 000000000000..04c712460622
--- /dev/null
+++ b/drivers/mci/omap_hsmmc_common.c
@@ -0,0 +1,530 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2008 Texas Instruments (http://www.ti.com/, Sukumar Ghorai <s-ghorai@ti.com>)
+
+/* #define DEBUG */
+#include <config.h>
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <mci.h>
+#include <clock.h>
+#include <errno.h>
+#include <io.h>
+#include <linux/err.h>
+
+#include "omap_hsmmc.h"
+
+struct hsmmc {
+ unsigned char res1[0x10];
+ unsigned int sysconfig; /* 0x10 */
+ unsigned int sysstatus; /* 0x14 */
+ unsigned char res2[0x14];
+ unsigned int con; /* 0x2C */
+ unsigned char res3[0xD4];
+ unsigned int blk; /* 0x104 */
+ unsigned int arg; /* 0x108 */
+ unsigned int cmd; /* 0x10C */
+ unsigned int rsp10; /* 0x110 */
+ unsigned int rsp32; /* 0x114 */
+ unsigned int rsp54; /* 0x118 */
+ unsigned int rsp76; /* 0x11C */
+ unsigned int data; /* 0x120 */
+ unsigned int pstate; /* 0x124 */
+ unsigned int hctl; /* 0x128 */
+ unsigned int sysctl; /* 0x12C */
+ unsigned int stat; /* 0x130 */
+ unsigned int ie; /* 0x134 */
+ unsigned char res4[0x8];
+ unsigned int capa; /* 0x140 */
+};
+
+/*
+ * OMAP HS MMC Bit definitions
+ */
+#define MMC_SOFTRESET (0x1 << 1)
+#define RESETDONE (0x1 << 0)
+#define NOOPENDRAIN (0x0 << 0)
+#define OPENDRAIN (0x1 << 0)
+#define OD (0x1 << 0)
+#define INIT_NOINIT (0x0 << 1)
+#define INIT_INITSTREAM (0x1 << 1)
+#define HR_NOHOSTRESP (0x0 << 2)
+#define STR_BLOCK (0x0 << 3)
+#define MODE_FUNC (0x0 << 4)
+#define DW8_1_4BITMODE (0x0 << 5)
+#define MIT_CTO (0x0 << 6)
+#define CDP_ACTIVEHIGH (0x0 << 7)
+#define WPP_ACTIVEHIGH (0x0 << 8)
+#define RESERVED_MASK (0x3 << 9)
+#define CTPL_MMC_SD (0x0 << 11)
+#define BLEN_512BYTESLEN (0x200 << 0)
+#define NBLK_STPCNT (0x0 << 16)
+#define DE_DISABLE (0x0 << 0)
+#define BCE_DISABLE (0x0 << 1)
+#define BCE_ENABLE (0x1 << 1)
+#define ACEN_DISABLE (0x0 << 2)
+#define DDIR_OFFSET (4)
+#define DDIR_MASK (0x1 << 4)
+#define DDIR_WRITE (0x0 << 4)
+#define DDIR_READ (0x1 << 4)
+#define MSBS_SGLEBLK (0x0 << 5)
+#define MSBS_MULTIBLK (0x1 << 5)
+#define RSP_TYPE_OFFSET (16)
+#define RSP_TYPE_MASK (0x3 << 16)
+#define RSP_TYPE_NORSP (0x0 << 16)
+#define RSP_TYPE_LGHT136 (0x1 << 16)
+#define RSP_TYPE_LGHT48 (0x2 << 16)
+#define RSP_TYPE_LGHT48B (0x3 << 16)
+#define CCCE_NOCHECK (0x0 << 19)
+#define CCCE_CHECK (0x1 << 19)
+#define CICE_NOCHECK (0x0 << 20)
+#define CICE_CHECK (0x1 << 20)
+#define DP_OFFSET (21)
+#define DP_MASK (0x1 << 21)
+#define DP_NO_DATA (0x0 << 21)
+#define DP_DATA (0x1 << 21)
+#define CMD_TYPE_NORMAL (0x0 << 22)
+#define INDEX_OFFSET (24)
+#define INDEX_MASK (0x3f << 24)
+#define INDEX(i) (i << 24)
+#define DATI_MASK (0x1 << 1)
+#define DATI_CMDDIS (0x1 << 1)
+#define DTW_1_BITMODE (0x0 << 1)
+#define DTW_4_BITMODE (0x1 << 1)
+#define DTW_8_BITMODE (0x1 << 5) /* CON[DW8]*/
+#define SDBP_PWROFF (0x0 << 8)
+#define SDBP_PWRON (0x1 << 8)
+#define SDVS_1V8 (0x5 << 9)
+#define SDVS_3V0 (0x6 << 9)
+#define ICE_MASK (0x1 << 0)
+#define ICE_STOP (0x0 << 0)
+#define ICS_MASK (0x1 << 1)
+#define ICS_NOTREADY (0x0 << 1)
+#define ICE_OSCILLATE (0x1 << 0)
+#define CEN_MASK (0x1 << 2)
+#define CEN_DISABLE (0x0 << 2)
+#define CEN_ENABLE (0x1 << 2)
+#define CLKD_OFFSET (6)
+#define CLKD_MASK (0x3FF << 6)
+#define DTO_MASK (0xF << 16)
+#define DTO_15THDTO (0xE << 16)
+#define SOFTRESETALL (0x1 << 24)
+#define CC_MASK (0x1 << 0)
+#define TC_MASK (0x1 << 1)
+#define BWR_MASK (0x1 << 4)
+#define BRR_MASK (0x1 << 5)
+#define ERRI_MASK (0x1 << 15)
+#define IE_CC (0x01 << 0)
+#define IE_TC (0x01 << 1)
+#define IE_BWR (0x01 << 4)
+#define IE_BRR (0x01 << 5)
+#define IE_CTO (0x01 << 16)
+#define IE_CCRC (0x01 << 17)
+#define IE_CEB (0x01 << 18)
+#define IE_CIE (0x01 << 19)
+#define IE_DTO (0x01 << 20)
+#define IE_DCRC (0x01 << 21)
+#define IE_DEB (0x01 << 22)
+#define IE_CERR (0x01 << 28)
+#define IE_BADA (0x01 << 29)
+
+#define VS30_3V0SUP (1 << 25)
+#define VS18_1V8SUP (1 << 26)
+
+/* Driver definitions */
+#define MMCSD_SECTOR_SIZE 512
+#define MMC_CARD 0
+#define SD_CARD 1
+#define BYTE_MODE 0
+#define SECTOR_MODE 1
+#define CLK_INITSEQ 0
+#define CLK_400KHZ 1
+#define CLK_MISC 2
+
+#define RSP_TYPE_NONE (RSP_TYPE_NORSP | CCCE_NOCHECK | CICE_NOCHECK)
+#define MMC_CMD0 (INDEX(0) | RSP_TYPE_NONE | DP_NO_DATA | DDIR_WRITE)
+
+/* Clock Configurations and Macros */
+#define MMC_CLOCK_REFERENCE 96 /* MHz */
+
+#define mmc_reg_out(addr, mask, val)\
+ writel((readl(addr) & (~(mask))) | ((val) & (mask)), (addr))
+
+#define to_hsmmc(mci) container_of(mci, struct omap_hsmmc, mci)
+
+static int mmc_init_stream(struct omap_hsmmc *hsmmc)
+{
+ uint64_t start;
+ struct hsmmc *mmc_base = hsmmc->base;
+
+ writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con);
+
+ writel(MMC_CMD0, &mmc_base->cmd);
+ start = get_time_ns();
+ while (!(readl(&mmc_base->stat) & CC_MASK)) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for cc!\n");
+ return -ETIMEDOUT;
+ }
+ }
+ writel(CC_MASK, &mmc_base->stat);
+ writel(MMC_CMD0, &mmc_base->cmd);
+
+ start = get_time_ns();
+ while (!(readl(&mmc_base->stat) & CC_MASK)) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for cc2!\n");
+ return -ETIMEDOUT;
+ }
+ }
+ writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con);
+
+ return 0;
+}
+
+int omap_hsmmc_init(struct omap_hsmmc *hsmmc)
+{
+ struct hsmmc *mmc_base = hsmmc->base;
+ unsigned int reg_val;
+ unsigned int dsor;
+ uint64_t start;
+
+ writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET,
+ &mmc_base->sysconfig);
+
+ start = get_time_ns();
+ while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timeout waiting for reset done\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl);
+
+ start = get_time_ns();
+ while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for softresetall!\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl);
+ writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP,
+ &mmc_base->capa);
+
+ reg_val = readl(&mmc_base->con) & RESERVED_MASK;
+
+ writel(CTPL_MMC_SD | reg_val | WPP_ACTIVEHIGH | CDP_ACTIVEHIGH |
+ MIT_CTO | DW8_1_4BITMODE | MODE_FUNC | STR_BLOCK |
+ HR_NOHOSTRESP | INIT_NOINIT | NOOPENDRAIN, &mmc_base->con);
+
+ dsor = 240;
+ mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
+ (ICE_STOP | DTO_15THDTO | CEN_DISABLE));
+ mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
+ (dsor << CLKD_OFFSET) | ICE_OSCILLATE);
+
+ start = get_time_ns();
+ while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for ics!\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
+
+ writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl);
+
+ writel(IE_BADA | IE_CERR | IE_DEB | IE_DCRC | IE_DTO | IE_CIE |
+ IE_CEB | IE_CCRC | IE_CTO | IE_BRR | IE_BWR | IE_TC | IE_CC,
+ &mmc_base->ie);
+
+ return mmc_init_stream(hsmmc);
+}
+
+static int mmc_read_data(struct omap_hsmmc *hsmmc, char *buf, unsigned int size)
+{
+ struct hsmmc *mmc_base = hsmmc->base;
+ unsigned int *output_buf = (unsigned int *)buf;
+ unsigned int mmc_stat;
+ unsigned int count;
+
+ /*
+ * Start Polled Read
+ */
+ count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
+ count /= 4;
+
+ while (size) {
+ uint64_t start = get_time_ns();
+ do {
+ mmc_stat = readl(&mmc_base->stat);
+ if (is_timeout(start, SECOND)) {
+ dev_err(hsmmc->dev, "timedout waiting for status!\n");
+ return -ETIMEDOUT;
+ }
+ } while (mmc_stat == 0);
+
+ if ((mmc_stat & ERRI_MASK) != 0) {
+ dev_err(hsmmc->dev, "Error while reading data. status: 0x%08x\n",
+ mmc_stat);
+ return -EIO;
+ }
+
+ if (mmc_stat & BRR_MASK) {
+ unsigned int k;
+
+ writel(readl(&mmc_base->stat) | BRR_MASK,
+ &mmc_base->stat);
+ for (k = 0; k < count; k++) {
+ *output_buf = readl(&mmc_base->data);
+ output_buf++;
+ }
+ size -= (count*4);
+ }
+
+ if (mmc_stat & BWR_MASK)
+ writel(readl(&mmc_base->stat) | BWR_MASK,
+ &mmc_base->stat);
+
+ if (mmc_stat & TC_MASK) {
+ writel(readl(&mmc_base->stat) | TC_MASK,
+ &mmc_base->stat);
+ break;
+ }
+ }
+ return 0;
+}
+
+static int mmc_write_data(struct omap_hsmmc *hsmmc, const char *buf, unsigned int size)
+{
+ struct hsmmc *mmc_base = hsmmc->base;
+ unsigned int *input_buf = (unsigned int *)buf;
+ unsigned int mmc_stat;
+ unsigned int count;
+
+ /*
+ * Start Polled Read
+ */
+ count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
+ count /= 4;
+
+ while (size) {
+ uint64_t start = get_time_ns();
+ do {
+ mmc_stat = readl(&mmc_base->stat);
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for status!\n");
+ return -ETIMEDOUT;
+ }
+ } while (mmc_stat == 0);
+
+ if ((mmc_stat & ERRI_MASK) != 0) {
+ dev_err(hsmmc->dev, "Error while reading data. status: 0x%08x\n",
+ mmc_stat);
+ return -EIO;
+ }
+
+ if (mmc_stat & BWR_MASK) {
+ unsigned int k;
+
+ writel(readl(&mmc_base->stat) | BWR_MASK,
+ &mmc_base->stat);
+ for (k = 0; k < count; k++) {
+ writel(*input_buf, &mmc_base->data);
+ input_buf++;
+ }
+ size -= (count * 4);
+ }
+
+ if (mmc_stat & BRR_MASK)
+ writel(readl(&mmc_base->stat) | BRR_MASK,
+ &mmc_base->stat);
+
+ if (mmc_stat & TC_MASK) {
+ writel(readl(&mmc_base->stat) | TC_MASK,
+ &mmc_base->stat);
+ break;
+ }
+ }
+ return 0;
+}
+
+int omap_hsmmc_send_cmd(struct omap_hsmmc *hsmmc, struct mci_cmd *cmd,
+ struct mci_data *data)
+{
+ struct hsmmc *mmc_base = hsmmc->base;
+ unsigned int flags, mmc_stat;
+ uint64_t start;
+
+ start = get_time_ns();
+ while ((readl(&mmc_base->pstate) & DATI_MASK) == DATI_CMDDIS) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for cmddis!\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ writel(0xFFFFFFFF, &mmc_base->stat);
+ start = get_time_ns();
+ while (readl(&mmc_base->stat)) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for stat!\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ /*
+ * CMDREG
+ * CMDIDX[13:8] : Command index
+ * DATAPRNT[5] : Data Present Select
+ * ENCMDIDX[4] : Command Index Check Enable
+ * ENCMDCRC[3] : Command CRC Check Enable
+ * RSPTYP[1:0]
+ * 00 = No Response
+ * 01 = Length 136
+ * 10 = Length 48
+ * 11 = Length 48 Check busy after response
+ */
+ /* Delay added before checking the status of frq change
+ * retry not supported by mmc.c(core file)
+ */
+ if (cmd->cmdidx == SD_CMD_APP_SEND_SCR)
+ udelay(50000); /* wait 50 ms */
+
+ if (!(cmd->resp_type & MMC_RSP_PRESENT))
+ flags = 0;
+ else if (cmd->resp_type & MMC_RSP_136)
+ flags = RSP_TYPE_LGHT136 | CICE_NOCHECK;
+ else if (cmd->resp_type & MMC_RSP_BUSY)
+ flags = RSP_TYPE_LGHT48B;
+ else
+ flags = RSP_TYPE_LGHT48;
+
+ /* enable default flags */
+ flags = flags | (CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK |
+ MSBS_SGLEBLK | ACEN_DISABLE | BCE_DISABLE | DE_DISABLE);
+
+ if (cmd->resp_type & MMC_RSP_CRC)
+ flags |= CCCE_CHECK;
+ if (cmd->resp_type & MMC_RSP_OPCODE)
+ flags |= CICE_CHECK;
+
+ if (data) {
+ if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) ||
+ (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) {
+ flags |= (MSBS_MULTIBLK | BCE_ENABLE);
+ data->blocksize = 512;
+ writel(data->blocksize | (data->blocks << 16),
+ &mmc_base->blk);
+ } else
+ writel(data->blocksize | NBLK_STPCNT, &mmc_base->blk);
+
+ if (data->flags & MMC_DATA_READ)
+ flags |= (DP_DATA | DDIR_READ);
+ else
+ flags |= (DP_DATA | DDIR_WRITE);
+ }
+
+ writel(cmd->cmdarg, &mmc_base->arg);
+ writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);
+
+ start = get_time_ns();
+ do {
+ mmc_stat = readl(&mmc_base->stat);
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timeout: No status update\n");
+ return -ETIMEDOUT;
+ }
+ } while (!mmc_stat);
+
+ if ((mmc_stat & IE_CTO) != 0)
+ return -ETIMEDOUT;
+ else if ((mmc_stat & ERRI_MASK) != 0)
+ return -1;
+
+ if (mmc_stat & CC_MASK) {
+ writel(CC_MASK, &mmc_base->stat);
+ if (cmd->resp_type & MMC_RSP_PRESENT) {
+ if (cmd->resp_type & MMC_RSP_136) {
+ /* response type 2 */
+ cmd->response[3] = readl(&mmc_base->rsp10);
+ cmd->response[2] = readl(&mmc_base->rsp32);
+ cmd->response[1] = readl(&mmc_base->rsp54);
+ cmd->response[0] = readl(&mmc_base->rsp76);
+ } else
+ /* response types 1, 1b, 3, 4, 5, 6 */
+ cmd->response[0] = readl(&mmc_base->rsp10);
+ }
+ }
+
+ if (!data)
+ return 0;
+
+ if (data->flags & MMC_DATA_READ)
+ return mmc_read_data(hsmmc, data->dest,
+ data->blocksize * data->blocks);
+
+ if (IS_ENABLED(CONFIG_MCI_WRITE))
+ return mmc_write_data(hsmmc, data->src,
+ data->blocksize * data->blocks);
+
+ return -ENOSYS;
+}
+
+void omap_hsmmc_set_ios(struct omap_hsmmc *hsmmc, struct mci_ios *ios)
+{
+ struct hsmmc *mmc_base = hsmmc->base;
+ unsigned int dsor = 0;
+ uint64_t start;
+
+ /* configue bus width */
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_8:
+ writel(readl(&mmc_base->con) | DTW_8_BITMODE,
+ &mmc_base->con);
+ break;
+
+ case MMC_BUS_WIDTH_4:
+ writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
+ &mmc_base->con);
+ writel(readl(&mmc_base->hctl) | DTW_4_BITMODE,
+ &mmc_base->hctl);
+ break;
+
+ case MMC_BUS_WIDTH_1:
+ writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
+ &mmc_base->con);
+ writel(readl(&mmc_base->hctl) & ~DTW_4_BITMODE,
+ &mmc_base->hctl);
+ break;
+ default:
+ return;
+ }
+
+ /* configure clock with 96Mhz system clock.
+ */
+ if (ios->clock != 0) {
+ dsor = (MMC_CLOCK_REFERENCE * 1000000 / ios->clock);
+ if ((MMC_CLOCK_REFERENCE * 1000000) / dsor > ios->clock)
+ dsor++;
+ }
+
+ mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
+ (ICE_STOP | DTO_15THDTO | CEN_DISABLE));
+
+ mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
+ (dsor << CLKD_OFFSET) | ICE_OSCILLATE);
+
+ start = get_time_ns();
+ while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for ics!\n");
+ return;
+ }
+ }
+ writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
+}
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 7/9] ARM: OMAP: add am33xx_hsmmc_start_image for PBL
2025-04-22 5:26 [PATCH 0/9] ARM: OMAP: beaglebone: add PBL SD xload support Ahmad Fatoum
` (5 preceding siblings ...)
2025-04-22 5:26 ` [PATCH 6/9] mci: omap_hsmmc: split out common code Ahmad Fatoum
@ 2025-04-22 5:26 ` Ahmad Fatoum
2025-04-22 5:26 ` [PATCH 8/9] mci: omap_hsmmc: add xload implementation " Ahmad Fatoum
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2025-04-22 5:26 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We have had a separate am335x_mlo_defconfig for a long time, but it
frequently breaks, because barebox keeps getting bigger and then is
slimmed down a bit again.
To counteract that, there is a am335x_mlo_sdmmc_defconfig, but the
downside is that this still requires two barebox builds: One for MLO
and one for barebox proper, because the MLO needs to fit into the
on-chip SRAM.
Reworking drivers for all supported boot media, including raw flash,
to be usable in PBL is a big undertaking, but supporting just SD is easy
enough, so add an entry point exclusively for that.
The end goal is to allow an easier integration for a future
beaglebone-yocto support in openembedded-core.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/mach-omap/Makefile | 1 +
arch/arm/mach-omap/am33xx_generic.c | 38 ++++++++---------
arch/arm/mach-omap/am33xx_xload.c | 66 +++++++++++++++++++++++++++++
include/mach/omap/am33xx-generic.h | 2 +
include/mach/omap/xload.h | 14 ++++++
5 files changed, 102 insertions(+), 19 deletions(-)
create mode 100644 arch/arm/mach-omap/am33xx_xload.c
create mode 100644 include/mach/omap/xload.h
diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile
index 6b42196b2373..83722dfa9ca1 100644
--- a/arch/arm/mach-omap/Makefile
+++ b/arch/arm/mach-omap/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_ARCH_OMAP3) += omap3_generic.o auxcr.o
pbl-$(CONFIG_ARCH_OMAP3) += omap3_generic.o auxcr.o
obj-$(CONFIG_ARCH_OMAP4) += omap4_generic.o omap4_clock.o
pbl-$(CONFIG_ARCH_OMAP4) += omap4_generic.o omap4_clock.o
+pbl-$(CONFIG_MCI_OMAP_HSMMC_PBL) += am33xx_xload.o
obj-pbl-$(CONFIG_ARCH_AM33XX) += am33xx_generic.o am33xx_clock.o am33xx_mux.o am3xxx.o emif4.o
obj-pbl-$(CONFIG_ARCH_AM35XX) += am3xxx.o emif4.o
obj-$(CONFIG_ARCH_AM33XX) += am33xx_scrm.o
diff --git a/arch/arm/mach-omap/am33xx_generic.c b/arch/arm/mach-omap/am33xx_generic.c
index bcafc0677e38..007daccdfbe1 100644
--- a/arch/arm/mach-omap/am33xx_generic.c
+++ b/arch/arm/mach-omap/am33xx_generic.c
@@ -120,40 +120,40 @@ u32 am33xx_running_in_sdram(void)
return 0; /* running in SRAM or FLASH */
}
-static int am33xx_bootsource(void)
+enum bootsource am33xx_get_bootsource(int *instance)
{
- enum bootsource src;
- int instance = 0;
uint32_t *am33xx_bootinfo = (void *)AM33XX_SRAM_SCRATCH_SPACE;
switch (am33xx_bootinfo[2] & 0xFF) {
case 0x05:
- src = BOOTSOURCE_NAND;
- break;
+ return BOOTSOURCE_NAND;
case 0x08:
- src = BOOTSOURCE_MMC;
instance = 0;
- break;
+ return BOOTSOURCE_MMC;
case 0x09:
- src = BOOTSOURCE_MMC;
- instance = 1;
- break;
+ *instance = 1;
+ return BOOTSOURCE_MMC;
case 0x0b:
- src = BOOTSOURCE_SPI;
- break;
+ return BOOTSOURCE_SPI;
case 0x41:
- src = BOOTSOURCE_SERIAL;
- break;
+ return BOOTSOURCE_SERIAL;
case 0x44:
- src = BOOTSOURCE_USB;
- break;
+ return BOOTSOURCE_USB;
case 0x46:
- src = BOOTSOURCE_NET;
- break;
+ return BOOTSOURCE_NET;
default:
- src = BOOTSOURCE_UNKNOWN;
+ return BOOTSOURCE_UNKNOWN;
}
+}
+
+static int am33xx_bootsource(void)
+{
+ enum bootsource src;
+ int instance = 0;
+
+ src = am33xx_get_bootsource(&instance);
bootsource_set_raw(src, instance);
+
return 0;
}
diff --git a/arch/arm/mach-omap/am33xx_xload.c b/arch/arm/mach-omap/am33xx_xload.c
new file mode 100644
index 000000000000..f0c8b451b308
--- /dev/null
+++ b/arch/arm/mach-omap/am33xx_xload.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <common.h>
+#include <filetype.h>
+#include <mach/omap/generic.h>
+#include <mach/omap/xload.h>
+#include <mach/omap/am33xx-silicon.h>
+#include <mach/omap/am33xx-generic.h>
+#include <mach/omap/am33xx-clock.h>
+#include <bootsource.h>
+#include <linux/sizes.h>
+#include <asm/cache.h>
+#include <pbl/bio.h>
+
+struct xload_instance {
+ void __iomem *base;
+};
+
+static void omap_hsmmc_fat_start_image(struct pbl_bio *bio, void *buf)
+{
+ int ret;
+
+ ret = pbl_fat_load(bio, "barebox.bin", buf, SZ_2M);
+ if (ret < 0) {
+ pr_err("pbl_fat_load: error %d\n", ret);
+ return;
+ }
+
+ sync_caches_for_execution();
+
+ asm volatile ("bx %0\n" : : "r"(buf) :);
+ __builtin_unreachable();
+}
+
+static const struct xload_instance am35xx_hsmmc_instances[] = {
+ [0] = { .base = IOMEM(AM33XX_MMCHS0_BASE), },
+ [1] = { .base = IOMEM(AM33XX_MMC1_BASE), },
+ [2] = { .base = IOMEM(AM33XX_MMCHS2_BASE), },
+};
+
+void __noreturn am33xx_hsmmc_start_image(void)
+{
+ void *buf = (void *)OMAP_DRAM_ADDR_SPACE_START;
+ const struct xload_instance *instance;
+ enum bootsource src;
+ struct pbl_bio bio;
+ int id = 0, ret;
+
+ omap_dmtimer_init(IOMEM(AM33XX_DMTIMER0_BASE),
+ am33xx_get_osc_clock() * 1000);
+
+ src = am33xx_get_bootsource(&id);
+ if (src != BOOTSOURCE_MMC)
+ panic("This MLO was configured only for SD/MMC\n");
+
+ instance = &am35xx_hsmmc_instances[id];
+
+ ret = omap_hsmmc_bio_init(&bio, instance->base, 0x100);
+ if (ret)
+ goto out_panic;
+
+ omap_hsmmc_fat_start_image(&bio, buf);
+
+out_panic:
+ panic("FAT chainloading failed\n");
+}
diff --git a/include/mach/omap/am33xx-generic.h b/include/mach/omap/am33xx-generic.h
index 30aa13974111..a1ede96a30ff 100644
--- a/include/mach/omap/am33xx-generic.h
+++ b/include/mach/omap/am33xx-generic.h
@@ -30,6 +30,8 @@ u32 am33xx_running_in_flash(void);
u32 am33xx_running_in_sram(void);
u32 am33xx_running_in_sdram(void);
+enum bootsource am33xx_get_bootsource(int *instance);
+
void am33xx_enable_per_clocks(void);
int am33xx_init(void);
int am33xx_devices_init(void);
diff --git a/include/mach/omap/xload.h b/include/mach/omap/xload.h
new file mode 100644
index 000000000000..d820d2602c22
--- /dev/null
+++ b/include/mach/omap/xload.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __MACH_OMAP_XLOAD_H
+#define __MACH_OMAP_XLOAD_H
+
+#include <linux/compiler.h>
+#include <pbl/bio.h>
+
+void __noreturn am33xx_hsmmc_start_image(void);
+
+int omap_hsmmc_bio_init(struct pbl_bio *bio, void __iomem *base,
+ unsigned reg_ofs);
+
+#endif /* __MACH_OMAP_XLOAD_H */
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 8/9] mci: omap_hsmmc: add xload implementation for PBL
2025-04-22 5:26 [PATCH 0/9] ARM: OMAP: beaglebone: add PBL SD xload support Ahmad Fatoum
` (6 preceding siblings ...)
2025-04-22 5:26 ` [PATCH 7/9] ARM: OMAP: add am33xx_hsmmc_start_image for PBL Ahmad Fatoum
@ 2025-04-22 5:26 ` Ahmad Fatoum
2025-04-22 5:26 ` [PATCH 9/9] ARM: OMAP: beaglebone: add PBL SD xload support Ahmad Fatoum
2025-04-22 10:55 ` [PATCH 0/9] " Sascha Hauer
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2025-04-22 5:26 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Luckily, the BootROM does no reset of hardware after handing over
control to the MLO and thus SD card, host and clock/resets are all
configured for barebox MLO to directly send MMC_CMD_READ_MULTIPLE_BLOCK.
Add a PBL driver that does this.
This will be used to enable a single barebox build to produce both MLO
and second stage images for the Beaglebone Black.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/Kconfig | 3 +++
drivers/mci/Makefile | 1 +
drivers/mci/omap_hsmmc_common.c | 2 +-
drivers/mci/omap_hsmmc_pbl.c | 32 ++++++++++++++++++++++++++++++++
4 files changed, 37 insertions(+), 1 deletion(-)
create mode 100644 drivers/mci/omap_hsmmc_pbl.c
diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index 09648aa77150..44fd4716aade 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -255,3 +255,6 @@ config MCI_ATMEL_PBL
config MCI_ATMEL_SDHCI_PBL
bool
select MCI_SDHCI
+
+config MCI_OMAP_HSMMC_PBL
+ bool
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index b209a86d8873..f76059e7b550 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_MCI_IMX_ESDHC) += imx-esdhc.o imx-esdhc-common.o
pbl-$(CONFIG_MCI_IMX_ESDHC_PBL) += imx-esdhc-pbl.o imx-esdhc-common.o
obj-$(CONFIG_MCI_MXS) += mxs.o
obj-$(CONFIG_MCI_OMAP_HSMMC) += omap_hsmmc.o omap_hsmmc_common.o
+pbl-$(CONFIG_MCI_OMAP_HSMMC_PBL) += omap_hsmmc_pbl.o omap_hsmmc_common.o
obj-$(CONFIG_MCI_PXA) += pxamci.o
obj-$(CONFIG_MCI_ROCKCHIP_DWCMSHC) += rockchip-dwcmshc-sdhci.o
obj-$(CONFIG_MCI_TEGRA) += tegra-sdmmc.o
diff --git a/drivers/mci/omap_hsmmc_common.c b/drivers/mci/omap_hsmmc_common.c
index 04c712460622..329908a6e4bd 100644
--- a/drivers/mci/omap_hsmmc_common.c
+++ b/drivers/mci/omap_hsmmc_common.c
@@ -468,7 +468,7 @@ int omap_hsmmc_send_cmd(struct omap_hsmmc *hsmmc, struct mci_cmd *cmd,
return mmc_read_data(hsmmc, data->dest,
data->blocksize * data->blocks);
- if (IS_ENABLED(CONFIG_MCI_WRITE))
+ if (IS_ENABLED(CONFIG_MCI_WRITE) && IN_PROPER)
return mmc_write_data(hsmmc, data->src,
data->blocksize * data->blocks);
diff --git a/drivers/mci/omap_hsmmc_pbl.c b/drivers/mci/omap_hsmmc_pbl.c
new file mode 100644
index 000000000000..0e6f39859d24
--- /dev/null
+++ b/drivers/mci/omap_hsmmc_pbl.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2008 Texas Instruments (http://www.ti.com/, Sukumar Ghorai <s-ghorai@ti.com>)
+
+#include <pbl/mci.h>
+#include <pbl/bio.h>
+#include <mci.h>
+#include <debug_ll.h>
+#include <mach/omap/xload.h>
+
+#include "omap_hsmmc.h"
+
+static int pbl_omap_hsmmc_send_cmd(struct pbl_mci *mci,
+ struct mci_cmd *cmd,
+ struct mci_data *data)
+{
+ return omap_hsmmc_send_cmd(mci->priv, cmd, data);
+}
+
+static struct omap_hsmmc hsmmc;
+static struct pbl_mci mci;
+
+int omap_hsmmc_bio_init(struct pbl_bio *bio, void __iomem *iobase,
+ unsigned reg_ofs)
+{
+ hsmmc.iobase = iobase;
+ hsmmc.base = iobase + reg_ofs;
+
+ mci.priv = &hsmmc;
+ mci.send_cmd = pbl_omap_hsmmc_send_cmd;
+
+ return pbl_mci_bio_init(&mci, bio);
+}
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 9/9] ARM: OMAP: beaglebone: add PBL SD xload support
2025-04-22 5:26 [PATCH 0/9] ARM: OMAP: beaglebone: add PBL SD xload support Ahmad Fatoum
` (7 preceding siblings ...)
2025-04-22 5:26 ` [PATCH 8/9] mci: omap_hsmmc: add xload implementation " Ahmad Fatoum
@ 2025-04-22 5:26 ` Ahmad Fatoum
2025-04-22 10:55 ` [PATCH 0/9] " Sascha Hauer
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2025-04-22 5:26 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
From: Ahmad Fatoum <a.fatoum@barebox.org>
The existing "full" MLO image supports multiple boot media at once, but
the newcomer SD/MMC only image has the advantage of doing so in the same
build alongside barebox second stage.
This makes for easier integration in BSPs, so provide it as extra image
if CONFIG_OMAP_BUILD_IFT is disabled.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/boards/beaglebone/lowlevel.c | 10 ++++++----
arch/arm/mach-omap/Kconfig | 8 ++++++--
images/Makefile.am33xx | 4 ++++
3 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/arch/arm/boards/beaglebone/lowlevel.c b/arch/arm/boards/beaglebone/lowlevel.c
index fec4f177781c..05764fc9138b 100644
--- a/arch/arm/boards/beaglebone/lowlevel.c
+++ b/arch/arm/boards/beaglebone/lowlevel.c
@@ -16,6 +16,7 @@
#include <mach/omap/syslib.h>
#include <mach/omap/am33xx-mux.h>
#include <mach/omap/am33xx-generic.h>
+#include <mach/omap/xload.h>
#include "beaglebone.h"
@@ -116,9 +117,6 @@ static void __udelay(int us)
static noinline int beaglebone_sram_init(void)
{
uint32_t sdram_size;
- void *fdt;
-
- fdt = __dtb_z_am335x_bone_common_start;
if (is_beaglebone_black())
sdram_size = SZ_512M;
@@ -150,7 +148,11 @@ static noinline int beaglebone_sram_init(void)
*/
__udelay(3000);
- barebox_arm_entry(OMAP_DRAM_ADDR_SPACE_START, sdram_size, fdt);
+ if (IS_ENABLED(CONFIG_OMAP_BUILD_IFT))
+ barebox_arm_entry(OMAP_DRAM_ADDR_SPACE_START, sdram_size,
+ __dtb_z_am335x_bone_common_start);
+ else
+ am33xx_hsmmc_start_image();
}
ENTRY_FUNCTION(start_am33xx_beaglebone_sram, bootinfo, r1, r2)
diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
index e7a9b331125d..bf2ab75eaf68 100644
--- a/arch/arm/mach-omap/Kconfig
+++ b/arch/arm/mach-omap/Kconfig
@@ -60,12 +60,15 @@ config OMAP_GPMC
NAND, OneNAND etc.
config OMAP_BUILD_IFT
- prompt "build ift binary (MLO)"
+ prompt "build ift binaries (MLO) only"
bool
help
- Say Y here if you want to build an MLO binary. On TI SoCs, this
+ Say Y here if you want to build only MLO binaries. On TI SoCs, this
binary is loaded to SRAM. It is responsible for initializing
the SDRAM and possibly chainloading a full-featured barebox.
+ If you say n here, barebox may still generate extra MLO binaries
+ alongside second stage barebox binaries, but these are currently
+ limited to only specific bootmedia as indicated in their file name.
config OMAP_BUILD_SPI
prompt "build SPI binary"
@@ -153,6 +156,7 @@ config MACH_BEAGLE
config MACH_BEAGLEBONE
bool "Texas Instrument's Beagle Bone"
select ARCH_AM33XX
+ select MCI_OMAP_HSMMC_PBL
help
Say Y here if you are using Beagle Bone
diff --git a/images/Makefile.am33xx b/images/Makefile.am33xx
index a63def771ed3..2a1cf3a0c40b 100644
--- a/images/Makefile.am33xx
+++ b/images/Makefile.am33xx
@@ -132,6 +132,10 @@ pblb-$(CONFIG_MACH_BEAGLEBONE) += start_am33xx_beaglebone_sdram
FILE_barebox-am33xx-beaglebone.img = start_am33xx_beaglebone_sdram.pblb
am33xx-barebox-$(CONFIG_MACH_BEAGLEBONE) += barebox-am33xx-beaglebone.img
+pblb-$(CONFIG_MACH_BEAGLEBONE) += start_am33xx_beaglebone_sram
+FILE_barebox-am33xx-beaglebone-mlo.mmc.img = start_am33xx_beaglebone_sram.pblb.mlo
+am33xx-barebox-$(CONFIG_MACH_BEAGLEBONE) += barebox-am33xx-beaglebone-mlo.mmc.img
+
pblb-$(CONFIG_MACH_BEAGLEBONE) += start_am33xx_beaglebone_sram
FILE_barebox-am33xx-beaglebone-mlo.img = start_am33xx_beaglebone_sram.pblb.mlo
am33xx-mlo-$(CONFIG_MACH_BEAGLEBONE) += barebox-am33xx-beaglebone-mlo.img
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 0/9] ARM: OMAP: beaglebone: add PBL SD xload support
2025-04-22 5:26 [PATCH 0/9] ARM: OMAP: beaglebone: add PBL SD xload support Ahmad Fatoum
` (8 preceding siblings ...)
2025-04-22 5:26 ` [PATCH 9/9] ARM: OMAP: beaglebone: add PBL SD xload support Ahmad Fatoum
@ 2025-04-22 10:55 ` Sascha Hauer
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2025-04-22 10:55 UTC (permalink / raw)
To: barebox, Ahmad Fatoum
On Tue, 22 Apr 2025 07:26:26 +0200, Ahmad Fatoum wrote:
> To allow for easier BSP integration, add support for generating a MLO
> capable of SD-Card boot in the same build as barebox proper
>
> For raw flash boot, the route with the separate config needs to be used.
>
> Ahmad Fatoum (9):
> clocksource: make available in PBL
> clocksource: ti-dm: make available in PBL
> mci: move mci_setup_cmd definition into header
> mci: add common PBL helper for chainloading after BootROM
> initialization
> mci: pbl: add autodetection of BootROM-initialized standard capacity
> cards
> mci: omap_hsmmc: split out common code
> ARM: OMAP: add am33xx_hsmmc_start_image for PBL
> mci: omap_hsmmc: add xload implementation for PBL
> ARM: OMAP: beaglebone: add PBL SD xload support
>
> [...]
Applied, thanks!
[1/9] clocksource: make available in PBL
https://git.pengutronix.de/cgit/barebox/commit/?id=adfc76dd5cbc (link may not be stable)
[2/9] clocksource: ti-dm: make available in PBL
https://git.pengutronix.de/cgit/barebox/commit/?id=74e2dadcd5e4 (link may not be stable)
[3/9] mci: move mci_setup_cmd definition into header
https://git.pengutronix.de/cgit/barebox/commit/?id=c8d7bb92a1e8 (link may not be stable)
[4/9] mci: add common PBL helper for chainloading after BootROM initialization
https://git.pengutronix.de/cgit/barebox/commit/?id=12bf28066aed (link may not be stable)
[5/9] mci: pbl: add autodetection of BootROM-initialized standard capacity cards
https://git.pengutronix.de/cgit/barebox/commit/?id=0801b7e1612c (link may not be stable)
[6/9] mci: omap_hsmmc: split out common code
https://git.pengutronix.de/cgit/barebox/commit/?id=7a67a40d2b10 (link may not be stable)
[7/9] ARM: OMAP: add am33xx_hsmmc_start_image for PBL
https://git.pengutronix.de/cgit/barebox/commit/?id=407324f655b4 (link may not be stable)
[8/9] mci: omap_hsmmc: add xload implementation for PBL
https://git.pengutronix.de/cgit/barebox/commit/?id=ccd09cb1980b (link may not be stable)
[9/9] ARM: OMAP: beaglebone: add PBL SD xload support
https://git.pengutronix.de/cgit/barebox/commit/?id=69d6ac58f2cb (link may not be stable)
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 11+ messages in thread