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"); 382