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/iopoll.h> 11 #include <linux/module.h> 12 #include <linux/platform_device.h> 13 #include <linux/slab.h> 14 #include <linux/spi/spi.h> 15 #include <linux/spi/spi-mem.h> 16 17 #define HISI_SFC_V3XX_VERSION (0x1f8) 18 19 #define HISI_SFC_V3XX_CMD_CFG (0x300) 20 #define HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF 9 21 #define HISI_SFC_V3XX_CMD_CFG_RW_MSK BIT(8) 22 #define HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK BIT(7) 23 #define HISI_SFC_V3XX_CMD_CFG_DUMMY_CNT_OFF 4 24 #define HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK BIT(3) 25 #define HISI_SFC_V3XX_CMD_CFG_CS_SEL_OFF 1 26 #define HISI_SFC_V3XX_CMD_CFG_START_MSK BIT(0) 27 #define HISI_SFC_V3XX_CMD_INS (0x308) 28 #define HISI_SFC_V3XX_CMD_ADDR (0x30c) 29 #define HISI_SFC_V3XX_CMD_DATABUF0 (0x400) 30 31 struct hisi_sfc_v3xx_host { 32 struct device *dev; 33 void __iomem *regbase; 34 int max_cmd_dword; 35 }; 36 37 #define HISI_SFC_V3XX_WAIT_TIMEOUT_US 1000000 38 #define HISI_SFC_V3XX_WAIT_POLL_INTERVAL_US 10 39 40 static int hisi_sfc_v3xx_wait_cmd_idle(struct hisi_sfc_v3xx_host *host) 41 { 42 u32 reg; 43 44 return readl_poll_timeout(host->regbase + HISI_SFC_V3XX_CMD_CFG, reg, 45 !(reg & HISI_SFC_V3XX_CMD_CFG_START_MSK), 46 HISI_SFC_V3XX_WAIT_POLL_INTERVAL_US, 47 HISI_SFC_V3XX_WAIT_TIMEOUT_US); 48 } 49 50 static int hisi_sfc_v3xx_adjust_op_size(struct spi_mem *mem, 51 struct spi_mem_op *op) 52 { 53 struct spi_device *spi = mem->spi; 54 struct hisi_sfc_v3xx_host *host; 55 uintptr_t addr = (uintptr_t)op->data.buf.in; 56 int max_byte_count; 57 58 host = spi_controller_get_devdata(spi->master); 59 60 max_byte_count = host->max_cmd_dword * 4; 61 62 if (!IS_ALIGNED(addr, 4) && op->data.nbytes >= 4) 63 op->data.nbytes = 4 - (addr % 4); 64 else if (op->data.nbytes > max_byte_count) 65 op->data.nbytes = max_byte_count; 66 67 return 0; 68 } 69 70 /* 71 * memcpy_{to,from}io doesn't gurantee 32b accesses - which we require for the 72 * DATABUF registers -so use __io{read,write}32_copy when possible. For 73 * trailing bytes, copy them byte-by-byte from the DATABUF register, as we 74 * can't clobber outside the source/dest buffer. 75 * 76 * For efficient data read/write, we try to put any start 32b unaligned data 77 * into a separate transaction in hisi_sfc_v3xx_adjust_op_size(). 78 */ 79 static void hisi_sfc_v3xx_read_databuf(struct hisi_sfc_v3xx_host *host, 80 u8 *to, unsigned int len) 81 { 82 void __iomem *from; 83 int i; 84 85 from = host->regbase + HISI_SFC_V3XX_CMD_DATABUF0; 86 87 if (IS_ALIGNED((uintptr_t)to, 4)) { 88 int words = len / 4; 89 90 __ioread32_copy(to, from, words); 91 92 len -= words * 4; 93 if (len) { 94 u32 val; 95 96 to += words * 4; 97 from += words * 4; 98 99 val = __raw_readl(from); 100 101 for (i = 0; i < len; i++, val >>= 8, to++) 102 *to = (u8)val; 103 } 104 } else { 105 for (i = 0; i < DIV_ROUND_UP(len, 4); i++, from += 4) { 106 u32 val = __raw_readl(from); 107 int j; 108 109 for (j = 0; j < 4 && (j + (i * 4) < len); 110 to++, val >>= 8, j++) 111 *to = (u8)val; 112 } 113 } 114 } 115 116 static void hisi_sfc_v3xx_write_databuf(struct hisi_sfc_v3xx_host *host, 117 const u8 *from, unsigned int len) 118 { 119 void __iomem *to; 120 int i; 121 122 to = host->regbase + HISI_SFC_V3XX_CMD_DATABUF0; 123 124 if (IS_ALIGNED((uintptr_t)from, 4)) { 125 int words = len / 4; 126 127 __iowrite32_copy(to, from, words); 128 129 len -= words * 4; 130 if (len) { 131 u32 val = 0; 132 133 to += words * 4; 134 from += words * 4; 135 136 for (i = 0; i < len; i++, from++) 137 val |= *from << i * 8; 138 __raw_writel(val, to); 139 } 140 141 } else { 142 for (i = 0; i < DIV_ROUND_UP(len, 4); i++, to += 4) { 143 u32 val = 0; 144 int j; 145 146 for (j = 0; j < 4 && (j + (i * 4) < len); 147 from++, j++) 148 val |= *from << j * 8; 149 __raw_writel(val, to); 150 } 151 } 152 } 153 154 static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host, 155 const struct spi_mem_op *op, 156 u8 chip_select) 157 { 158 int ret, len = op->data.nbytes; 159 u32 config = 0; 160 161 if (op->addr.nbytes) 162 config |= HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK; 163 164 if (op->data.dir != SPI_MEM_NO_DATA) { 165 config |= (len - 1) << HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF; 166 config |= HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK; 167 } 168 169 if (op->data.dir == SPI_MEM_DATA_OUT) 170 hisi_sfc_v3xx_write_databuf(host, op->data.buf.out, len); 171 else if (op->data.dir == SPI_MEM_DATA_IN) 172 config |= HISI_SFC_V3XX_CMD_CFG_RW_MSK; 173 174 config |= op->dummy.nbytes << HISI_SFC_V3XX_CMD_CFG_DUMMY_CNT_OFF | 175 chip_select << HISI_SFC_V3XX_CMD_CFG_CS_SEL_OFF | 176 HISI_SFC_V3XX_CMD_CFG_START_MSK; 177 178 writel(op->addr.val, host->regbase + HISI_SFC_V3XX_CMD_ADDR); 179 writel(op->cmd.opcode, host->regbase + HISI_SFC_V3XX_CMD_INS); 180 181 writel(config, host->regbase + HISI_SFC_V3XX_CMD_CFG); 182 183 ret = hisi_sfc_v3xx_wait_cmd_idle(host); 184 if (ret) 185 return ret; 186 187 if (op->data.dir == SPI_MEM_DATA_IN) 188 hisi_sfc_v3xx_read_databuf(host, op->data.buf.in, len); 189 190 return 0; 191 } 192 193 static int hisi_sfc_v3xx_exec_op(struct spi_mem *mem, 194 const struct spi_mem_op *op) 195 { 196 struct hisi_sfc_v3xx_host *host; 197 struct spi_device *spi = mem->spi; 198 u8 chip_select = spi->chip_select; 199 200 host = spi_controller_get_devdata(spi->master); 201 202 return hisi_sfc_v3xx_generic_exec_op(host, op, chip_select); 203 } 204 205 static const struct spi_controller_mem_ops hisi_sfc_v3xx_mem_ops = { 206 .adjust_op_size = hisi_sfc_v3xx_adjust_op_size, 207 .exec_op = hisi_sfc_v3xx_exec_op, 208 }; 209 210 static int hisi_sfc_v3xx_probe(struct platform_device *pdev) 211 { 212 struct device *dev = &pdev->dev; 213 struct hisi_sfc_v3xx_host *host; 214 struct spi_controller *ctlr; 215 u32 version; 216 int ret; 217 218 ctlr = spi_alloc_master(&pdev->dev, sizeof(*host)); 219 if (!ctlr) 220 return -ENOMEM; 221 222 ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | 223 SPI_TX_DUAL | SPI_TX_QUAD; 224 225 host = spi_controller_get_devdata(ctlr); 226 host->dev = dev; 227 228 platform_set_drvdata(pdev, host); 229 230 host->regbase = devm_platform_ioremap_resource(pdev, 0); 231 if (IS_ERR(host->regbase)) { 232 ret = PTR_ERR(host->regbase); 233 goto err_put_master; 234 } 235 236 ctlr->bus_num = -1; 237 ctlr->num_chipselect = 1; 238 ctlr->mem_ops = &hisi_sfc_v3xx_mem_ops; 239 240 version = readl(host->regbase + HISI_SFC_V3XX_VERSION); 241 242 switch (version) { 243 case 0x351: 244 host->max_cmd_dword = 64; 245 break; 246 default: 247 host->max_cmd_dword = 16; 248 break; 249 } 250 251 ret = devm_spi_register_controller(dev, ctlr); 252 if (ret) 253 goto err_put_master; 254 255 dev_info(&pdev->dev, "hw version 0x%x\n", version); 256 257 return 0; 258 259 err_put_master: 260 spi_master_put(ctlr); 261 return ret; 262 } 263 264 #if IS_ENABLED(CONFIG_ACPI) 265 static const struct acpi_device_id hisi_sfc_v3xx_acpi_ids[] = { 266 {"HISI0341", 0}, 267 {} 268 }; 269 MODULE_DEVICE_TABLE(acpi, hisi_sfc_v3xx_acpi_ids); 270 #endif 271 272 static struct platform_driver hisi_sfc_v3xx_spi_driver = { 273 .driver = { 274 .name = "hisi-sfc-v3xx", 275 .acpi_match_table = ACPI_PTR(hisi_sfc_v3xx_acpi_ids), 276 }, 277 .probe = hisi_sfc_v3xx_probe, 278 }; 279 280 module_platform_driver(hisi_sfc_v3xx_spi_driver); 281 282 MODULE_LICENSE("GPL"); 283 MODULE_AUTHOR("John Garry <john.garry@huawei.com>"); 284 MODULE_DESCRIPTION("HiSilicon SPI NOR V3XX Flash Controller Driver for hi16xx chipsets"); 285