1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2015
3*4882a593Smuzhiyun * Cristian Birsan <cristian.birsan@microchip.com>
4*4882a593Smuzhiyun * Purna Chandra Mandal <purna.mandal@microchip.com>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <dm.h>
11*4882a593Smuzhiyun #include <fdt_support.h>
12*4882a593Smuzhiyun #include <flash.h>
13*4882a593Smuzhiyun #include <mach/pic32.h>
14*4882a593Smuzhiyun #include <wait_bit.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun /* NVM Controller registers */
19*4882a593Smuzhiyun struct pic32_reg_nvm {
20*4882a593Smuzhiyun struct pic32_reg_atomic ctrl;
21*4882a593Smuzhiyun struct pic32_reg_atomic key;
22*4882a593Smuzhiyun struct pic32_reg_atomic addr;
23*4882a593Smuzhiyun struct pic32_reg_atomic data;
24*4882a593Smuzhiyun };
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /* NVM operations */
27*4882a593Smuzhiyun #define NVMOP_NOP 0
28*4882a593Smuzhiyun #define NVMOP_WORD_WRITE 1
29*4882a593Smuzhiyun #define NVMOP_PAGE_ERASE 4
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun /* NVM control bits */
32*4882a593Smuzhiyun #define NVM_WR BIT(15)
33*4882a593Smuzhiyun #define NVM_WREN BIT(14)
34*4882a593Smuzhiyun #define NVM_WRERR BIT(13)
35*4882a593Smuzhiyun #define NVM_LVDERR BIT(12)
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /* NVM programming unlock register */
38*4882a593Smuzhiyun #define LOCK_KEY 0x0
39*4882a593Smuzhiyun #define UNLOCK_KEY1 0xaa996655
40*4882a593Smuzhiyun #define UNLOCK_KEY2 0x556699aa
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /*
43*4882a593Smuzhiyun * PIC32 flash banks consist of number of pages, each page
44*4882a593Smuzhiyun * into number of rows and rows into number of words.
45*4882a593Smuzhiyun * Here we will maintain page information instead of sector.
46*4882a593Smuzhiyun */
47*4882a593Smuzhiyun flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
48*4882a593Smuzhiyun static struct pic32_reg_nvm *nvm_regs_p;
49*4882a593Smuzhiyun
flash_initiate_operation(u32 nvmop)50*4882a593Smuzhiyun static inline void flash_initiate_operation(u32 nvmop)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun /* set operation */
53*4882a593Smuzhiyun writel(nvmop, &nvm_regs_p->ctrl.raw);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /* enable flash write */
56*4882a593Smuzhiyun writel(NVM_WREN, &nvm_regs_p->ctrl.set);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun /* unlock sequence */
59*4882a593Smuzhiyun writel(LOCK_KEY, &nvm_regs_p->key.raw);
60*4882a593Smuzhiyun writel(UNLOCK_KEY1, &nvm_regs_p->key.raw);
61*4882a593Smuzhiyun writel(UNLOCK_KEY2, &nvm_regs_p->key.raw);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /* initiate operation */
64*4882a593Smuzhiyun writel(NVM_WR, &nvm_regs_p->ctrl.set);
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
flash_wait_till_busy(const char * func,ulong timeout)67*4882a593Smuzhiyun static int flash_wait_till_busy(const char *func, ulong timeout)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun int ret = wait_for_bit_le32(&nvm_regs_p->ctrl.raw,
70*4882a593Smuzhiyun NVM_WR, false, timeout, false);
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun return ret ? ERR_TIMEOUT : ERR_OK;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
flash_complete_operation(void)75*4882a593Smuzhiyun static inline int flash_complete_operation(void)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun u32 tmp;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun tmp = readl(&nvm_regs_p->ctrl.raw);
80*4882a593Smuzhiyun if (tmp & NVM_WRERR) {
81*4882a593Smuzhiyun printf("Error in Block Erase - Lock Bit may be set!\n");
82*4882a593Smuzhiyun flash_initiate_operation(NVMOP_NOP);
83*4882a593Smuzhiyun return ERR_PROTECTED;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun if (tmp & NVM_LVDERR) {
87*4882a593Smuzhiyun printf("Error in Block Erase - low-vol detected!\n");
88*4882a593Smuzhiyun flash_initiate_operation(NVMOP_NOP);
89*4882a593Smuzhiyun return ERR_NOT_ERASED;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun /* disable flash write or erase operation */
93*4882a593Smuzhiyun writel(NVM_WREN, &nvm_regs_p->ctrl.clr);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun return ERR_OK;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /*
99*4882a593Smuzhiyun * Erase flash sectors, returns:
100*4882a593Smuzhiyun * ERR_OK - OK
101*4882a593Smuzhiyun * ERR_INVAL - invalid sector arguments
102*4882a593Smuzhiyun * ERR_TIMEOUT - write timeout
103*4882a593Smuzhiyun * ERR_NOT_ERASED - Flash not erased
104*4882a593Smuzhiyun * ERR_UNKNOWN_FLASH_VENDOR - incorrect flash
105*4882a593Smuzhiyun */
flash_erase(flash_info_t * info,int s_first,int s_last)106*4882a593Smuzhiyun int flash_erase(flash_info_t *info, int s_first, int s_last)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun ulong sect_start, sect_end, flags;
109*4882a593Smuzhiyun int prot, sect;
110*4882a593Smuzhiyun int rc;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_MCHP) {
113*4882a593Smuzhiyun printf("Can't erase unknown flash type %08lx - aborted\n",
114*4882a593Smuzhiyun info->flash_id);
115*4882a593Smuzhiyun return ERR_UNKNOWN_FLASH_VENDOR;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun if ((s_first < 0) || (s_first > s_last)) {
119*4882a593Smuzhiyun printf("- no sectors to erase\n");
120*4882a593Smuzhiyun return ERR_INVAL;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun prot = 0;
124*4882a593Smuzhiyun for (sect = s_first; sect <= s_last; ++sect) {
125*4882a593Smuzhiyun if (info->protect[sect])
126*4882a593Smuzhiyun prot++;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun if (prot)
130*4882a593Smuzhiyun printf("- Warning: %d protected sectors will not be erased!\n",
131*4882a593Smuzhiyun prot);
132*4882a593Smuzhiyun else
133*4882a593Smuzhiyun printf("\n");
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /* erase on unprotected sectors */
136*4882a593Smuzhiyun for (sect = s_first; sect <= s_last; sect++) {
137*4882a593Smuzhiyun if (info->protect[sect])
138*4882a593Smuzhiyun continue;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /* disable interrupts */
141*4882a593Smuzhiyun flags = disable_interrupts();
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun /* write destination page address (physical) */
144*4882a593Smuzhiyun sect_start = CPHYSADDR(info->start[sect]);
145*4882a593Smuzhiyun writel(sect_start, &nvm_regs_p->addr.raw);
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun /* page erase */
148*4882a593Smuzhiyun flash_initiate_operation(NVMOP_PAGE_ERASE);
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /* wait */
151*4882a593Smuzhiyun rc = flash_wait_till_busy(__func__,
152*4882a593Smuzhiyun CONFIG_SYS_FLASH_ERASE_TOUT);
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun /* re-enable interrupts if necessary */
155*4882a593Smuzhiyun if (flags)
156*4882a593Smuzhiyun enable_interrupts();
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun if (rc != ERR_OK)
159*4882a593Smuzhiyun return rc;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun rc = flash_complete_operation();
162*4882a593Smuzhiyun if (rc != ERR_OK)
163*4882a593Smuzhiyun return rc;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /*
166*4882a593Smuzhiyun * flash content is updated but cache might contain stale
167*4882a593Smuzhiyun * data, so invalidate dcache.
168*4882a593Smuzhiyun */
169*4882a593Smuzhiyun sect_end = info->start[sect] + info->size / info->sector_count;
170*4882a593Smuzhiyun invalidate_dcache_range(info->start[sect], sect_end);
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun printf(" done\n");
174*4882a593Smuzhiyun return ERR_OK;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
page_erase(flash_info_t * info,int sect)177*4882a593Smuzhiyun int page_erase(flash_info_t *info, int sect)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun return 0;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /* Write a word to flash */
write_word(flash_info_t * info,ulong dest,ulong word)183*4882a593Smuzhiyun static int write_word(flash_info_t *info, ulong dest, ulong word)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun ulong flags;
186*4882a593Smuzhiyun int rc;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /* read flash to check if it is sufficiently erased */
189*4882a593Smuzhiyun if ((readl((void __iomem *)dest) & word) != word) {
190*4882a593Smuzhiyun printf("Error, Flash not erased!\n");
191*4882a593Smuzhiyun return ERR_NOT_ERASED;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun /* disable interrupts */
195*4882a593Smuzhiyun flags = disable_interrupts();
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /* update destination page address (physical) */
198*4882a593Smuzhiyun writel(CPHYSADDR(dest), &nvm_regs_p->addr.raw);
199*4882a593Smuzhiyun writel(word, &nvm_regs_p->data.raw);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun /* word write */
202*4882a593Smuzhiyun flash_initiate_operation(NVMOP_WORD_WRITE);
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun /* wait for operation to complete */
205*4882a593Smuzhiyun rc = flash_wait_till_busy(__func__, CONFIG_SYS_FLASH_WRITE_TOUT);
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /* re-enable interrupts if necessary */
208*4882a593Smuzhiyun if (flags)
209*4882a593Smuzhiyun enable_interrupts();
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (rc != ERR_OK)
212*4882a593Smuzhiyun return rc;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun return flash_complete_operation();
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun /*
218*4882a593Smuzhiyun * Copy memory to flash, returns:
219*4882a593Smuzhiyun * ERR_OK - OK
220*4882a593Smuzhiyun * ERR_TIMEOUT - write timeout
221*4882a593Smuzhiyun * ERR_NOT_ERASED - Flash not erased
222*4882a593Smuzhiyun */
write_buff(flash_info_t * info,uchar * src,ulong addr,ulong cnt)223*4882a593Smuzhiyun int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun ulong dst, tmp_le, len = cnt;
226*4882a593Smuzhiyun int i, l, rc;
227*4882a593Smuzhiyun uchar *cp;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun /* get lower word aligned address */
230*4882a593Smuzhiyun dst = (addr & ~3);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun /* handle unaligned start bytes */
233*4882a593Smuzhiyun l = addr - dst;
234*4882a593Smuzhiyun if (l != 0) {
235*4882a593Smuzhiyun tmp_le = 0;
236*4882a593Smuzhiyun for (i = 0, cp = (uchar *)dst; i < l; ++i, ++cp)
237*4882a593Smuzhiyun tmp_le |= *cp << (i * 8);
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun for (; (i < 4) && (cnt > 0); ++i, ++src, --cnt, ++cp)
240*4882a593Smuzhiyun tmp_le |= *src << (i * 8);
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun for (; (cnt == 0) && (i < 4); ++i, ++cp)
243*4882a593Smuzhiyun tmp_le |= *cp << (i * 8);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun rc = write_word(info, dst, tmp_le);
246*4882a593Smuzhiyun if (rc)
247*4882a593Smuzhiyun goto out;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun dst += 4;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun /* handle word aligned part */
253*4882a593Smuzhiyun while (cnt >= 4) {
254*4882a593Smuzhiyun tmp_le = src[0] | src[1] << 8 | src[2] << 16 | src[3] << 24;
255*4882a593Smuzhiyun rc = write_word(info, dst, tmp_le);
256*4882a593Smuzhiyun if (rc)
257*4882a593Smuzhiyun goto out;
258*4882a593Smuzhiyun src += 4;
259*4882a593Smuzhiyun dst += 4;
260*4882a593Smuzhiyun cnt -= 4;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun if (cnt == 0) {
264*4882a593Smuzhiyun rc = ERR_OK;
265*4882a593Smuzhiyun goto out;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /* handle unaligned tail bytes */
269*4882a593Smuzhiyun tmp_le = 0;
270*4882a593Smuzhiyun for (i = 0, cp = (uchar *)dst; (i < 4) && (cnt > 0); ++i, ++cp) {
271*4882a593Smuzhiyun tmp_le |= *src++ << (i * 8);
272*4882a593Smuzhiyun --cnt;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun for (; i < 4; ++i, ++cp)
276*4882a593Smuzhiyun tmp_le |= *cp << (i * 8);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun rc = write_word(info, dst, tmp_le);
279*4882a593Smuzhiyun out:
280*4882a593Smuzhiyun /*
281*4882a593Smuzhiyun * flash content updated by nvm controller but CPU cache might
282*4882a593Smuzhiyun * have stale data, so invalidate dcache.
283*4882a593Smuzhiyun */
284*4882a593Smuzhiyun invalidate_dcache_range(addr, addr + len);
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun printf(" done\n");
287*4882a593Smuzhiyun return rc;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
flash_print_info(flash_info_t * info)290*4882a593Smuzhiyun void flash_print_info(flash_info_t *info)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun int i;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun if (info->flash_id == FLASH_UNKNOWN) {
295*4882a593Smuzhiyun printf("missing or unknown FLASH type\n");
296*4882a593Smuzhiyun return;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun switch (info->flash_id & FLASH_VENDMASK) {
300*4882a593Smuzhiyun case FLASH_MAN_MCHP:
301*4882a593Smuzhiyun printf("Microchip Technology ");
302*4882a593Smuzhiyun break;
303*4882a593Smuzhiyun default:
304*4882a593Smuzhiyun printf("Unknown Vendor ");
305*4882a593Smuzhiyun break;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun switch (info->flash_id & FLASH_TYPEMASK) {
309*4882a593Smuzhiyun case FLASH_MCHP100T:
310*4882a593Smuzhiyun printf("Internal (8 Mbit, 64 x 16k)\n");
311*4882a593Smuzhiyun break;
312*4882a593Smuzhiyun default:
313*4882a593Smuzhiyun printf("Unknown Chip Type\n");
314*4882a593Smuzhiyun break;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun printf(" Size: %ld MB in %d Sectors\n",
318*4882a593Smuzhiyun info->size >> 20, info->sector_count);
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun printf(" Sector Start Addresses:");
321*4882a593Smuzhiyun for (i = 0; i < info->sector_count; ++i) {
322*4882a593Smuzhiyun if ((i % 5) == 0)
323*4882a593Smuzhiyun printf("\n ");
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun printf(" %08lX%s", info->start[i],
326*4882a593Smuzhiyun info->protect[i] ? " (RO)" : " ");
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun printf("\n");
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
flash_init(void)331*4882a593Smuzhiyun unsigned long flash_init(void)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun unsigned long size = 0;
334*4882a593Smuzhiyun struct udevice *dev;
335*4882a593Smuzhiyun int bank;
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun /* probe every MTD device */
338*4882a593Smuzhiyun for (uclass_first_device(UCLASS_MTD, &dev); dev;
339*4882a593Smuzhiyun uclass_next_device(&dev)) {
340*4882a593Smuzhiyun /* nop */
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun /* calc total flash size */
344*4882a593Smuzhiyun for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank)
345*4882a593Smuzhiyun size += flash_info[bank].size;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun return size;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
pic32_flash_bank_init(flash_info_t * info,ulong base,ulong size)350*4882a593Smuzhiyun static void pic32_flash_bank_init(flash_info_t *info,
351*4882a593Smuzhiyun ulong base, ulong size)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun ulong sect_size;
354*4882a593Smuzhiyun int sect;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /* device & manufacturer code */
357*4882a593Smuzhiyun info->flash_id = FLASH_MAN_MCHP | FLASH_MCHP100T;
358*4882a593Smuzhiyun info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
359*4882a593Smuzhiyun info->size = size;
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun /* update sector (i.e page) info */
362*4882a593Smuzhiyun sect_size = info->size / info->sector_count;
363*4882a593Smuzhiyun for (sect = 0; sect < info->sector_count; sect++) {
364*4882a593Smuzhiyun info->start[sect] = base;
365*4882a593Smuzhiyun /* protect each sector by default */
366*4882a593Smuzhiyun info->protect[sect] = 1;
367*4882a593Smuzhiyun base += sect_size;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
pic32_flash_probe(struct udevice * dev)371*4882a593Smuzhiyun static int pic32_flash_probe(struct udevice *dev)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun void *blob = (void *)gd->fdt_blob;
374*4882a593Smuzhiyun int node = dev_of_offset(dev);
375*4882a593Smuzhiyun const char *list, *end;
376*4882a593Smuzhiyun const fdt32_t *cell;
377*4882a593Smuzhiyun unsigned long addr, size;
378*4882a593Smuzhiyun int parent, addrc, sizec;
379*4882a593Smuzhiyun flash_info_t *info;
380*4882a593Smuzhiyun int len, idx;
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun /*
383*4882a593Smuzhiyun * decode regs. there are multiple reg tuples, and they need to
384*4882a593Smuzhiyun * match with reg-names.
385*4882a593Smuzhiyun */
386*4882a593Smuzhiyun parent = fdt_parent_offset(blob, node);
387*4882a593Smuzhiyun fdt_support_default_count_cells(blob, parent, &addrc, &sizec);
388*4882a593Smuzhiyun list = fdt_getprop(blob, node, "reg-names", &len);
389*4882a593Smuzhiyun if (!list)
390*4882a593Smuzhiyun return -ENOENT;
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun end = list + len;
393*4882a593Smuzhiyun cell = fdt_getprop(blob, node, "reg", &len);
394*4882a593Smuzhiyun if (!cell)
395*4882a593Smuzhiyun return -ENOENT;
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun for (idx = 0, info = &flash_info[0]; list < end;) {
398*4882a593Smuzhiyun addr = fdt_translate_address((void *)blob, node, cell + idx);
399*4882a593Smuzhiyun size = fdt_addr_to_cpu(cell[idx + addrc]);
400*4882a593Smuzhiyun len = strlen(list);
401*4882a593Smuzhiyun if (!strncmp(list, "nvm", len)) {
402*4882a593Smuzhiyun /* NVM controller */
403*4882a593Smuzhiyun nvm_regs_p = ioremap(addr, size);
404*4882a593Smuzhiyun } else if (!strncmp(list, "bank", 4)) {
405*4882a593Smuzhiyun /* Flash bank: use kseg0 cached address */
406*4882a593Smuzhiyun pic32_flash_bank_init(info, CKSEG0ADDR(addr), size);
407*4882a593Smuzhiyun info++;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun idx += addrc + sizec;
410*4882a593Smuzhiyun list += len + 1;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun /* disable flash write/erase operations */
414*4882a593Smuzhiyun writel(NVM_WREN, &nvm_regs_p->ctrl.clr);
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun #if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
417*4882a593Smuzhiyun /* monitor protection ON by default */
418*4882a593Smuzhiyun flash_protect(FLAG_PROTECT_SET,
419*4882a593Smuzhiyun CONFIG_SYS_MONITOR_BASE,
420*4882a593Smuzhiyun CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
421*4882a593Smuzhiyun &flash_info[0]);
422*4882a593Smuzhiyun #endif
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun #ifdef CONFIG_ENV_IS_IN_FLASH
425*4882a593Smuzhiyun /* ENV protection ON by default */
426*4882a593Smuzhiyun flash_protect(FLAG_PROTECT_SET,
427*4882a593Smuzhiyun CONFIG_ENV_ADDR,
428*4882a593Smuzhiyun CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
429*4882a593Smuzhiyun &flash_info[0]);
430*4882a593Smuzhiyun #endif
431*4882a593Smuzhiyun return 0;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun static const struct udevice_id pic32_flash_ids[] = {
435*4882a593Smuzhiyun { .compatible = "microchip,pic32mzda-flash" },
436*4882a593Smuzhiyun {}
437*4882a593Smuzhiyun };
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun U_BOOT_DRIVER(pic32_flash) = {
440*4882a593Smuzhiyun .name = "pic32_flash",
441*4882a593Smuzhiyun .id = UCLASS_MTD,
442*4882a593Smuzhiyun .of_match = pic32_flash_ids,
443*4882a593Smuzhiyun .probe = pic32_flash_probe,
444*4882a593Smuzhiyun };
445