+++ /dev/null
-From 160cc587decac38e0f28f1583412a987a70450e9 Mon Sep 17 00:00:00 2001
-From: Maksim Kiselev <bigunclemax@gmail.com>
-Date: Wed, 10 May 2023 11:11:08 +0300
-Subject: [PATCH 7/9] dt-bindings: spi: sun6i: add DT bindings for Allwinner
- R329/D1/R528/T113s SPI
-
-Listed above Allwinner SoCs has two SPI controllers. First is the regular
-SPI controller and the second one has additional functionality for
-MIPI-DBI Type C.
-
-Add compatible strings for these controllers
-
-Signed-off-by: Maksim Kiselev <bigunclemax@gmail.com>
-Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Reviewed-by: Andre Przywara <andre.przywara@arm.com>
-Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com>
----
- .../bindings/spi/allwinner,sun6i-a31-spi.yaml | 10 ++
- .../boot/dts/allwinner/sunxi-d1s-t113.dtsi | 37 +++++
- drivers/spi/spi-sun6i.c | 131 ++++++++++++------
- 3 files changed, 138 insertions(+), 40 deletions(-)
-
-diff --git a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
-index 58b7056f4a70..95939684a00d 100644
---- a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
-+++ b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
-@@ -19,6 +19,7 @@ properties:
-
- compatible:
- oneOf:
-+ - const: allwinner,sun50i-r329-spi
- - const: allwinner,sun6i-a31-spi
- - const: allwinner,sun8i-h3-spi
- - items:
-@@ -28,6 +29,15 @@ properties:
- - allwinner,sun50i-h616-spi
- - allwinner,suniv-f1c100s-spi
- - const: allwinner,sun8i-h3-spi
-+ - items:
-+ - enum:
-+ - allwinner,sun20i-d1-spi
-+ - allwinner,sun50i-r329-spi-dbi
-+ - const: allwinner,sun50i-r329-spi
-+ - items:
-+ - const: allwinner,sun20i-d1-spi-dbi
-+ - const: allwinner,sun50i-r329-spi-dbi
-+ - const: allwinner,sun50i-r329-spi
-
- reg:
- maxItems: 1
-diff --git a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
-index 3723612b1fd8..6efff8f41e00 100644
---- a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
-+++ b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
-@@ -108,6 +108,12 @@
- function = "emac";
- };
-
-+ /omit-if-no-ref/
-+ spi0_pins: spi0-pins {
-+ pins = "PC2", "PC3", "PC4", "PC5";
-+ function = "spi0";
-+ };
-+
- /omit-if-no-ref/
- uart1_pg6_pins: uart1-pg6-pins {
- pins = "PG6", "PG7";
-@@ -435,6 +441,37 @@
- #size-cells = <0>;
- };
-
-+ spi0: spi@4025000 {
-+ compatible = "allwinner,sun20i-d1-spi",
-+ "allwinner,sun50i-r329-spi";
-+ reg = <0x04025000 0x1000>;
-+ interrupts = <SOC_PERIPHERAL_IRQ(15) IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
-+ clock-names = "ahb", "mod";
-+ dmas = <&dma 22>, <&dma 22>;
-+ dma-names = "rx", "tx";
-+ resets = <&ccu RST_BUS_SPI0>;
-+ status = "disabled";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ };
-+
-+ spi1: spi@4026000 {
-+ compatible = "allwinner,sun20i-d1-spi-dbi",
-+ "allwinner,sun50i-r329-spi-dbi",
-+ "allwinner,sun50i-r329-spi";
-+ reg = <0x04026000 0x1000>;
-+ interrupts = <SOC_PERIPHERAL_IRQ(16) IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
-+ clock-names = "ahb", "mod";
-+ dmas = <&dma 23>, <&dma 23>;
-+ dma-names = "rx", "tx";
-+ resets = <&ccu RST_BUS_SPI1>;
-+ status = "disabled";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ };
-+
- usb_otg: usb@4100000 {
- compatible = "allwinner,sun20i-d1-musb",
- "allwinner,sun8i-a33-musb";
-diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
-index 23ad052528db..4f32cd99a81e 100644
---- a/drivers/spi/spi-sun6i.c
-+++ b/drivers/spi/spi-sun6i.c
-@@ -42,7 +42,9 @@
- #define SUN6I_TFR_CTL_CS_MANUAL BIT(6)
- #define SUN6I_TFR_CTL_CS_LEVEL BIT(7)
- #define SUN6I_TFR_CTL_DHB BIT(8)
-+#define SUN6I_TFR_CTL_SDC BIT(11)
- #define SUN6I_TFR_CTL_FBS BIT(12)
-+#define SUN6I_TFR_CTL_SDM BIT(13)
- #define SUN6I_TFR_CTL_XCH BIT(31)
-
- #define SUN6I_INT_CTL_REG 0x10
-@@ -85,6 +87,11 @@
- #define SUN6I_TXDATA_REG 0x200
- #define SUN6I_RXDATA_REG 0x300
-
-+struct sun6i_spi_cfg {
-+ unsigned long fifo_depth;
-+ bool has_clk_ctl;
-+};
-+
- struct sun6i_spi {
- struct spi_master *master;
- void __iomem *base_addr;
-@@ -99,7 +106,7 @@ struct sun6i_spi {
- const u8 *tx_buf;
- u8 *rx_buf;
- int len;
-- unsigned long fifo_depth;
-+ const struct sun6i_spi_cfg *cfg;
- };
-
- static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg)
-@@ -156,7 +163,7 @@ static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi)
- u8 byte;
-
- /* See how much data we can fit */
-- cnt = sspi->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi);
-+ cnt = sspi->cfg->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi);
-
- len = min((int)cnt, sspi->len);
-
-@@ -256,7 +263,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
- struct spi_transfer *tfr)
- {
- struct sun6i_spi *sspi = spi_master_get_devdata(master);
-- unsigned int mclk_rate, div, div_cdr1, div_cdr2, timeout;
-+ unsigned int div, div_cdr1, div_cdr2, timeout;
- unsigned int start, end, tx_time;
- unsigned int trig_level;
- unsigned int tx_len = 0, rx_len = 0;
-@@ -289,14 +296,14 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
- * the hardcoded value used in old generation of Allwinner
- * SPI controller. (See spi-sun4i.c)
- */
-- trig_level = sspi->fifo_depth / 4 * 3;
-+ trig_level = sspi->cfg->fifo_depth / 4 * 3;
- } else {
- /*
- * Setup FIFO DMA request trigger level
- * We choose 1/2 of the full fifo depth, that value will
- * be used as DMA burst length.
- */
-- trig_level = sspi->fifo_depth / 2;
-+ trig_level = sspi->cfg->fifo_depth / 2;
-
- if (tfr->tx_buf)
- reg |= SUN6I_FIFO_CTL_TF_DRQ_EN;
-@@ -346,39 +353,65 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
-
- sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
-
-- /* Ensure that we have a parent clock fast enough */
-- mclk_rate = clk_get_rate(sspi->mclk);
-- if (mclk_rate < (2 * tfr->speed_hz)) {
-- clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
-- mclk_rate = clk_get_rate(sspi->mclk);
-- }
-+ if (sspi->cfg->has_clk_ctl) {
-+ unsigned int mclk_rate = clk_get_rate(sspi->mclk);
-
-- /*
-- * Setup clock divider.
-- *
-- * We have two choices there. Either we can use the clock
-- * divide rate 1, which is calculated thanks to this formula:
-- * SPI_CLK = MOD_CLK / (2 ^ cdr)
-- * Or we can use CDR2, which is calculated with the formula:
-- * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
-- * Wether we use the former or the latter is set through the
-- * DRS bit.
-- *
-- * First try CDR2, and if we can't reach the expected
-- * frequency, fall back to CDR1.
-- */
-- div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
-- div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
-- if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
-- reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
-- tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
-+ /* Ensure that we have a parent clock fast enough */
-+ if (mclk_rate < (2 * tfr->speed_hz)) {
-+ clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
-+ mclk_rate = clk_get_rate(sspi->mclk);
-+ }
-+
-+ /*
-+ * Setup clock divider.
-+ *
-+ * We have two choices there. Either we can use the clock
-+ * divide rate 1, which is calculated thanks to this formula:
-+ * SPI_CLK = MOD_CLK / (2 ^ cdr)
-+ * Or we can use CDR2, which is calculated with the formula:
-+ * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
-+ * Wether we use the former or the latter is set through the
-+ * DRS bit.
-+ *
-+ * First try CDR2, and if we can't reach the expected
-+ * frequency, fall back to CDR1.
-+ */
-+ div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
-+ div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
-+ if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
-+ reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
-+ tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
-+ } else {
-+ div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
-+ reg = SUN6I_CLK_CTL_CDR1(div);
-+ tfr->effective_speed_hz = mclk_rate / (1 << div);
-+ }
-+
-+ sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
- } else {
-- div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
-- reg = SUN6I_CLK_CTL_CDR1(div);
-- tfr->effective_speed_hz = mclk_rate / (1 << div);
-+ clk_set_rate(sspi->mclk, tfr->speed_hz);
-+ tfr->effective_speed_hz = clk_get_rate(sspi->mclk);
-+
-+ /*
-+ * Configure work mode.
-+ *
-+ * There are three work modes depending on the controller clock
-+ * frequency:
-+ * - normal sample mode : CLK <= 24MHz SDM=1 SDC=0
-+ * - delay half-cycle sample mode : CLK <= 40MHz SDM=0 SDC=0
-+ * - delay one-cycle sample mode : CLK >= 80MHz SDM=0 SDC=1
-+ */
-+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
-+ reg &= ~(SUN6I_TFR_CTL_SDM | SUN6I_TFR_CTL_SDC);
-+
-+ if (tfr->effective_speed_hz <= 24000000)
-+ reg |= SUN6I_TFR_CTL_SDM;
-+ else if (tfr->effective_speed_hz >= 80000000)
-+ reg |= SUN6I_TFR_CTL_SDC;
-+
-+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
- }
-
-- sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
- /* Finally enable the bus - doing so before might raise SCK to HIGH */
- reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG);
- reg |= SUN6I_GBL_CTL_BUS_ENABLE;
-@@ -410,9 +443,9 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
- reg = SUN6I_INT_CTL_TC;
-
- if (!use_dma) {
-- if (rx_len > sspi->fifo_depth)
-+ if (rx_len > sspi->cfg->fifo_depth)
- reg |= SUN6I_INT_CTL_RF_RDY;
-- if (tx_len > sspi->fifo_depth)
-+ if (tx_len > sspi->cfg->fifo_depth)
- reg |= SUN6I_INT_CTL_TF_ERQ;
- }
-
-@@ -543,7 +576,7 @@ static bool sun6i_spi_can_dma(struct spi_master *master,
- * the fifo length we can just fill the fifo and wait for a single
- * irq, so don't bother setting up dma
- */
-- return xfer->len > sspi->fifo_depth;
-+ return xfer->len > sspi->cfg->fifo_depth;
- }
-
- static int sun6i_spi_probe(struct platform_device *pdev)
-@@ -582,7 +615,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
- }
-
- sspi->master = master;
-- sspi->fifo_depth = (unsigned long)of_device_get_match_data(&pdev->dev);
-+ sspi->cfg = of_device_get_match_data(&pdev->dev);
-
- master->max_speed_hz = 100 * 1000 * 1000;
- master->min_speed_hz = 3 * 1000;
-@@ -696,9 +729,27 @@ static int sun6i_spi_remove(struct platform_device *pdev)
- return 0;
- }
-
-+static const struct sun6i_spi_cfg sun6i_a31_spi_cfg = {
-+ .fifo_depth = SUN6I_FIFO_DEPTH,
-+ .has_clk_ctl = true,
-+};
-+
-+static const struct sun6i_spi_cfg sun8i_h3_spi_cfg = {
-+ .fifo_depth = SUN8I_FIFO_DEPTH,
-+ .has_clk_ctl = true,
-+};
-+
-+static const struct sun6i_spi_cfg sun50i_r329_spi_cfg = {
-+ .fifo_depth = SUN8I_FIFO_DEPTH,
-+};
-+
- static const struct of_device_id sun6i_spi_match[] = {
-- { .compatible = "allwinner,sun6i-a31-spi", .data = (void *)SUN6I_FIFO_DEPTH },
-- { .compatible = "allwinner,sun8i-h3-spi", .data = (void *)SUN8I_FIFO_DEPTH },
-+ { .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_cfg },
-+ { .compatible = "allwinner,sun8i-h3-spi", .data = &sun8i_h3_spi_cfg },
-+ {
-+ .compatible = "allwinner,sun50i-r329-spi",
-+ .data = &sun50i_r329_spi_cfg
-+ },
- {}
- };
- MODULE_DEVICE_TABLE(of, sun6i_spi_match);
---
-2.20.1
-