]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
mmc: mtk-sd: Aggregate writes for MSDC_PATCH_BIT1/2 setup
authorAngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tue, 25 Mar 2025 11:06:59 +0000 (12:06 +0100)
committerUlf Hansson <ulf.hansson@linaro.org>
Wed, 14 May 2025 14:59:16 +0000 (16:59 +0200)
Instead of continuously reading and writing to the patch bit 1/2
registers, prepare the final values to write to those and write
just once per register during the setup phase.

This makes the driver slightly smaller and also slightly improves
the execution time of the msdc_init_hw function, called not only
at probe time, but also when resuming from system suspend.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Link: https://lore.kernel.org/r/20250325110701.52623-3-angelogioacchino.delregno@collabora.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/mtk-sd.c

index 04471a7ef0782895c2b13b7a23f31d54e75f8e35..dd3f7468d32c562abf695e249d60318e57360f31 100644 (file)
@@ -1831,7 +1831,7 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
 
 static void msdc_init_hw(struct msdc_host *host)
 {
-       u32 val, pb1_val;
+       u32 val, pb1_val, pb2_val;
        u32 tune_reg = host->dev_comp->pad_tune_reg;
        struct mmc_host *mmc = mmc_from_priv(host);
 
@@ -1885,6 +1885,13 @@ static void msdc_init_hw(struct msdc_host *host)
        writel(0, host->base + MSDC_IOCON);
        sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0);
 
+       /*
+        * Patch bit 0 and 1 are completely rewritten, but for patch bit 2
+        * defaults are retained and, if necessary, only some bits are fixed
+        * up: read the PB2 register here for later usage in this function.
+        */
+       pb2_val = readl(host->base + MSDC_PATCH_BIT2);
+
        /* Enable odd number support for 8-bit data bus */
        val = MSDC_PATCH_BIT_ODDSUPP;
 
@@ -1902,6 +1909,8 @@ static void msdc_init_hw(struct msdc_host *host)
 
        /* Set CKGEN delay to one stage */
        val |= FIELD_PREP(MSDC_CKGEN_MSDC_DLY_SEL, 1);
+
+       /* First MSDC_PATCH_BIT setup is done: pull the trigger! */
        writel(val, host->base + MSDC_PATCH_BIT);
 
        /* Set wr data, crc status, cmd response turnaround period for UHS104 */
@@ -1917,58 +1926,54 @@ static void msdc_init_hw(struct msdc_host *host)
        pb1_val |= MSDC_PB1_LP_DCM_EN | MSDC_PB1_RSVD3 |
                   MSDC_PB1_AHB_GDMA_HCLK | MSDC_PB1_MSDC_CLK_ENFEAT;
 
-       /* Enable R1b command busy check */
-       pb1_val |= MSDC_PB1_BUSY_CHECK_SEL;
-       writel(pb1_val, host->base + MSDC_PATCH_BIT1);
-
-       sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL);
+       /* If needed, enable R1b command busy check at controller init time */
+       if (!host->dev_comp->busy_check)
+               pb1_val |= MSDC_PB1_BUSY_CHECK_SEL;
 
        if (host->dev_comp->stop_clk_fix) {
                if (host->dev_comp->stop_dly_sel)
-                       sdr_set_field(host->base + MSDC_PATCH_BIT1,
-                                     MSDC_PATCH_BIT1_STOP_DLY,
-                                     host->dev_comp->stop_dly_sel);
+                       pb1_val |= FIELD_PREP(MSDC_PATCH_BIT1_STOP_DLY,
+                                             host->dev_comp->stop_dly_sel);
 
-               if (host->dev_comp->pop_en_cnt)
-                       sdr_set_field(host->base + MSDC_PATCH_BIT2,
-                                     MSDC_PB2_POP_EN_CNT,
-                                     host->dev_comp->pop_en_cnt);
+               if (host->dev_comp->pop_en_cnt) {
+                       pb2_val &= ~MSDC_PB2_POP_EN_CNT;
+                       pb2_val |= FIELD_PREP(MSDC_PB2_POP_EN_CNT,
+                                             host->dev_comp->pop_en_cnt);
+               }
 
-               sdr_clr_bits(host->base + SDC_FIFO_CFG,
-                            SDC_FIFO_CFG_WRVALIDSEL);
-               sdr_clr_bits(host->base + SDC_FIFO_CFG,
-                            SDC_FIFO_CFG_RDVALIDSEL);
+               sdr_clr_bits(host->base + SDC_FIFO_CFG, SDC_FIFO_CFG_WRVALIDSEL);
+               sdr_clr_bits(host->base + SDC_FIFO_CFG, SDC_FIFO_CFG_RDVALIDSEL);
        }
 
-       if (host->dev_comp->busy_check)
-               sdr_clr_bits(host->base + MSDC_PATCH_BIT1, BIT(7));
-
        if (host->dev_comp->async_fifo) {
-               sdr_set_field(host->base + MSDC_PATCH_BIT2,
-                             MSDC_PB2_RESPWAIT, 3);
-               if (host->dev_comp->enhance_rx) {
-                       if (host->top_base)
-                               sdr_set_bits(host->top_base + EMMC_TOP_CONTROL,
-                                            SDC_RX_ENH_EN);
-                       else
-                               sdr_set_bits(host->base + SDC_ADV_CFG0,
-                                            SDC_RX_ENHANCE_EN);
+               /* Set CMD response timeout multiplier to 65 + (16 * 3) cycles */
+               pb2_val &= ~MSDC_PB2_RESPWAIT;
+               pb2_val |= FIELD_PREP(MSDC_PB2_RESPWAIT, 3);
+
+               /* eMMC4.5: Select async FIFO path for CMD resp and CRC status */
+               pb2_val &= ~MSDC_PATCH_BIT2_CFGRESP;
+               pb2_val |= MSDC_PATCH_BIT2_CFGCRCSTS;
+
+               if (!host->dev_comp->enhance_rx) {
+                       /* eMMC4.5: Delay 2T for CMD resp and CRC status EN signals */
+                       pb2_val &= ~(MSDC_PB2_RESPSTSENSEL | MSDC_PB2_CRCSTSENSEL);
+                       pb2_val |= FIELD_PREP(MSDC_PB2_RESPSTSENSEL, 2);
+                       pb2_val |= FIELD_PREP(MSDC_PB2_CRCSTSENSEL, 2);
+               } else if (host->top_base) {
+                       sdr_set_bits(host->top_base + EMMC_TOP_CONTROL, SDC_RX_ENH_EN);
                } else {
-                       sdr_set_field(host->base + MSDC_PATCH_BIT2,
-                                     MSDC_PB2_RESPSTSENSEL, 2);
-                       sdr_set_field(host->base + MSDC_PATCH_BIT2,
-                                     MSDC_PB2_CRCSTSENSEL, 2);
+                       sdr_set_bits(host->base + SDC_ADV_CFG0, SDC_RX_ENHANCE_EN);
                }
-               /* use async fifo, then no need tune internal delay */
-               sdr_clr_bits(host->base + MSDC_PATCH_BIT2,
-                            MSDC_PATCH_BIT2_CFGRESP);
-               sdr_set_bits(host->base + MSDC_PATCH_BIT2,
-                            MSDC_PATCH_BIT2_CFGCRCSTS);
        }
 
        if (host->dev_comp->support_64g)
-               sdr_set_bits(host->base + MSDC_PATCH_BIT2,
-                            MSDC_PB2_SUPPORT_64G);
+               pb2_val |= MSDC_PB2_SUPPORT_64G;
+
+       /* Patch Bit 1/2 setup is done: pull the trigger! */
+       writel(pb1_val, host->base + MSDC_PATCH_BIT1);
+       writel(pb2_val, host->base + MSDC_PATCH_BIT2);
+       sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL);
+
        if (host->dev_comp->data_tune) {
                if (host->top_base) {
                        sdr_set_bits(host->top_base + EMMC_TOP_CONTROL,