sunxi: enable SPINAND support on 6.1 for the MYIR SPINAND board
[openwrt/staging/wigyori.git] / target / linux / sunxi / patches-6.1 / 0007-dt-bindings-spi-sun6i-add-DT-bindings-for-Allwinner-.patch
1 From 160cc587decac38e0f28f1583412a987a70450e9 Mon Sep 17 00:00:00 2001
2 From: Maksim Kiselev <bigunclemax@gmail.com>
3 Date: Wed, 10 May 2023 11:11:08 +0300
4 Subject: [PATCH 7/9] dt-bindings: spi: sun6i: add DT bindings for Allwinner
5 R329/D1/R528/T113s SPI
6
7 Listed above Allwinner SoCs has two SPI controllers. First is the regular
8 SPI controller and the second one has additional functionality for
9 MIPI-DBI Type C.
10
11 Add compatible strings for these controllers
12
13 Signed-off-by: Maksim Kiselev <bigunclemax@gmail.com>
14 Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
15 Reviewed-by: Andre Przywara <andre.przywara@arm.com>
16 Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com>
17 ---
18 .../bindings/spi/allwinner,sun6i-a31-spi.yaml | 10 ++
19 .../boot/dts/allwinner/sunxi-d1s-t113.dtsi | 37 +++++
20 drivers/spi/spi-sun6i.c | 131 ++++++++++++------
21 3 files changed, 138 insertions(+), 40 deletions(-)
22
23 diff --git a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
24 index 58b7056f4a70..95939684a00d 100644
25 --- a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
26 +++ b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
27 @@ -19,6 +19,7 @@ properties:
28
29 compatible:
30 oneOf:
31 + - const: allwinner,sun50i-r329-spi
32 - const: allwinner,sun6i-a31-spi
33 - const: allwinner,sun8i-h3-spi
34 - items:
35 @@ -28,6 +29,15 @@ properties:
36 - allwinner,sun50i-h616-spi
37 - allwinner,suniv-f1c100s-spi
38 - const: allwinner,sun8i-h3-spi
39 + - items:
40 + - enum:
41 + - allwinner,sun20i-d1-spi
42 + - allwinner,sun50i-r329-spi-dbi
43 + - const: allwinner,sun50i-r329-spi
44 + - items:
45 + - const: allwinner,sun20i-d1-spi-dbi
46 + - const: allwinner,sun50i-r329-spi-dbi
47 + - const: allwinner,sun50i-r329-spi
48
49 reg:
50 maxItems: 1
51 diff --git a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
52 index 3723612b1fd8..6efff8f41e00 100644
53 --- a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
54 +++ b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
55 @@ -108,6 +108,12 @@
56 function = "emac";
57 };
58
59 + /omit-if-no-ref/
60 + spi0_pins: spi0-pins {
61 + pins = "PC2", "PC3", "PC4", "PC5";
62 + function = "spi0";
63 + };
64 +
65 /omit-if-no-ref/
66 uart1_pg6_pins: uart1-pg6-pins {
67 pins = "PG6", "PG7";
68 @@ -435,6 +441,37 @@
69 #size-cells = <0>;
70 };
71
72 + spi0: spi@4025000 {
73 + compatible = "allwinner,sun20i-d1-spi",
74 + "allwinner,sun50i-r329-spi";
75 + reg = <0x04025000 0x1000>;
76 + interrupts = <SOC_PERIPHERAL_IRQ(15) IRQ_TYPE_LEVEL_HIGH>;
77 + clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
78 + clock-names = "ahb", "mod";
79 + dmas = <&dma 22>, <&dma 22>;
80 + dma-names = "rx", "tx";
81 + resets = <&ccu RST_BUS_SPI0>;
82 + status = "disabled";
83 + #address-cells = <1>;
84 + #size-cells = <0>;
85 + };
86 +
87 + spi1: spi@4026000 {
88 + compatible = "allwinner,sun20i-d1-spi-dbi",
89 + "allwinner,sun50i-r329-spi-dbi",
90 + "allwinner,sun50i-r329-spi";
91 + reg = <0x04026000 0x1000>;
92 + interrupts = <SOC_PERIPHERAL_IRQ(16) IRQ_TYPE_LEVEL_HIGH>;
93 + clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
94 + clock-names = "ahb", "mod";
95 + dmas = <&dma 23>, <&dma 23>;
96 + dma-names = "rx", "tx";
97 + resets = <&ccu RST_BUS_SPI1>;
98 + status = "disabled";
99 + #address-cells = <1>;
100 + #size-cells = <0>;
101 + };
102 +
103 usb_otg: usb@4100000 {
104 compatible = "allwinner,sun20i-d1-musb",
105 "allwinner,sun8i-a33-musb";
106 diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
107 index 23ad052528db..4f32cd99a81e 100644
108 --- a/drivers/spi/spi-sun6i.c
109 +++ b/drivers/spi/spi-sun6i.c
110 @@ -42,7 +42,9 @@
111 #define SUN6I_TFR_CTL_CS_MANUAL BIT(6)
112 #define SUN6I_TFR_CTL_CS_LEVEL BIT(7)
113 #define SUN6I_TFR_CTL_DHB BIT(8)
114 +#define SUN6I_TFR_CTL_SDC BIT(11)
115 #define SUN6I_TFR_CTL_FBS BIT(12)
116 +#define SUN6I_TFR_CTL_SDM BIT(13)
117 #define SUN6I_TFR_CTL_XCH BIT(31)
118
119 #define SUN6I_INT_CTL_REG 0x10
120 @@ -85,6 +87,11 @@
121 #define SUN6I_TXDATA_REG 0x200
122 #define SUN6I_RXDATA_REG 0x300
123
124 +struct sun6i_spi_cfg {
125 + unsigned long fifo_depth;
126 + bool has_clk_ctl;
127 +};
128 +
129 struct sun6i_spi {
130 struct spi_master *master;
131 void __iomem *base_addr;
132 @@ -99,7 +106,7 @@ struct sun6i_spi {
133 const u8 *tx_buf;
134 u8 *rx_buf;
135 int len;
136 - unsigned long fifo_depth;
137 + const struct sun6i_spi_cfg *cfg;
138 };
139
140 static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg)
141 @@ -156,7 +163,7 @@ static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi)
142 u8 byte;
143
144 /* See how much data we can fit */
145 - cnt = sspi->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi);
146 + cnt = sspi->cfg->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi);
147
148 len = min((int)cnt, sspi->len);
149
150 @@ -256,7 +263,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
151 struct spi_transfer *tfr)
152 {
153 struct sun6i_spi *sspi = spi_master_get_devdata(master);
154 - unsigned int mclk_rate, div, div_cdr1, div_cdr2, timeout;
155 + unsigned int div, div_cdr1, div_cdr2, timeout;
156 unsigned int start, end, tx_time;
157 unsigned int trig_level;
158 unsigned int tx_len = 0, rx_len = 0;
159 @@ -289,14 +296,14 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
160 * the hardcoded value used in old generation of Allwinner
161 * SPI controller. (See spi-sun4i.c)
162 */
163 - trig_level = sspi->fifo_depth / 4 * 3;
164 + trig_level = sspi->cfg->fifo_depth / 4 * 3;
165 } else {
166 /*
167 * Setup FIFO DMA request trigger level
168 * We choose 1/2 of the full fifo depth, that value will
169 * be used as DMA burst length.
170 */
171 - trig_level = sspi->fifo_depth / 2;
172 + trig_level = sspi->cfg->fifo_depth / 2;
173
174 if (tfr->tx_buf)
175 reg |= SUN6I_FIFO_CTL_TF_DRQ_EN;
176 @@ -346,39 +353,65 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
177
178 sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
179
180 - /* Ensure that we have a parent clock fast enough */
181 - mclk_rate = clk_get_rate(sspi->mclk);
182 - if (mclk_rate < (2 * tfr->speed_hz)) {
183 - clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
184 - mclk_rate = clk_get_rate(sspi->mclk);
185 - }
186 + if (sspi->cfg->has_clk_ctl) {
187 + unsigned int mclk_rate = clk_get_rate(sspi->mclk);
188
189 - /*
190 - * Setup clock divider.
191 - *
192 - * We have two choices there. Either we can use the clock
193 - * divide rate 1, which is calculated thanks to this formula:
194 - * SPI_CLK = MOD_CLK / (2 ^ cdr)
195 - * Or we can use CDR2, which is calculated with the formula:
196 - * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
197 - * Wether we use the former or the latter is set through the
198 - * DRS bit.
199 - *
200 - * First try CDR2, and if we can't reach the expected
201 - * frequency, fall back to CDR1.
202 - */
203 - div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
204 - div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
205 - if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
206 - reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
207 - tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
208 + /* Ensure that we have a parent clock fast enough */
209 + if (mclk_rate < (2 * tfr->speed_hz)) {
210 + clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
211 + mclk_rate = clk_get_rate(sspi->mclk);
212 + }
213 +
214 + /*
215 + * Setup clock divider.
216 + *
217 + * We have two choices there. Either we can use the clock
218 + * divide rate 1, which is calculated thanks to this formula:
219 + * SPI_CLK = MOD_CLK / (2 ^ cdr)
220 + * Or we can use CDR2, which is calculated with the formula:
221 + * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
222 + * Wether we use the former or the latter is set through the
223 + * DRS bit.
224 + *
225 + * First try CDR2, and if we can't reach the expected
226 + * frequency, fall back to CDR1.
227 + */
228 + div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
229 + div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
230 + if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
231 + reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
232 + tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
233 + } else {
234 + div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
235 + reg = SUN6I_CLK_CTL_CDR1(div);
236 + tfr->effective_speed_hz = mclk_rate / (1 << div);
237 + }
238 +
239 + sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
240 } else {
241 - div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
242 - reg = SUN6I_CLK_CTL_CDR1(div);
243 - tfr->effective_speed_hz = mclk_rate / (1 << div);
244 + clk_set_rate(sspi->mclk, tfr->speed_hz);
245 + tfr->effective_speed_hz = clk_get_rate(sspi->mclk);
246 +
247 + /*
248 + * Configure work mode.
249 + *
250 + * There are three work modes depending on the controller clock
251 + * frequency:
252 + * - normal sample mode : CLK <= 24MHz SDM=1 SDC=0
253 + * - delay half-cycle sample mode : CLK <= 40MHz SDM=0 SDC=0
254 + * - delay one-cycle sample mode : CLK >= 80MHz SDM=0 SDC=1
255 + */
256 + reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
257 + reg &= ~(SUN6I_TFR_CTL_SDM | SUN6I_TFR_CTL_SDC);
258 +
259 + if (tfr->effective_speed_hz <= 24000000)
260 + reg |= SUN6I_TFR_CTL_SDM;
261 + else if (tfr->effective_speed_hz >= 80000000)
262 + reg |= SUN6I_TFR_CTL_SDC;
263 +
264 + sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
265 }
266
267 - sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
268 /* Finally enable the bus - doing so before might raise SCK to HIGH */
269 reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG);
270 reg |= SUN6I_GBL_CTL_BUS_ENABLE;
271 @@ -410,9 +443,9 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
272 reg = SUN6I_INT_CTL_TC;
273
274 if (!use_dma) {
275 - if (rx_len > sspi->fifo_depth)
276 + if (rx_len > sspi->cfg->fifo_depth)
277 reg |= SUN6I_INT_CTL_RF_RDY;
278 - if (tx_len > sspi->fifo_depth)
279 + if (tx_len > sspi->cfg->fifo_depth)
280 reg |= SUN6I_INT_CTL_TF_ERQ;
281 }
282
283 @@ -543,7 +576,7 @@ static bool sun6i_spi_can_dma(struct spi_master *master,
284 * the fifo length we can just fill the fifo and wait for a single
285 * irq, so don't bother setting up dma
286 */
287 - return xfer->len > sspi->fifo_depth;
288 + return xfer->len > sspi->cfg->fifo_depth;
289 }
290
291 static int sun6i_spi_probe(struct platform_device *pdev)
292 @@ -582,7 +615,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
293 }
294
295 sspi->master = master;
296 - sspi->fifo_depth = (unsigned long)of_device_get_match_data(&pdev->dev);
297 + sspi->cfg = of_device_get_match_data(&pdev->dev);
298
299 master->max_speed_hz = 100 * 1000 * 1000;
300 master->min_speed_hz = 3 * 1000;
301 @@ -696,9 +729,27 @@ static int sun6i_spi_remove(struct platform_device *pdev)
302 return 0;
303 }
304
305 +static const struct sun6i_spi_cfg sun6i_a31_spi_cfg = {
306 + .fifo_depth = SUN6I_FIFO_DEPTH,
307 + .has_clk_ctl = true,
308 +};
309 +
310 +static const struct sun6i_spi_cfg sun8i_h3_spi_cfg = {
311 + .fifo_depth = SUN8I_FIFO_DEPTH,
312 + .has_clk_ctl = true,
313 +};
314 +
315 +static const struct sun6i_spi_cfg sun50i_r329_spi_cfg = {
316 + .fifo_depth = SUN8I_FIFO_DEPTH,
317 +};
318 +
319 static const struct of_device_id sun6i_spi_match[] = {
320 - { .compatible = "allwinner,sun6i-a31-spi", .data = (void *)SUN6I_FIFO_DEPTH },
321 - { .compatible = "allwinner,sun8i-h3-spi", .data = (void *)SUN8I_FIFO_DEPTH },
322 + { .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_cfg },
323 + { .compatible = "allwinner,sun8i-h3-spi", .data = &sun8i_h3_spi_cfg },
324 + {
325 + .compatible = "allwinner,sun50i-r329-spi",
326 + .data = &sun50i_r329_spi_cfg
327 + },
328 {}
329 };
330 MODULE_DEVICE_TABLE(of, sun6i_spi_match);
331 --
332 2.20.1
333