]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/pdk.git/blob - packages/ti/board/src/flash/nor/gpmc/nor_gpmc.c
board-rtos: add to PDK
[processor-sdk/pdk.git] / packages / ti / board / src / flash / nor / gpmc / nor_gpmc.c
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