1 /* 2 * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw> 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <dm.h> 9 #include <errno.h> 10 #include <fdt_support.h> 11 #include <flash.h> 12 #include <mtd.h> 13 #include <asm/io.h> 14 15 DECLARE_GLOBAL_DATA_PTR; 16 17 /* 18 * The QUADSPI_MEM_OP register is used to do memory protect and erase operations 19 */ 20 #define QUADSPI_MEM_OP_BULK_ERASE 0x00000001 21 #define QUADSPI_MEM_OP_SECTOR_ERASE 0x00000002 22 #define QUADSPI_MEM_OP_SECTOR_PROTECT 0x00000003 23 24 /* 25 * The QUADSPI_ISR register is used to determine whether an invalid write or 26 * erase operation trigerred an interrupt 27 */ 28 #define QUADSPI_ISR_ILLEGAL_ERASE BIT(0) 29 #define QUADSPI_ISR_ILLEGAL_WRITE BIT(1) 30 31 struct altera_qspi_regs { 32 u32 rd_status; 33 u32 rd_sid; 34 u32 rd_rdid; 35 u32 mem_op; 36 u32 isr; 37 u32 imr; 38 u32 chip_select; 39 }; 40 41 struct altera_qspi_platdata { 42 struct altera_qspi_regs *regs; 43 void *base; 44 unsigned long size; 45 }; 46 47 flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* FLASH chips info */ 48 49 void flash_print_info(flash_info_t *info) 50 { 51 printf("Altera QSPI flash Size: %ld MB in %d Sectors\n", 52 info->size >> 20, info->sector_count); 53 } 54 55 int flash_erase(flash_info_t *info, int s_first, int s_last) 56 { 57 struct mtd_info *mtd = info->mtd; 58 struct erase_info instr; 59 int ret; 60 61 memset(&instr, 0, sizeof(instr)); 62 instr.addr = mtd->erasesize * s_first; 63 instr.len = mtd->erasesize * (s_last + 1 - s_first); 64 ret = mtd_erase(mtd, &instr); 65 if (ret) 66 return ERR_NOT_ERASED; 67 68 return 0; 69 } 70 71 int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt) 72 { 73 struct mtd_info *mtd = info->mtd; 74 struct udevice *dev = mtd->dev; 75 struct altera_qspi_platdata *pdata = dev_get_platdata(dev); 76 ulong base = (ulong)pdata->base; 77 loff_t to = addr - base; 78 size_t retlen; 79 int ret; 80 81 ret = mtd_write(mtd, to, cnt, &retlen, src); 82 if (ret) 83 return ERR_NOT_ERASED; 84 85 return 0; 86 } 87 88 unsigned long flash_init(void) 89 { 90 struct udevice *dev; 91 92 /* probe every MTD device */ 93 for (uclass_first_device(UCLASS_MTD, &dev); 94 dev; 95 uclass_next_device(&dev)) { 96 } 97 98 return flash_info[0].size; 99 } 100 101 static int altera_qspi_erase(struct mtd_info *mtd, struct erase_info *instr) 102 { 103 struct udevice *dev = mtd->dev; 104 struct altera_qspi_platdata *pdata = dev_get_platdata(dev); 105 struct altera_qspi_regs *regs = pdata->regs; 106 size_t addr = instr->addr; 107 size_t len = instr->len; 108 size_t end = addr + len; 109 u32 sect; 110 u32 stat; 111 112 instr->state = MTD_ERASING; 113 addr &= ~(mtd->erasesize - 1); /* get lower aligned address */ 114 while (addr < end) { 115 sect = addr / mtd->erasesize; 116 sect <<= 8; 117 sect |= QUADSPI_MEM_OP_SECTOR_ERASE; 118 debug("erase %08x\n", sect); 119 writel(sect, ®s->mem_op); 120 stat = readl(®s->isr); 121 if (stat & QUADSPI_ISR_ILLEGAL_ERASE) { 122 /* erase failed, sector might be protected */ 123 debug("erase %08x fail %x\n", sect, stat); 124 writel(stat, ®s->isr); /* clear isr */ 125 instr->state = MTD_ERASE_FAILED; 126 return -EIO; 127 } 128 addr += mtd->erasesize; 129 } 130 instr->state = MTD_ERASE_DONE; 131 mtd_erase_callback(instr); 132 133 return 0; 134 } 135 136 static int altera_qspi_read(struct mtd_info *mtd, loff_t from, size_t len, 137 size_t *retlen, u_char *buf) 138 { 139 struct udevice *dev = mtd->dev; 140 struct altera_qspi_platdata *pdata = dev_get_platdata(dev); 141 142 memcpy_fromio(buf, pdata->base + from, len); 143 *retlen = len; 144 145 return 0; 146 } 147 148 static int altera_qspi_write(struct mtd_info *mtd, loff_t to, size_t len, 149 size_t *retlen, const u_char *buf) 150 { 151 struct udevice *dev = mtd->dev; 152 struct altera_qspi_platdata *pdata = dev_get_platdata(dev); 153 struct altera_qspi_regs *regs = pdata->regs; 154 u32 stat; 155 156 memcpy_toio(pdata->base + to, buf, len); 157 /* check whether write triggered a illegal write interrupt */ 158 stat = readl(®s->isr); 159 if (stat & QUADSPI_ISR_ILLEGAL_WRITE) { 160 /* write failed, sector might be protected */ 161 debug("write fail %x\n", stat); 162 writel(stat, ®s->isr); /* clear isr */ 163 return -EIO; 164 } 165 *retlen = len; 166 167 return 0; 168 } 169 170 static void altera_qspi_sync(struct mtd_info *mtd) 171 { 172 } 173 174 static int altera_qspi_probe(struct udevice *dev) 175 { 176 struct altera_qspi_platdata *pdata = dev_get_platdata(dev); 177 struct altera_qspi_regs *regs = pdata->regs; 178 unsigned long base = (unsigned long)pdata->base; 179 struct mtd_info *mtd; 180 flash_info_t *flash = &flash_info[0]; 181 u32 rdid; 182 int i; 183 184 rdid = readl(®s->rd_rdid); 185 debug("rdid %x\n", rdid); 186 187 mtd = dev_get_uclass_priv(dev); 188 mtd->dev = dev; 189 mtd->name = "nor0"; 190 mtd->type = MTD_NORFLASH; 191 mtd->flags = MTD_CAP_NORFLASH; 192 mtd->size = 1 << ((rdid & 0xff) - 6); 193 mtd->writesize = 1; 194 mtd->writebufsize = mtd->writesize; 195 mtd->_erase = altera_qspi_erase; 196 mtd->_read = altera_qspi_read; 197 mtd->_write = altera_qspi_write; 198 mtd->_sync = altera_qspi_sync; 199 mtd->numeraseregions = 0; 200 mtd->erasesize = 0x10000; 201 if (add_mtd_device(mtd)) 202 return -ENOMEM; 203 204 flash->mtd = mtd; 205 flash->size = mtd->size; 206 flash->sector_count = mtd->size / mtd->erasesize; 207 flash->flash_id = rdid; 208 flash->start[0] = base; 209 for (i = 1; i < flash->sector_count; i++) 210 flash->start[i] = flash->start[i - 1] + mtd->erasesize; 211 gd->bd->bi_flashstart = base; 212 213 return 0; 214 } 215 216 static int altera_qspi_ofdata_to_platdata(struct udevice *dev) 217 { 218 struct altera_qspi_platdata *pdata = dev_get_platdata(dev); 219 void *blob = (void *)gd->fdt_blob; 220 int node = dev->of_offset; 221 const char *list, *end; 222 const fdt32_t *cell; 223 void *base; 224 unsigned long addr, size; 225 int parent, addrc, sizec; 226 int len, idx; 227 228 /* 229 * decode regs. there are multiple reg tuples, and they need to 230 * match with reg-names. 231 */ 232 parent = fdt_parent_offset(blob, node); 233 of_bus_default_count_cells(blob, parent, &addrc, &sizec); 234 list = fdt_getprop(blob, node, "reg-names", &len); 235 if (!list) 236 return -ENOENT; 237 end = list + len; 238 cell = fdt_getprop(blob, node, "reg", &len); 239 if (!cell) 240 return -ENOENT; 241 idx = 0; 242 while (list < end) { 243 addr = fdt_translate_address((void *)blob, 244 node, cell + idx); 245 size = fdt_addr_to_cpu(cell[idx + addrc]); 246 base = map_physmem(addr, size, MAP_NOCACHE); 247 len = strlen(list); 248 if (strcmp(list, "avl_csr") == 0) { 249 pdata->regs = base; 250 } else if (strcmp(list, "avl_mem") == 0) { 251 pdata->base = base; 252 pdata->size = size; 253 } 254 idx += addrc + sizec; 255 list += (len + 1); 256 } 257 258 return 0; 259 } 260 261 static const struct udevice_id altera_qspi_ids[] = { 262 { .compatible = "altr,quadspi-1.0" }, 263 {} 264 }; 265 266 U_BOOT_DRIVER(altera_qspi) = { 267 .name = "altera_qspi", 268 .id = UCLASS_MTD, 269 .of_match = altera_qspi_ids, 270 .ofdata_to_platdata = altera_qspi_ofdata_to_platdata, 271 .platdata_auto_alloc_size = sizeof(struct altera_qspi_platdata), 272 .probe = altera_qspi_probe, 273 }; 274