The MMCI variants do not all expose the same FIFO capacity. The ARM
PL180 can transfer 16 words when the FIFO is full or empty, STM32 can
transfer 32 words, and Ux500 can transfer 30 words. Their half-full and
half-empty conditions guarantee eight words.

Store the full and half FIFO sizes in the host according to the
peripheral ID. Use the full size when the corresponding full or empty
status is asserted and otherwise retain the half-size burst. This
reduces the number of status polls and bulk I/O operations where the
larger FIFO capacity is available.

Signed-off-by: Linus Walleij <[email protected]>
---
 drivers/mmc/arm_pl180_mmci.c | 47 ++++++++++++++++++++++++++------------------
 drivers/mmc/arm_pl180_mmci.h |  7 ++++++-
 2 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c
index 7d58c64df11d..31efa7576ff5 100644
--- a/drivers/mmc/arm_pl180_mmci.c
+++ b/drivers/mmc/arm_pl180_mmci.c
@@ -143,6 +143,7 @@ static int read_bytes(struct mmc *dev, u32 *dest, u32 
blkcount, u32 blksize)
        u32 *tempbuff = dest;
        u64 xfercount = blkcount * blksize;
        struct pl180_mmc_host *host = dev->priv;
+       unsigned int count;
        u32 status, status_err;
 
        debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
@@ -150,13 +151,18 @@ static int read_bytes(struct mmc *dev, u32 *dest, u32 
blkcount, u32 blksize)
        status = readl(&host->base->status);
        status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT |
                               SDI_STA_RXOVERR);
-       while (!status_err &&
-              xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32)) {
-               if (status & SDI_STA_RXFIFOBR) {
+       while (!status_err && xfercount >= host->fifo_half_size) {
+               count = 0;
+               if (status & SDI_STA_RXFIFOF)
+                       count = min_t(u64, xfercount, host->fifo_size);
+               else if (status & SDI_STA_RXFIFOBR)
+                       count = host->fifo_half_size;
+
+               if (count) {
                        readsl(&host->base->fifo, tempbuff,
-                              SDI_FIFO_BURST_SIZE);
-                       tempbuff += SDI_FIFO_BURST_SIZE;
-                       xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32);
+                              count / sizeof(u32));
+                       tempbuff += count / sizeof(u32);
+                       xfercount -= count;
                }
                status = readl(&host->base->status);
                status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT |
@@ -211,6 +217,7 @@ static int write_bytes(struct mmc *dev, u32 *src, u32 
blkcount, u32 blksize)
        u32 *tempbuff = src;
        u64 xfercount = blkcount * blksize;
        struct pl180_mmc_host *host = dev->priv;
+       unsigned int count;
        u32 status, status_err;
 
        debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
@@ -218,19 +225,17 @@ static int write_bytes(struct mmc *dev, u32 *src, u32 
blkcount, u32 blksize)
        status = readl(&host->base->status);
        status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
        while (!status_err && xfercount) {
-               if (status & SDI_STA_TXFIFOBW) {
-                       if (xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32)) {
-                               writesl(&host->base->fifo, tempbuff,
-                                       SDI_FIFO_BURST_SIZE);
-                               tempbuff += SDI_FIFO_BURST_SIZE;
-                               xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32);
-                       } else {
-                               while (xfercount >= sizeof(u32)) {
-                                       writel(*(tempbuff), &host->base->fifo);
-                                       tempbuff++;
-                                       xfercount -= sizeof(u32);
-                               }
-                       }
+               count = 0;
+               if (status & SDI_STA_TXFIFOE)
+                       count = min_t(u64, xfercount, host->fifo_size);
+               else if (status & SDI_STA_TXFIFOBW)
+                       count = min_t(u64, xfercount, host->fifo_half_size);
+
+               if (count) {
+                       writesl(&host->base->fifo, tempbuff,
+                               count / sizeof(u32));
+                       tempbuff += count / sizeof(u32);
+                       xfercount -= count;
                }
                status = readl(&host->base->status);
                status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
@@ -451,6 +456,8 @@ static int arm_pl180_mmc_probe(struct udevice *dev)
        host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN |
                            SDI_CLKCR_PWRSAV | SDI_CLKCR_HWFC_EN;
        host->clock_in = clk_get_rate(&clk);
+       host->fifo_size = SDI_FIFO_SIZE_ARM;
+       host->fifo_half_size = SDI_FIFO_HALF_SIZE;
 
        cfg->name = dev->name;
        cfg->voltages = VOLTAGE_WINDOW_SD;
@@ -462,9 +469,11 @@ static int arm_pl180_mmc_probe(struct udevice *dev)
        periphid = dev_read_u32_default(dev, "arm,primecell-periphid", 0);
        switch (periphid) {
        case STM32_MMCI_ID: /* stm32 variant */
+               host->fifo_size = SDI_FIFO_SIZE_STM32;
                host->version2 = false;
                break;
        case UX500V2_MMCI_ID:
+               host->fifo_size = SDI_FIFO_SIZE_UX500;
                host->pwr_init = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON;
                host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V2 | SDI_CLKCR_CLKEN |
                                    SDI_CLKCR_PWRSAV | SDI_CLKCR_HWFC_EN;
diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h
index fca15910a8db..92057c18f55e 100644
--- a/drivers/mmc/arm_pl180_mmci.h
+++ b/drivers/mmc/arm_pl180_mmci.h
@@ -140,7 +140,10 @@
 #define SDI_DCTRL_DBLOCKSIZE_V2_MASK   0x7fff0000
 #define SDI_DCTRL_DBLOCKSIZE_V2_SHIFT  16
 
-#define SDI_FIFO_BURST_SIZE    8
+#define SDI_FIFO_SIZE_ARM      (16 * sizeof(u32))
+#define SDI_FIFO_SIZE_STM32    (32 * sizeof(u32))
+#define SDI_FIFO_SIZE_UX500    (30 * sizeof(u32))
+#define SDI_FIFO_HALF_SIZE     (8 * sizeof(u32))
 
 #define STM32_MMCI_ID          0x00880180
 #define UX500V2_MMCI_ID                0x10480180
@@ -189,6 +192,8 @@ struct pl180_mmc_host {
        unsigned int clock_max;
        unsigned int clkdiv_init;
        unsigned int pwr_init;
+       unsigned int fifo_size;
+       unsigned int fifo_half_size;
        int version2;
        struct mmc_config cfg;
 #ifdef CONFIG_DM_MMC

-- 
2.55.0

Reply via email to