2 * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
4 * SPDX-License-Identifier: GPL-2.0+
10 #include <fdt_support.h>
15 DECLARE_GLOBAL_DATA_PTR
;
17 /* The STATUS register */
18 #define QUADSPI_SR_BP0 BIT(2)
19 #define QUADSPI_SR_BP1 BIT(3)
20 #define QUADSPI_SR_BP2 BIT(4)
21 #define QUADSPI_SR_BP2_0 GENMASK(4, 2)
22 #define QUADSPI_SR_BP3 BIT(6)
23 #define QUADSPI_SR_TB BIT(5)
26 * The QUADSPI_MEM_OP register is used to do memory protect and erase operations
28 #define QUADSPI_MEM_OP_BULK_ERASE 0x00000001
29 #define QUADSPI_MEM_OP_SECTOR_ERASE 0x00000002
30 #define QUADSPI_MEM_OP_SECTOR_PROTECT 0x00000003
33 * The QUADSPI_ISR register is used to determine whether an invalid write or
34 * erase operation trigerred an interrupt
36 #define QUADSPI_ISR_ILLEGAL_ERASE BIT(0)
37 #define QUADSPI_ISR_ILLEGAL_WRITE BIT(1)
39 struct altera_qspi_regs
{
49 struct altera_qspi_platdata
{
50 struct altera_qspi_regs
*regs
;
55 flash_info_t flash_info
[CONFIG_SYS_MAX_FLASH_BANKS
]; /* FLASH chips info */
57 static void altera_qspi_get_locked_range(struct mtd_info
*mtd
, loff_t
*ofs
,
60 void flash_print_info(flash_info_t
*info
)
62 struct mtd_info
*mtd
= info
->mtd
;
66 printf("Altera QSPI flash Size: %ld MB in %d Sectors\n",
67 info
->size
>> 20, info
->sector_count
);
68 altera_qspi_get_locked_range(mtd
, &ofs
, &len
);
69 printf(" %08lX +%lX", info
->start
[0], info
->size
);
71 printf(", protected %08llX +%llX",
72 info
->start
[0] + ofs
, len
);
77 int flash_erase(flash_info_t
*info
, int s_first
, int s_last
)
79 struct mtd_info
*mtd
= info
->mtd
;
80 struct erase_info instr
;
83 memset(&instr
, 0, sizeof(instr
));
84 instr
.addr
= mtd
->erasesize
* s_first
;
85 instr
.len
= mtd
->erasesize
* (s_last
+ 1 - s_first
);
86 ret
= mtd_erase(mtd
, &instr
);
93 int write_buff(flash_info_t
*info
, uchar
*src
, ulong addr
, ulong cnt
)
95 struct mtd_info
*mtd
= info
->mtd
;
96 struct udevice
*dev
= mtd
->dev
;
97 struct altera_qspi_platdata
*pdata
= dev_get_platdata(dev
);
98 ulong base
= (ulong
)pdata
->base
;
99 loff_t to
= addr
- base
;
103 ret
= mtd_write(mtd
, to
, cnt
, &retlen
, src
);
105 return ERR_PROTECTED
;
110 unsigned long flash_init(void)
114 /* probe every MTD device */
115 for (uclass_first_device(UCLASS_MTD
, &dev
);
117 uclass_next_device(&dev
)) {
120 return flash_info
[0].size
;
123 static int altera_qspi_erase(struct mtd_info
*mtd
, struct erase_info
*instr
)
125 struct udevice
*dev
= mtd
->dev
;
126 struct altera_qspi_platdata
*pdata
= dev_get_platdata(dev
);
127 struct altera_qspi_regs
*regs
= pdata
->regs
;
128 size_t addr
= instr
->addr
;
129 size_t len
= instr
->len
;
130 size_t end
= addr
+ len
;
134 instr
->state
= MTD_ERASING
;
135 addr
&= ~(mtd
->erasesize
- 1); /* get lower aligned address */
137 sect
= addr
/ mtd
->erasesize
;
139 sect
|= QUADSPI_MEM_OP_SECTOR_ERASE
;
140 debug("erase %08x\n", sect
);
141 writel(sect
, ®s
->mem_op
);
142 stat
= readl(®s
->isr
);
143 if (stat
& QUADSPI_ISR_ILLEGAL_ERASE
) {
144 /* erase failed, sector might be protected */
145 debug("erase %08x fail %x\n", sect
, stat
);
146 writel(stat
, ®s
->isr
); /* clear isr */
147 instr
->state
= MTD_ERASE_FAILED
;
150 addr
+= mtd
->erasesize
;
152 instr
->state
= MTD_ERASE_DONE
;
153 mtd_erase_callback(instr
);
158 static int altera_qspi_read(struct mtd_info
*mtd
, loff_t from
, size_t len
,
159 size_t *retlen
, u_char
*buf
)
161 struct udevice
*dev
= mtd
->dev
;
162 struct altera_qspi_platdata
*pdata
= dev_get_platdata(dev
);
164 memcpy_fromio(buf
, pdata
->base
+ from
, len
);
170 static int altera_qspi_write(struct mtd_info
*mtd
, loff_t to
, size_t len
,
171 size_t *retlen
, const u_char
*buf
)
173 struct udevice
*dev
= mtd
->dev
;
174 struct altera_qspi_platdata
*pdata
= dev_get_platdata(dev
);
175 struct altera_qspi_regs
*regs
= pdata
->regs
;
178 memcpy_toio(pdata
->base
+ to
, buf
, len
);
179 /* check whether write triggered a illegal write interrupt */
180 stat
= readl(®s
->isr
);
181 if (stat
& QUADSPI_ISR_ILLEGAL_WRITE
) {
182 /* write failed, sector might be protected */
183 debug("write fail %x\n", stat
);
184 writel(stat
, ®s
->isr
); /* clear isr */
192 static void altera_qspi_sync(struct mtd_info
*mtd
)
196 static void altera_qspi_get_locked_range(struct mtd_info
*mtd
, loff_t
*ofs
,
199 struct udevice
*dev
= mtd
->dev
;
200 struct altera_qspi_platdata
*pdata
= dev_get_platdata(dev
);
201 struct altera_qspi_regs
*regs
= pdata
->regs
;
202 int shift0
= ffs(QUADSPI_SR_BP2_0
) - 1;
203 int shift3
= ffs(QUADSPI_SR_BP3
) - 1 - 3;
204 u32 stat
= readl(®s
->rd_status
);
205 unsigned pow
= ((stat
& QUADSPI_SR_BP2_0
) >> shift0
) |
206 ((stat
& QUADSPI_SR_BP3
) >> shift3
);
211 *len
= mtd
->erasesize
<< (pow
- 1);
212 if (*len
> mtd
->size
)
214 if (!(stat
& QUADSPI_SR_TB
))
215 *ofs
= mtd
->size
- *len
;
219 static int altera_qspi_lock(struct mtd_info
*mtd
, loff_t ofs
, uint64_t len
)
221 struct udevice
*dev
= mtd
->dev
;
222 struct altera_qspi_platdata
*pdata
= dev_get_platdata(dev
);
223 struct altera_qspi_regs
*regs
= pdata
->regs
;
224 u32 sector_start
, sector_end
;
230 num_sectors
= mtd
->size
/ mtd
->erasesize
;
231 sector_start
= ofs
/ mtd
->erasesize
;
232 sector_end
= (ofs
+ len
) / mtd
->erasesize
;
234 if (sector_start
>= num_sectors
/ 2) {
235 sr_bp
= fls(num_sectors
- 1 - sector_start
) + 1;
237 } else if (sector_end
< num_sectors
/ 2) {
238 sr_bp
= fls(sector_end
) + 1;
245 mem_op
= (sr_tb
<< 12) | (sr_bp
<< 8);
246 mem_op
|= QUADSPI_MEM_OP_SECTOR_PROTECT
;
247 debug("lock %08x\n", mem_op
);
248 writel(mem_op
, ®s
->mem_op
);
253 static int altera_qspi_unlock(struct mtd_info
*mtd
, loff_t ofs
, uint64_t len
)
255 struct udevice
*dev
= mtd
->dev
;
256 struct altera_qspi_platdata
*pdata
= dev_get_platdata(dev
);
257 struct altera_qspi_regs
*regs
= pdata
->regs
;
260 mem_op
= QUADSPI_MEM_OP_SECTOR_PROTECT
;
261 debug("unlock %08x\n", mem_op
);
262 writel(mem_op
, ®s
->mem_op
);
267 static int altera_qspi_probe(struct udevice
*dev
)
269 struct altera_qspi_platdata
*pdata
= dev_get_platdata(dev
);
270 struct altera_qspi_regs
*regs
= pdata
->regs
;
271 unsigned long base
= (unsigned long)pdata
->base
;
272 struct mtd_info
*mtd
;
273 flash_info_t
*flash
= &flash_info
[0];
277 rdid
= readl(®s
->rd_rdid
);
278 debug("rdid %x\n", rdid
);
280 mtd
= dev_get_uclass_priv(dev
);
283 mtd
->type
= MTD_NORFLASH
;
284 mtd
->flags
= MTD_CAP_NORFLASH
;
285 mtd
->size
= 1 << ((rdid
& 0xff) - 6);
287 mtd
->writebufsize
= mtd
->writesize
;
288 mtd
->_erase
= altera_qspi_erase
;
289 mtd
->_read
= altera_qspi_read
;
290 mtd
->_write
= altera_qspi_write
;
291 mtd
->_sync
= altera_qspi_sync
;
292 mtd
->_lock
= altera_qspi_lock
;
293 mtd
->_unlock
= altera_qspi_unlock
;
294 mtd
->numeraseregions
= 0;
295 mtd
->erasesize
= 0x10000;
296 if (add_mtd_device(mtd
))
300 flash
->size
= mtd
->size
;
301 flash
->sector_count
= mtd
->size
/ mtd
->erasesize
;
302 flash
->flash_id
= rdid
;
303 flash
->start
[0] = base
;
304 for (i
= 1; i
< flash
->sector_count
; i
++)
305 flash
->start
[i
] = flash
->start
[i
- 1] + mtd
->erasesize
;
306 gd
->bd
->bi_flashstart
= base
;
311 static int altera_qspi_ofdata_to_platdata(struct udevice
*dev
)
313 struct altera_qspi_platdata
*pdata
= dev_get_platdata(dev
);
314 void *blob
= (void *)gd
->fdt_blob
;
315 int node
= dev
->of_offset
;
316 const char *list
, *end
;
319 unsigned long addr
, size
;
320 int parent
, addrc
, sizec
;
324 * decode regs. there are multiple reg tuples, and they need to
325 * match with reg-names.
327 parent
= fdt_parent_offset(blob
, node
);
328 of_bus_default_count_cells(blob
, parent
, &addrc
, &sizec
);
329 list
= fdt_getprop(blob
, node
, "reg-names", &len
);
333 cell
= fdt_getprop(blob
, node
, "reg", &len
);
338 addr
= fdt_translate_address((void *)blob
,
340 size
= fdt_addr_to_cpu(cell
[idx
+ addrc
]);
341 base
= map_physmem(addr
, size
, MAP_NOCACHE
);
343 if (strcmp(list
, "avl_csr") == 0) {
345 } else if (strcmp(list
, "avl_mem") == 0) {
349 idx
+= addrc
+ sizec
;
356 static const struct udevice_id altera_qspi_ids
[] = {
357 { .compatible
= "altr,quadspi-1.0" },
361 U_BOOT_DRIVER(altera_qspi
) = {
362 .name
= "altera_qspi",
364 .of_match
= altera_qspi_ids
,
365 .ofdata_to_platdata
= altera_qspi_ofdata_to_platdata
,
366 .platdata_auto_alloc_size
= sizeof(struct altera_qspi_platdata
),
367 .probe
= altera_qspi_probe
,