spi: meson-spicc: setup IO line delay
authorNeil Armstrong <narmstrong@baylibre.com>
Thu, 12 Mar 2020 13:31:28 +0000 (14:31 +0100)
committerMark Brown <broonie@kernel.org>
Thu, 12 Mar 2020 17:22:53 +0000 (17:22 +0000)
Now the controller can support frequencies higher than 30MHz, we need
the setup the I/O line delays in regard of the SPI clock frequency.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Link: https://lore.kernel.org/r/20200312133131.26430-7-narmstrong@baylibre.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-meson-spicc.c

index b5bd3a897e8fba20f0a6669299b7b12bac7f6bc8..4494a791f4a706f1dd6b868f89c14055e496c581 100644 (file)
 #define SPICC_SWAP_RO          BIT(14) /* RX FIFO Data Swap Read-Only */
 #define SPICC_SWAP_W1          BIT(15) /* RX FIFO Data Swap Write-Only */
 #define SPICC_DLYCTL_RO_MASK   GENMASK(20, 15) /* Delay Control Read-Only */
-#define SPICC_DLYCTL_W1_MASK   GENMASK(21, 16) /* Delay Control Write-Only */
+#define SPICC_MO_DELAY_MASK    GENMASK(17, 16) /* Master Output Delay */
+#define SPICC_MO_NO_DELAY      0
+#define SPICC_MO_DELAY_1_CYCLE 1
+#define SPICC_MO_DELAY_2_CYCLE 2
+#define SPICC_MO_DELAY_3_CYCLE 3
+#define SPICC_MI_DELAY_MASK    GENMASK(19, 18) /* Master Input Delay */
+#define SPICC_MI_NO_DELAY      0
+#define SPICC_MI_DELAY_1_CYCLE 1
+#define SPICC_MI_DELAY_2_CYCLE 2
+#define SPICC_MI_DELAY_3_CYCLE 3
+#define SPICC_MI_CAP_DELAY_MASK        GENMASK(21, 20) /* Master Capture Delay */
+#define SPICC_CAP_AHEAD_2_CYCLE        0
+#define SPICC_CAP_AHEAD_1_CYCLE        1
+#define SPICC_CAP_NO_DELAY     2
+#define SPICC_CAP_DELAY_1_CYCLE        3
 #define SPICC_FIFORST_RO_MASK  GENMASK(22, 21) /* FIFO Softreset Read-Only */
 #define SPICC_FIFORST_W1_MASK  GENMASK(23, 22) /* FIFO Softreset Write-Only */
 
@@ -328,6 +342,49 @@ static irqreturn_t meson_spicc_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static void meson_spicc_auto_io_delay(struct meson_spicc_device *spicc)
+{
+       u32 div, hz;
+       u32 mi_delay, cap_delay;
+       u32 conf;
+
+       if (spicc->data->has_enhance_clk_div) {
+               div = FIELD_GET(SPICC_ENH_DATARATE_MASK,
+                               readl_relaxed(spicc->base + SPICC_ENH_CTL0));
+               div++;
+               div <<= 1;
+       } else {
+               div = FIELD_GET(SPICC_DATARATE_MASK,
+                               readl_relaxed(spicc->base + SPICC_CONREG));
+               div += 2;
+               div = 1 << div;
+       }
+
+       mi_delay = SPICC_MI_NO_DELAY;
+       cap_delay = SPICC_CAP_AHEAD_2_CYCLE;
+       hz = clk_get_rate(spicc->clk);
+
+       if (hz >= 100000000)
+               cap_delay = SPICC_CAP_DELAY_1_CYCLE;
+       else if (hz >= 80000000)
+               cap_delay = SPICC_CAP_NO_DELAY;
+       else if (hz >= 40000000)
+               cap_delay = SPICC_CAP_AHEAD_1_CYCLE;
+       else if (div >= 16)
+               mi_delay = SPICC_MI_DELAY_3_CYCLE;
+       else if (div >= 8)
+               mi_delay = SPICC_MI_DELAY_2_CYCLE;
+       else if (div >= 6)
+               mi_delay = SPICC_MI_DELAY_1_CYCLE;
+
+       conf = readl_relaxed(spicc->base + SPICC_TESTREG);
+       conf &= ~(SPICC_MO_DELAY_MASK | SPICC_MI_DELAY_MASK
+                 | SPICC_MI_CAP_DELAY_MASK);
+       conf |= FIELD_PREP(SPICC_MI_DELAY_MASK, mi_delay);
+       conf |= FIELD_PREP(SPICC_MI_CAP_DELAY_MASK, cap_delay);
+       writel_relaxed(conf, spicc->base + SPICC_TESTREG);
+}
+
 static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc,
                                   struct spi_transfer *xfer)
 {
@@ -346,6 +403,8 @@ static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc,
                writel_relaxed(conf, spicc->base + SPICC_CONREG);
 
        clk_set_rate(spicc->clk, xfer->speed_hz);
+
+       meson_spicc_auto_io_delay(spicc);
 }
 
 static int meson_spicc_transfer_one(struct spi_master *master,