Merge tag 'tag-chrome-platform-fixes-for-v5.7-rc5' of git://git.kernel.org/pub/scm...
[linux-block.git] / drivers / spi / spi-hisi-sfc-v3xx.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // HiSilicon SPI NOR V3XX Flash Controller Driver for hi16xx chipsets
4 //
5 // Copyright (c) 2019 HiSilicon Technologies Co., Ltd.
6 // Author: John Garry <john.garry@huawei.com>
7
8 #include <linux/acpi.h>
9 #include <linux/bitops.h>
10 #include <linux/dmi.h>
11 #include <linux/iopoll.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/slab.h>
15 #include <linux/spi/spi.h>
16 #include <linux/spi/spi-mem.h>
17
18 #define HISI_SFC_V3XX_VERSION (0x1f8)
19
20 #define HISI_SFC_V3XX_CMD_CFG (0x300)
21 #define HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT (1 << 17)
22 #define HISI_SFC_V3XX_CMD_CFG_DUAL_IO (2 << 17)
23 #define HISI_SFC_V3XX_CMD_CFG_FULL_DIO (3 << 17)
24 #define HISI_SFC_V3XX_CMD_CFG_QUAD_IN_QUAD_OUT (5 << 17)
25 #define HISI_SFC_V3XX_CMD_CFG_QUAD_IO (6 << 17)
26 #define HISI_SFC_V3XX_CMD_CFG_FULL_QIO (7 << 17)
27 #define HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF 9
28 #define HISI_SFC_V3XX_CMD_CFG_RW_MSK BIT(8)
29 #define HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK BIT(7)
30 #define HISI_SFC_V3XX_CMD_CFG_DUMMY_CNT_OFF 4
31 #define HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK BIT(3)
32 #define HISI_SFC_V3XX_CMD_CFG_CS_SEL_OFF 1
33 #define HISI_SFC_V3XX_CMD_CFG_START_MSK BIT(0)
34 #define HISI_SFC_V3XX_CMD_INS (0x308)
35 #define HISI_SFC_V3XX_CMD_ADDR (0x30c)
36 #define HISI_SFC_V3XX_CMD_DATABUF0 (0x400)
37
38 struct hisi_sfc_v3xx_host {
39         struct device *dev;
40         void __iomem *regbase;
41         int max_cmd_dword;
42 };
43
44 #define HISI_SFC_V3XX_WAIT_TIMEOUT_US           1000000
45 #define HISI_SFC_V3XX_WAIT_POLL_INTERVAL_US     10
46
47 static int hisi_sfc_v3xx_wait_cmd_idle(struct hisi_sfc_v3xx_host *host)
48 {
49         u32 reg;
50
51         return readl_poll_timeout(host->regbase + HISI_SFC_V3XX_CMD_CFG, reg,
52                                   !(reg & HISI_SFC_V3XX_CMD_CFG_START_MSK),
53                                   HISI_SFC_V3XX_WAIT_POLL_INTERVAL_US,
54                                   HISI_SFC_V3XX_WAIT_TIMEOUT_US);
55 }
56
57 static int hisi_sfc_v3xx_adjust_op_size(struct spi_mem *mem,
58                                         struct spi_mem_op *op)
59 {
60         struct spi_device *spi = mem->spi;
61         struct hisi_sfc_v3xx_host *host;
62         uintptr_t addr = (uintptr_t)op->data.buf.in;
63         int max_byte_count;
64
65         host = spi_controller_get_devdata(spi->master);
66
67         max_byte_count = host->max_cmd_dword * 4;
68
69         if (!IS_ALIGNED(addr, 4) && op->data.nbytes >= 4)
70                 op->data.nbytes = 4 - (addr % 4);
71         else if (op->data.nbytes > max_byte_count)
72                 op->data.nbytes = max_byte_count;
73
74         return 0;
75 }
76
77 /*
78  * memcpy_{to,from}io doesn't gurantee 32b accesses - which we require for the
79  * DATABUF registers -so use __io{read,write}32_copy when possible. For
80  * trailing bytes, copy them byte-by-byte from the DATABUF register, as we
81  * can't clobber outside the source/dest buffer.
82  *
83  * For efficient data read/write, we try to put any start 32b unaligned data
84  * into a separate transaction in hisi_sfc_v3xx_adjust_op_size().
85  */
86 static void hisi_sfc_v3xx_read_databuf(struct hisi_sfc_v3xx_host *host,
87                                        u8 *to, unsigned int len)
88 {
89         void __iomem *from;
90         int i;
91
92         from = host->regbase + HISI_SFC_V3XX_CMD_DATABUF0;
93
94         if (IS_ALIGNED((uintptr_t)to, 4)) {
95                 int words = len / 4;
96
97                 __ioread32_copy(to, from, words);
98
99                 len -= words * 4;
100                 if (len) {
101                         u32 val;
102
103                         to += words * 4;
104                         from += words * 4;
105
106                         val = __raw_readl(from);
107
108                         for (i = 0; i < len; i++, val >>= 8, to++)
109                                 *to = (u8)val;
110                 }
111         } else {
112                 for (i = 0; i < DIV_ROUND_UP(len, 4); i++, from += 4) {
113                         u32 val = __raw_readl(from);
114                         int j;
115
116                         for (j = 0; j < 4 && (j + (i * 4) < len);
117                              to++, val >>= 8, j++)
118                                 *to = (u8)val;
119                 }
120         }
121 }
122
123 static void hisi_sfc_v3xx_write_databuf(struct hisi_sfc_v3xx_host *host,
124                                         const u8 *from, unsigned int len)
125 {
126         void __iomem *to;
127         int i;
128
129         to = host->regbase + HISI_SFC_V3XX_CMD_DATABUF0;
130
131         if (IS_ALIGNED((uintptr_t)from, 4)) {
132                 int words = len / 4;
133
134                 __iowrite32_copy(to, from, words);
135
136                 len -= words * 4;
137                 if (len) {
138                         u32 val = 0;
139
140                         to += words * 4;
141                         from += words * 4;
142
143                         for (i = 0; i < len; i++, from++)
144                                 val |= *from << i * 8;
145                         __raw_writel(val, to);
146                 }
147
148         } else {
149                 for (i = 0; i < DIV_ROUND_UP(len, 4); i++, to += 4) {
150                         u32 val = 0;
151                         int j;
152
153                         for (j = 0; j < 4 && (j + (i * 4) < len);
154                              from++, j++)
155                                 val |= *from << j * 8;
156                         __raw_writel(val, to);
157                 }
158         }
159 }
160
161 static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host,
162                                          const struct spi_mem_op *op,
163                                          u8 chip_select)
164 {
165         int ret, len = op->data.nbytes;
166         u32 config = 0;
167
168         if (op->addr.nbytes)
169                 config |= HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK;
170
171         switch (op->data.buswidth) {
172         case 0 ... 1:
173                 break;
174         case 2:
175                 if (op->addr.buswidth <= 1) {
176                         config |= HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT;
177                 } else if (op->addr.buswidth == 2) {
178                         if (op->cmd.buswidth <= 1) {
179                                 config |= HISI_SFC_V3XX_CMD_CFG_DUAL_IO;
180                         } else if (op->cmd.buswidth == 2) {
181                                 config |= HISI_SFC_V3XX_CMD_CFG_FULL_DIO;
182                         } else {
183                                 return -EIO;
184                         }
185                 } else {
186                         return -EIO;
187                 }
188                 break;
189         case 4:
190                 if (op->addr.buswidth <= 1) {
191                         config |= HISI_SFC_V3XX_CMD_CFG_QUAD_IN_QUAD_OUT;
192                 } else if (op->addr.buswidth == 4) {
193                         if (op->cmd.buswidth <= 1) {
194                                 config |= HISI_SFC_V3XX_CMD_CFG_QUAD_IO;
195                         } else if (op->cmd.buswidth == 4) {
196                                 config |= HISI_SFC_V3XX_CMD_CFG_FULL_QIO;
197                         } else {
198                                 return -EIO;
199                         }
200                 } else {
201                         return -EIO;
202                 }
203                 break;
204         default:
205                 return -EOPNOTSUPP;
206         }
207
208         if (op->data.dir != SPI_MEM_NO_DATA) {
209                 config |= (len - 1) << HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF;
210                 config |= HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK;
211         }
212
213         if (op->data.dir == SPI_MEM_DATA_OUT)
214                 hisi_sfc_v3xx_write_databuf(host, op->data.buf.out, len);
215         else if (op->data.dir == SPI_MEM_DATA_IN)
216                 config |= HISI_SFC_V3XX_CMD_CFG_RW_MSK;
217
218         config |= op->dummy.nbytes << HISI_SFC_V3XX_CMD_CFG_DUMMY_CNT_OFF |
219                   chip_select << HISI_SFC_V3XX_CMD_CFG_CS_SEL_OFF |
220                   HISI_SFC_V3XX_CMD_CFG_START_MSK;
221
222         writel(op->addr.val, host->regbase + HISI_SFC_V3XX_CMD_ADDR);
223         writel(op->cmd.opcode, host->regbase + HISI_SFC_V3XX_CMD_INS);
224
225         writel(config, host->regbase + HISI_SFC_V3XX_CMD_CFG);
226
227         ret = hisi_sfc_v3xx_wait_cmd_idle(host);
228         if (ret)
229                 return ret;
230
231         if (op->data.dir == SPI_MEM_DATA_IN)
232                 hisi_sfc_v3xx_read_databuf(host, op->data.buf.in, len);
233
234         return 0;
235 }
236
237 static int hisi_sfc_v3xx_exec_op(struct spi_mem *mem,
238                                  const struct spi_mem_op *op)
239 {
240         struct hisi_sfc_v3xx_host *host;
241         struct spi_device *spi = mem->spi;
242         u8 chip_select = spi->chip_select;
243
244         host = spi_controller_get_devdata(spi->master);
245
246         return hisi_sfc_v3xx_generic_exec_op(host, op, chip_select);
247 }
248
249 static const struct spi_controller_mem_ops hisi_sfc_v3xx_mem_ops = {
250         .adjust_op_size = hisi_sfc_v3xx_adjust_op_size,
251         .exec_op = hisi_sfc_v3xx_exec_op,
252 };
253
254 static int hisi_sfc_v3xx_buswidth_override_bits;
255
256 /*
257  * ACPI FW does not allow us to currently set the device buswidth, so quirk it
258  * depending on the board.
259  */
260 static int __init hisi_sfc_v3xx_dmi_quirk(const struct dmi_system_id *d)
261 {
262         hisi_sfc_v3xx_buswidth_override_bits = SPI_RX_QUAD | SPI_TX_QUAD;
263
264         return 0;
265 }
266
267 static const struct dmi_system_id hisi_sfc_v3xx_dmi_quirk_table[]  = {
268         {
269         .callback = hisi_sfc_v3xx_dmi_quirk,
270         .matches = {
271                 DMI_MATCH(DMI_SYS_VENDOR, "Huawei"),
272                 DMI_MATCH(DMI_PRODUCT_NAME, "D06"),
273         },
274         },
275         {
276         .callback = hisi_sfc_v3xx_dmi_quirk,
277         .matches = {
278                 DMI_MATCH(DMI_SYS_VENDOR, "Huawei"),
279                 DMI_MATCH(DMI_PRODUCT_NAME, "TaiShan 2280 V2"),
280         },
281         },
282         {
283         .callback = hisi_sfc_v3xx_dmi_quirk,
284         .matches = {
285                 DMI_MATCH(DMI_SYS_VENDOR, "Huawei"),
286                 DMI_MATCH(DMI_PRODUCT_NAME, "TaiShan 200 (Model 2280)"),
287         },
288         },
289         {}
290 };
291
292 static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
293 {
294         struct device *dev = &pdev->dev;
295         struct hisi_sfc_v3xx_host *host;
296         struct spi_controller *ctlr;
297         u32 version;
298         int ret;
299
300         ctlr = spi_alloc_master(&pdev->dev, sizeof(*host));
301         if (!ctlr)
302                 return -ENOMEM;
303
304         ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD |
305                           SPI_TX_DUAL | SPI_TX_QUAD;
306
307         ctlr->buswidth_override_bits = hisi_sfc_v3xx_buswidth_override_bits;
308
309         host = spi_controller_get_devdata(ctlr);
310         host->dev = dev;
311
312         platform_set_drvdata(pdev, host);
313
314         host->regbase = devm_platform_ioremap_resource(pdev, 0);
315         if (IS_ERR(host->regbase)) {
316                 ret = PTR_ERR(host->regbase);
317                 goto err_put_master;
318         }
319
320         ctlr->bus_num = -1;
321         ctlr->num_chipselect = 1;
322         ctlr->mem_ops = &hisi_sfc_v3xx_mem_ops;
323
324         version = readl(host->regbase + HISI_SFC_V3XX_VERSION);
325
326         switch (version) {
327         case 0x351:
328                 host->max_cmd_dword = 64;
329                 break;
330         default:
331                 host->max_cmd_dword = 16;
332                 break;
333         }
334
335         ret = devm_spi_register_controller(dev, ctlr);
336         if (ret)
337                 goto err_put_master;
338
339         dev_info(&pdev->dev, "hw version 0x%x\n", version);
340
341         return 0;
342
343 err_put_master:
344         spi_master_put(ctlr);
345         return ret;
346 }
347
348 #if IS_ENABLED(CONFIG_ACPI)
349 static const struct acpi_device_id hisi_sfc_v3xx_acpi_ids[] = {
350         {"HISI0341", 0},
351         {}
352 };
353 MODULE_DEVICE_TABLE(acpi, hisi_sfc_v3xx_acpi_ids);
354 #endif
355
356 static struct platform_driver hisi_sfc_v3xx_spi_driver = {
357         .driver = {
358                 .name   = "hisi-sfc-v3xx",
359                 .acpi_match_table = ACPI_PTR(hisi_sfc_v3xx_acpi_ids),
360         },
361         .probe  = hisi_sfc_v3xx_probe,
362 };
363
364 static int __init hisi_sfc_v3xx_spi_init(void)
365 {
366         dmi_check_system(hisi_sfc_v3xx_dmi_quirk_table);
367
368         return platform_driver_register(&hisi_sfc_v3xx_spi_driver);
369 }
370
371 static void __exit hisi_sfc_v3xx_spi_exit(void)
372 {
373         platform_driver_unregister(&hisi_sfc_v3xx_spi_driver);
374 }
375
376 module_init(hisi_sfc_v3xx_spi_init);
377 module_exit(hisi_sfc_v3xx_spi_exit);
378
379 MODULE_LICENSE("GPL");
380 MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
381 MODULE_DESCRIPTION("HiSilicon SPI NOR V3XX Flash Controller Driver for hi16xx chipsets");