1 /*\r
2 * Copyright (c) 2016 - 2019, Texas Instruments Incorporated\r
3 * All rights reserved.\r
4 *\r
5 * Redistribution and use in source and binary forms, with or without\r
6 * modification, are permitted provided that the following conditions\r
7 * are met:\r
8 *\r
9 * * Redistributions of source code must retain the above copyright\r
10 * notice, this list of conditions and the following disclaimer.\r
11 *\r
12 * * Redistributions in binary form must reproduce the above copyright\r
13 * notice, this list of conditions and the following disclaimer in the\r
14 * documentation and/or other materials provided with the distribution.\r
15 *\r
16 * * Neither the name of Texas Instruments Incorporated nor the names of\r
17 * its contributors may be used to endorse or promote products derived\r
18 * from this software without specific prior written permission.\r
19 *\r
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\r
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\r
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\r
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
31 *\r
32 */\r
33 \r
34 #include <ti/board/src/flash/nor/gpmc/nor_gpmc.h>\r
35 \r
36 static NOR_HANDLE Nor_gpmcOpen(uint32_t norIntf, uint32_t portNum, void *params);\r
37 static void Nor_gpmcClose(NOR_HANDLE handle);\r
38 static NOR_STATUS Nor_gpmcRead(NOR_HANDLE handle, uint32_t addr,\r
39 uint32_t len, uint8_t *buf, uint32_t mode);\r
40 static NOR_STATUS Nor_gpmcWrite(NOR_HANDLE handle, uint32_t addr,\r
41 uint32_t len, uint8_t *buf, uint32_t mode);\r
42 static NOR_STATUS Nor_gpmcErase(NOR_HANDLE handle, int32_t block, bool blkErase);\r
43 \r
44 /* NAND function table for NAND GPMC interface implementation */\r
45 const NOR_FxnTable Nor_gpmcFxnTable =\r
46 {\r
47 &Nor_gpmcOpen,\r
48 &Nor_gpmcClose,\r
49 &Nor_gpmcRead,\r
50 &Nor_gpmcWrite,\r
51 &Nor_gpmcErase,\r
52 };\r
53 \r
54 NOR_Info Nor_gpmcInfo =\r
55 {\r
56 0, /* hwHandle */\r
57 0, /* manufacturerId */\r
58 0, /* deviceId */\r
59 0, /* busWidth */\r
60 NOR_NUM_BLOCKS, /* blockCnt */\r
61 NOR_NUM_PAGES_PER_BLOCK, /* pageCnt */\r
62 NOR_PAGE_SIZE, /* pageSize */\r
63 0, /* baseAddr */\r
64 NOR_SECTOR_SIZE /* sectorSize */\r
65 };\r
66 \r
67 static volatile uint8_t *Nor_gpmcMakeAddr(NOR_HANDLE handle,\r
68 uint32_t blkAddr,\r
69 uint32_t offset)\r
70 {\r
71 NOR_Info *norGpmcInfo = (NOR_Info *)handle;\r
72 uint32_t addr;\r
73 \r
74 if (norGpmcInfo->busWidth == NOR_BUSWIDTH_8BITS)\r
75 {\r
76 addr = blkAddr + offset;\r
77 }\r
78 else\r
79 {\r
80 addr = blkAddr + (offset << 1);\r
81 }\r
82 \r
83 return ((volatile uint8_t *) addr);\r
84 }\r
85 \r
86 static void Nor_gpmcMakeCmd(NOR_HANDLE handle,\r
87 uint32_t cmd,\r
88 void *cmdbuf)\r
89 {\r
90 NOR_Info *norGpmcInfo = (NOR_Info *)handle;\r
91 uint32_t i;\r
92 uint8_t *cp = (uint8_t *) cmdbuf;\r
93 \r
94 for (i = (1 << norGpmcInfo->busWidth); i > 0; i--)\r
95 {\r
96 *cp = (i & ((1 << norGpmcInfo->busWidth) - 1)) ? 0x00 : cmd;\r
97 cp++;\r
98 }\r
99 }\r
100 \r
101 static void Nor_gpmcWriteCmd(NOR_HANDLE handle, uint32_t blkAddr,\r
102 uint32_t offset, uint32_t cmd)\r
103 {\r
104 NOR_Info *norGpmcInfo = (NOR_Info *)handle;\r
105 volatile NOR_Ptr addr;\r
106 NOR_Data cmdword;\r
107 \r
108 addr.cp = Nor_gpmcMakeAddr(handle, blkAddr, offset);\r
109 Nor_gpmcMakeCmd(handle, cmd, &cmdword);\r
110 if (norGpmcInfo->busWidth == NOR_BUSWIDTH_8BITS)\r
111 {\r
112 /* Bus width 8 bit */\r
113 *addr.cp = cmdword.c;\r
114 }\r
115 else\r
116 {\r
117 /* Default Bus width 16 bit */\r
118 *addr.wp = cmdword.w;\r
119 }\r
120 }\r
121 \r
122 static void Nor_gpmcPrefixCommands(NOR_HANDLE handle)\r
123 {\r
124 NOR_Info *norGpmcInfo = (NOR_Info *)handle;\r
125 \r
126 Nor_gpmcWriteCmd(handle, norGpmcInfo->baseAddr, NOR_CMD0_ADDR, NOR_CMD0);\r
127 Nor_gpmcWriteCmd(handle, norGpmcInfo->baseAddr, NOR_CMD1_ADDR, NOR_CMD1);\r
128 }\r
129 \r
130 static void Nor_gpmcWriteData(NOR_HANDLE handle, uint32_t address, uint32_t data)\r
131 {\r
132 NOR_Info *norGpmcInfo = (NOR_Info *)handle;\r
133 volatile NOR_Ptr pAddr;\r
134 NOR_Data dataword;\r
135 \r
136 dataword.l = data;\r
137 pAddr.cp = (volatile uint8_t *)address;\r
138 \r
139 if (norGpmcInfo->busWidth == NOR_BUSWIDTH_8BITS)\r
140 {\r
141 /* Bus width 8 bit */\r
142 *pAddr.cp = dataword.c;\r
143 }\r
144 else\r
145 {\r
146 /* Default Bus width 16 bit */\r
147 *pAddr.wp = dataword.w;\r
148 }\r
149 }\r
150 \r
151 uint32_t Nor_gpmcReadData(NOR_HANDLE handle, uint32_t address,\r
152 uint32_t offset)\r
153 {\r
154 NOR_Info *norGpmcInfo = (NOR_Info *)handle;\r
155 volatile NOR_Ptr pAddr;\r
156 NOR_Data dataword;\r
157 \r
158 dataword.l = 0x00000000;\r
159 \r
160 pAddr.cp = Nor_gpmcMakeAddr(handle, address, offset);\r
161 \r
162 if (norGpmcInfo->busWidth == NOR_BUSWIDTH_8BITS)\r
163 {\r
164 /* Bus width 8 bit */\r
165 dataword.c = *pAddr.cp;\r
166 }\r
167 else\r
168 {\r
169 /* Default Bus width 16 bit */\r
170 dataword.w = *pAddr.wp;\r
171 }\r
172 return dataword.l;\r
173 }\r
174 \r
175 static void Nor_delay(uint32_t usec)\r
176 {\r
177 #if defined (evmAM335x)\r
178 /* Board_delay is currently not supported for AM devices */\r
179 volatile uint32_t count = usec * 1000000;\r
180 \r
181 while (count)\r
182 {\r
183 count--;\r
184 if (0U == count)\r
185 {\r
186 break;\r
187 }\r
188 }\r
189 #elif defined (evmK2G)\r
190 Board_delay(usec);\r
191 #else\r
192 #endif\r
193 }\r
194 \r
195 static void Nor_gpmcSoftReset(NOR_HANDLE handle)\r
196 {\r
197 NOR_Info *norGpmcInfo = (NOR_Info *)handle;\r
198 \r
199 /* Reset Flash to be in Read Array Mode*/\r
200 Nor_gpmcWriteCmd(handle, norGpmcInfo->baseAddr, NOR_CMD2_ADDR, NOR_CMD_RESET);\r
201 Nor_delay(1);\r
202 }\r
203 \r
204 static NOR_STATUS Nor_gpmcReadId(NOR_HANDLE handle)\r
205 {\r
206 NOR_STATUS retVal = NOR_FAIL;\r
207 NOR_Info *norGpmcInfo = (NOR_Info *)handle;\r
208 uint32_t manfID, devID;\r
209 \r
210 Nor_gpmcSoftReset(handle);\r
211 \r
212 /* Write read ID commands*/\r
213 Nor_gpmcPrefixCommands(handle);\r
214 Nor_gpmcWriteCmd(handle, norGpmcInfo->baseAddr, NOR_CMD2_ADDR,\r
215 NOR_CMD_RDID);\r
216 \r
217 /* Read manufacturer's and device ID */\r
218 manfID = Nor_gpmcReadData(handle, norGpmcInfo->baseAddr, NOR_MANFID_ADDR);\r
219 devID = Nor_gpmcReadData(handle, norGpmcInfo->baseAddr, NOR_DEVID_ADDR0);\r
220 if ((manfID == NOR_MANF_ID) && (devID == NOR_DEVICE_ID))\r
221 {\r
222 Nor_gpmcInfo.manufacturerId = manfID;\r
223 Nor_gpmcInfo.deviceId = devID;\r
224 retVal = NOR_PASS;\r
225 }\r
226 \r
227 /* Exit back to read array mode */\r
228 Nor_gpmcSoftReset(handle);\r
229 \r
230 return (retVal);\r
231 }\r
232 \r
233 NOR_HANDLE Nor_gpmcOpen(uint32_t norIntf, uint32_t portNum, void *params)\r
234 {\r
235 GPMC_Params gpmcParams; /* GPMC params structure */\r
236 GPMC_Handle hwHandle; /* GPMC handle */\r
237 NOR_HANDLE norHandle = 0;\r
238 \r
239 /* Init GPMC driver */\r
240 GPMC_init();\r
241 \r
242 if (params)\r
243 {\r
244 memcpy(&gpmcParams, params, sizeof(GPMC_Params));\r
245 }\r
246 else\r
247 {\r
248 /* Use default GPMC config params if no params provided */\r
249 GPMC_Params_init(&gpmcParams);\r
250 }\r
251 hwHandle = (GPMC_Handle)GPMC_open(portNum, &gpmcParams);\r
252 \r
253 if (hwHandle)\r
254 {\r
255 GPMC_control(hwHandle, GPMC_V1_CMD_GETDEVADDR, (void *)(&Nor_gpmcInfo.baseAddr));\r
256 GPMC_control(hwHandle, GPMC_V1_CMD_GETDEVSIZE, (void *)(&Nor_gpmcInfo.busWidth));\r
257 \r
258 Nor_gpmcSoftReset((NOR_HANDLE)(&Nor_gpmcInfo));\r
259 if (Nor_gpmcReadId((NOR_HANDLE)(&Nor_gpmcInfo)) == NOR_PASS)\r
260 {\r
261 Nor_gpmcInfo.hwHandle = (uint32_t)hwHandle;\r
262 norHandle = (NOR_HANDLE)(&Nor_gpmcInfo);\r
263 }\r
264 }\r
265 \r
266 return (norHandle);\r
267 }\r
268 \r
269 void Nor_gpmcClose(NOR_HANDLE handle)\r
270 {\r
271 NOR_Info *norGpmcInfo;\r
272 GPMC_Handle gpmcHandle;\r
273 \r
274 if (handle)\r
275 {\r
276 norGpmcInfo = (NOR_Info *)handle;\r
277 gpmcHandle = (GPMC_Handle)norGpmcInfo->hwHandle;\r
278 \r
279 if (gpmcHandle)\r
280 {\r
281 GPMC_close(gpmcHandle);\r
282 }\r
283 }\r
284 }\r
285 \r
286 static NOR_STATUS Nor_gpmcIsSetAll (NOR_HANDLE handle,\r
287 uint32_t addr,\r
288 uint8_t mask)\r
289 {\r
290 NOR_Info *norGpmcInfo = (NOR_Info *)handle;\r
291 volatile NOR_Ptr address;\r
292 NOR_Data maskword;\r
293 bool retval = true;\r
294 uint32_t temp;\r
295 \r
296 maskword.l = 0x00000000;\r
297 \r
298 address.cp = Nor_gpmcMakeAddr(handle, addr, 0);\r
299 temp = *address.wp;\r
300 Nor_gpmcMakeCmd (handle, mask, &maskword);\r
301 if (norGpmcInfo->busWidth == NOR_BUSWIDTH_8BITS)\r
302 {\r
303 temp = *address.cp;\r
304 retval = ((maskword.c & temp) == maskword.c);\r
305 }\r
306 else\r
307 {\r
308 temp = *address.wp;\r
309 retval = ((maskword.w & temp) == maskword.w);\r
310 }\r
311 return retval;\r
312 }\r
313 \r
314 static NOR_STATUS Nor_gpmcWaitReady(NOR_HANDLE handle, uint32_t addr, uint32_t mask, uint32_t timeOut)\r
315 {\r
316 NOR_STATUS status = NOR_PASS;\r
317 \r
318 do\r
319 {\r
320 if (Nor_gpmcIsSetAll(handle, addr, mask))\r
321 {\r
322 break;\r
323 }\r
324 \r
325 timeOut--;\r
326 if (!timeOut) {\r
327 status = NOR_TIMEOUT;\r
328 break;\r
329 }\r
330 \r
331 } while (1);\r
332 \r
333 return (status);\r
334 }\r
335 \r
336 NOR_STATUS Nor_gpmcRead(NOR_HANDLE handle, uint32_t addr,\r
337 uint32_t len, uint8_t *buf, uint32_t mode)\r
338 {\r
339 NOR_Info *norGpmcInfo;\r
340 GPMC_Transaction transaction;\r
341 GPMC_Handle gpmcHandle;\r
342 bool ret;\r
343 \r
344 if ((!handle) || ((addr + len) > NOR_SIZE))\r
345 {\r
346 return NOR_INVALID_PARAM;\r
347 }\r
348 \r
349 norGpmcInfo = (NOR_Info *)handle;\r
350 if (!norGpmcInfo->hwHandle)\r
351 {\r
352 return NOR_FAIL;\r
353 }\r
354 gpmcHandle = (GPMC_Handle)norGpmcInfo->hwHandle;\r
355 \r
356 transaction.offset = addr;\r
357 transaction.txBuf = NULL;\r
358 transaction.rxBuf = (void *)buf;\r
359 transaction.count = len;\r
360 \r
361 ret = GPMC_transfer(gpmcHandle, &transaction);\r
362 if (ret == true)\r
363 {\r
364 return NOR_PASS;\r
365 }\r
366 else\r
367 {\r
368 return NOR_FAIL;\r
369 }\r
370 }\r
371 \r
372 /* Write one byte (or one 16-bit word) data */\r
373 static NOR_STATUS Nor_gpmcWriteOne(NOR_HANDLE handle, uint32_t offsetAddr,\r
374 uint32_t data)\r
375 {\r
376 NOR_STATUS status = NOR_PASS;\r
377 NOR_Info *norGpmcInfo = (NOR_Info *)handle;\r
378 uint32_t flag = 0;\r
379 uint32_t address = norGpmcInfo->baseAddr + offsetAddr;\r
380 \r
381 /* Send Commands*/\r
382 Nor_gpmcPrefixCommands(handle);\r
383 Nor_gpmcWriteCmd(handle, norGpmcInfo->baseAddr,\r
384 NOR_CMD2_ADDR, NOR_CMD_PROG);\r
385 Nor_gpmcWriteData(handle, address, data);\r
386 \r
387 /* Wait for ready.*/\r
388 while (1)\r
389 {\r
390 if ((Nor_gpmcReadData(handle, address, 0) &\r
391 (BIT7 | BIT15)) == (data & (BIT7 | BIT15)))\r
392 {\r
393 flag = 1U;\r
394 }\r
395 else\r
396 {\r
397 if (Nor_gpmcWaitReady(handle, address, BIT5, NOR_WRITE_TIMEOUT) == NOR_PASS)\r
398 {\r
399 if ((Nor_gpmcReadData(handle, address, 0) &\r
400 (BIT7 | BIT15)) != (data & (BIT7 | BIT15)))\r
401 {\r
402 status = NOR_FAIL;\r
403 }\r
404 flag = 1U;\r
405 }\r
406 }\r
407 \r
408 if (flag == 1U)\r
409 {\r
410 break;\r
411 }\r
412 }\r
413 \r
414 /* Return Read Mode*/\r
415 Nor_gpmcSoftReset(handle);\r
416 \r
417 return (status);\r
418 }\r
419 \r
420 NOR_STATUS Nor_gpmcWrite(NOR_HANDLE handle, uint32_t addr, uint32_t len,\r
421 uint8_t *buf, uint32_t mode)\r
422 {\r
423 NOR_Info *norGpmcInfo;\r
424 uint8_t *bufPt8 = buf;\r
425 uint16_t *bufPt16 = (uint16_t *)buf;\r
426 uint32_t i;\r
427 uint32_t offsetAddr = addr;\r
428 \r
429 if ((!handle) || ((addr + len) > NOR_SIZE))\r
430 {\r
431 return NOR_INVALID_PARAM;\r
432 }\r
433 \r
434 norGpmcInfo = (NOR_Info *)handle;\r
435 if (!norGpmcInfo->hwHandle)\r
436 {\r
437 return NOR_FAIL;\r
438 }\r
439 \r
440 if (norGpmcInfo->busWidth == NOR_BUSWIDTH_8BITS)\r
441 {\r
442 for (i = 0; i < len; i++)\r
443 {\r
444 if (Nor_gpmcWriteOne(handle, offsetAddr, (uint32_t)(*bufPt8)) !=\r
445 NOR_PASS)\r
446 {\r
447 return NOR_FAIL;\r
448 }\r
449 bufPt8++;\r
450 offsetAddr++;\r
451 }\r
452 }\r
453 else\r
454 {\r
455 for (i = 0; i < len/2; i++)\r
456 {\r
457 if (Nor_gpmcWriteOne(handle, offsetAddr, (uint32_t)(*bufPt16)) !=\r
458 NOR_PASS)\r
459 {\r
460 return NOR_FAIL;\r
461 }\r
462 bufPt16++;\r
463 offsetAddr += 2;\r
464 }\r
465 }\r
466 \r
467 return NOR_PASS;\r
468 }\r
469 \r
470 NOR_STATUS Nor_gpmcErase(NOR_HANDLE handle, int32_t sector, bool blkErase)\r
471 {\r
472 NOR_STATUS status = NOR_PASS;\r
473 NOR_Info *norGpmcInfo;\r
474 uint32_t sectorAddr;\r
475 uint32_t timeOut;\r
476 \r
477 if ((!handle) || (sector >= NOR_NUM_SECTORS))\r
478 {\r
479 return NOR_INVALID_PARAM;\r
480 }\r
481 \r
482 norGpmcInfo = (NOR_Info *)handle;\r
483 if (!norGpmcInfo->hwHandle)\r
484 {\r
485 return NOR_FAIL;\r
486 }\r
487 \r
488 Nor_gpmcPrefixCommands(handle);\r
489 Nor_gpmcWriteCmd(handle, norGpmcInfo->baseAddr, NOR_CMD2_ADDR, NOR_CMD_BLK_ERASE_SETUP);\r
490 Nor_gpmcPrefixCommands(handle);\r
491 \r
492 /* Send commands */\r
493 if (sector == NOR_BE_SECTOR_NUM)\r
494 {\r
495 sectorAddr = 0;\r
496 timeOut = NOR_BULK_ERASE_TIMEOUT;\r
497 Nor_gpmcWriteCmd(handle, NOR_CMD0_ADDR, 0x0, NOR_CMD_BULK_ERASE);\r
498 }\r
499 else\r
500 {\r
501 sectorAddr = norGpmcInfo->baseAddr + sector * NOR_SECTOR_SIZE;\r
502 timeOut = NOR_SECTOR_ERASE_TIMEOUT;\r
503 Nor_gpmcWriteCmd(handle, sectorAddr, 0x0, NOR_CMD_BLK_ERASE);\r
504 }\r
505 \r
506 status = Nor_gpmcWaitReady(handle, sectorAddr, BIT7, timeOut);\r
507 \r
508 /* Flash Mode: Read Array*/\r
509 Nor_gpmcSoftReset(handle);\r
510 \r
511 return (status);\r
512 }\r