1 /*
2 *
3 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the
16 * distribution.
17 *
18 * Neither the name of Texas Instruments Incorporated nor the names of
19 * its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
38 /************************************************************************************
39 * FILE PURPOSE: C66x Device Specific functions
40 ************************************************************************************
41 * FILE NAME: c66x.c
42 *
43 * DESCRIPTION: Implements the device specific functions for the IBL
44 *
45 * @file c66x.c
46 *
47 * @brief
48 * This file implements the device specific functions for the IBL
49 *
50 ************************************************************************************/
51 #include "ibl.h"
52 #include "iblloc.h"
53 #include "iblcfg.h"
54 #include "device.h"
55 #include "pllapi.h"
56 #include "emif31api.h"
57 #include "pscapi.h"
58 #include "gpio.h"
59 #include "qm_api.h"
60 #include "cpdma_api.h"
61 #include "pa_api.h"
62 #include "serdes_api.h"
63 #include "net.h"
64 #include "nandhwapi.h"
65 #include "nor_api.h"
66 #include "spi_api.h"
67 #include <string.h>
68 #include <stdint.h>
69 #include "target.h"
70 #include "uart.h"
72 #define PLL_DDR_INIT_LOOPMAX 10
73 #define IBL_RESULT_CODE_STR_LEN 20
74 #define IBL_RESULT_CODE_LOC 17
76 extern cregister unsigned int DNUM;
78 /**
79 * @brief Determine if an address is local
80 *
81 * @details
82 * Examines an input address to determine if it is a local address. Using the largest
83 * L2 size on the C6670.
84 */
85 bool address_is_local (Uint32 addr)
86 {
87 /* L2 */
88 if ((addr >= 0x00800000) && (addr < 0x00900000))
89 return (TRUE);
91 /* L1P */
92 if ((addr >= 0x00e00000) && (addr < 0x00e08000))
93 return (TRUE);
95 /* L2D */
96 if ((addr >= 0x00f00000) && (addr < 0x00f08000))
97 return (TRUE);
99 return (FALSE);
101 }
104 /**
105 * @brief Convert a local l1d, l1p or l2 address to a global address
106 *
107 * @details
108 * The global address is formed. If the address is not local then
109 * the input address is returned
110 */
111 Uint32 deviceLocalAddrToGlobal (Uint32 addr)
112 {
114 if (address_is_local (addr))
115 addr = (1 << 28) | (DNUM << 24) | addr;
117 return (addr);
119 }
122 /**
123 * @brief
124 * Enable the DDR
125 *
126 * @details
127 * The DDR controller on the c66x is an emif 4.0. The controller is
128 * initialized directly with the supplied values
129 */
130 void deviceDdrConfig (void)
131 {
132 uint32 loopcount=0;
133 int8 ddr_result_code_str[IBL_RESULT_CODE_STR_LEN] = "IBL Result code 0";
134 /* The emif registers must be made visible. MPAX mapping 2 is used */
135 DEVICE_REG_XMPAX_L(2) = 0x10000000 | 0xff; /* replacement addr + perm*/
136 DEVICE_REG_XMPAX_H(2) = 0x2100000B; /* base addr + seg size (64KB)*/
138 if (ibl.ddrConfig.configDdr != 0)
139 hwEmif4p0Enable (&ibl.ddrConfig.uEmif.emif4p0);
141 #ifdef PLL_REINIT_WORKAROUND
142 for (loopcount = 0; loopcount < PLL_DDR_INIT_LOOPMAX; loopcount++)
143 {
144 /* Calling MAIN, PA, DDR PLL init */
145 if (ibl.pllConfig[ibl_MAIN_PLL].doEnable == TRUE)
146 hwPllSetPll (MAIN_PLL,
147 ibl.pllConfig[ibl_MAIN_PLL].prediv,
148 ibl.pllConfig[ibl_MAIN_PLL].mult,
149 ibl.pllConfig[ibl_MAIN_PLL].postdiv);
151 if (ibl.pllConfig[ibl_NET_PLL].doEnable == TRUE)
152 hwPllSetCfgPll (DEVICE_PLL_BASE(NET_PLL),
153 ibl.pllConfig[ibl_NET_PLL].prediv,
154 ibl.pllConfig[ibl_NET_PLL].mult,
155 ibl.pllConfig[ibl_NET_PLL].postdiv,
156 ibl.pllConfig[ibl_MAIN_PLL].pllOutFreqMhz,
157 ibl.pllConfig[ibl_NET_PLL].pllOutFreqMhz);
159 if (ibl.pllConfig[ibl_DDR_PLL].doEnable == TRUE)
160 hwPllSetCfg2Pll (DEVICE_PLL_BASE(DDR_PLL),
161 ibl.pllConfig[ibl_DDR_PLL].prediv,
162 ibl.pllConfig[ibl_DDR_PLL].mult,
163 ibl.pllConfig[ibl_DDR_PLL].postdiv,
164 ibl.pllConfig[ibl_MAIN_PLL].pllOutFreqMhz,
165 ibl.pllConfig[ibl_DDR_PLL].pllOutFreqMhz);
167 if (ibl.ddrConfig.configDdr != 0)
168 hwEmif4p0Enable (&ibl.ddrConfig.uEmif.emif4p0);
170 if (ddr3_memory_test() == 0)
171 {
172 break;
173 }
174 }
175 /* Init UART again because we are re-initializing the PLL's */
176 uart_init();
178 if (loopcount < 10)
179 {
180 ddr_result_code_str[IBL_RESULT_CODE_LOC] = loopcount + '0';
181 }
182 else if ((loopcount >= 10) && (loopcount < 35))
183 {
184 ddr_result_code_str[IBL_RESULT_CODE_LOC] = loopcount + 'A';
185 }
186 else
187 {
188 ddr_result_code_str[IBL_RESULT_CODE_LOC] = loopcount + 'Z';
189 }
191 if (loopcount == PLL_DDR_INIT_LOOPMAX)
192 {
193 uart_write_string("IBL: DDR INITIALIZATION FAILED",0);
194 }
195 else
196 {
197 uart_write_string("IBL: PLL and DDR Initialization Complete",0);
198 /* Clear the 16MB DDR3 memory - Workaround - should be removed after Linux fixes the issue */
199 ddr3_memory_zero(16);
200 }
201 uart_write_string(ddr_result_code_str,0);
202 #endif
203 }
207 /**
208 * @brief Enable EMIF25 or SPI interface to the NAND
209 *
210 */
211 int32 deviceConfigureForNand(void)
212 {
214 return (0);
216 }
218 /**
219 * @brief
220 * Return the base memory address for emif25 in a given chip select space
221 */
222 uint32 deviceEmif25MemBase (int32 cs)
223 {
224 switch (cs) {
226 case 2: return (TARGET_MEM_NAND_CS_2);
228 case 3: return (TARGET_MEM_NAND_CS_3);
230 case 4: return (TARGET_MEM_NAND_CS_4);
232 case 5: return (TARGET_MEM_NAND_CS_5);
234 }
236 return (0xffffffff);
238 }
241 /**
242 * @brief
243 * Return the PSC number for NAND/NOR through emif. Only 6678 has the emif
244 */
245 Int32 deviceEmifPscNum (void)
246 {
247 Uint32 v;
249 v = *((Uint32 *)DEVICE_JTAG_ID_REG);
250 v &= DEVICE_JTAG_ID_MASK;
251 if (v == DEVICE_C6678_JTAG_ID_VAL)
252 return (TARGET_PWR_EMIF_C6678);
254 /* Return a negative number to indicate no PSC module is associated with NAND */
255 return (-1);
257 }
261 /**
262 * @brief
263 * The e-fuse mac address is loaded
264 */
265 void deviceLoadDefaultEthAddress (uint8 *maddr)
266 {
267 uint32 macA, macB;
269 /* Read the e-fuse mac address */
270 macA = *((uint32 *)0x2620110);
271 macB = *((uint32 *)0x2620114);
273 maddr[0] = (macB >> 8) & 0xff;
274 maddr[1] = (macB >> 0) & 0xff;
275 maddr[2] = (macA >> 24) & 0xff;
276 maddr[3] = (macA >> 16) & 0xff;
277 maddr[4] = (macA >> 8) & 0xff;
278 maddr[5] = (macA >> 0) & 0xff;
279 }
282 /**
283 * @brief
284 * Compile time queue manager information
285 */
286 #define DEVICE_NUM_RX_CPPIS 1
287 #define DEVICE_NUM_TX_CPPIS 1
288 #define DEVICE_NUM_CPPIS (DEVICE_NUM_RX_CPPIS + DEVICE_NUM_TX_CPPIS)
290 /* The linking RAM */
291 #pragma DATA_SECTION(qm_linkram_buf, ".linkram")
292 #pragma DATA_ALIGN(qm_linkram_buf, 16)
293 uint8 qm_linkram_buf[DEVICE_NUM_CPPIS * 2 * (sizeof(uint32)/sizeof(uint8))];
296 /* The CPPI RAM */
297 #pragma DATA_SECTION(qm_cppi_buf, ".cppi")
298 #pragma DATA_ALIGN(qm_cppi_buf, 16)
299 uint8 qm_cppi_buf[QM_DESC_SIZE_BYTES * DEVICE_NUM_CPPIS];
302 /* The rx data buffers */
303 #pragma DATA_SECTION(qm_buffer, ".mac_buffer")
304 #pragma DATA_ALIGN(qm_buffer, 16)
305 uint8 qm_buffer[MAX_SIZE_STREAM_BUFFER * DEVICE_NUM_RX_CPPIS];
307 const qmConfig_t qmConfig = {
308 (UINT32) qm_linkram_buf,
309 sizeof (qm_cppi_buf),
310 (UINT32) qm_cppi_buf,
312 DEVICE_NUM_CPPIS,
313 DEVICE_QM_FREE_Q
314 };
316 /**
317 * @brief
318 * Return the queue manager memory configuration information
319 */
320 void *targetGetQmConfig (void)
321 {
322 return ((void *)&qmConfig);
323 }
325 /**
326 * @brief
327 * Attach a packet buffer to each descriptor and push onto the linked buffer queue
328 */
329 void targetInitQs (void)
330 {
331 int32 i;
332 qmHostDesc_t *hd;
334 for (i = 0; i < DEVICE_NUM_RX_CPPIS; i++) {
336 hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
337 hd->buffLen = sizeof (qm_buffer) / DEVICE_NUM_CPPIS;
338 hd->buffPtr = (UINT32) &(qm_buffer[MAX_SIZE_STREAM_BUFFER * i]);
339 hd->nextBDPtr = 0;
340 hd->origBufferLen = MAX_SIZE_STREAM_BUFFER;
341 hd->origBuffPtr = hd->buffPtr;
343 hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
345 }
348 for (i = 0; i < DEVICE_NUM_TX_CPPIS; i++) {
350 hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
351 hd->buffLen = 0;
352 hd->buffPtr = 0;
353 hd->nextBDPtr = 0;
354 hd->origBufferLen = 0;
355 hd->origBuffPtr = 0;
357 hwQmQueuePush (hd, DEVICE_QM_TX_Q, QM_DESC_SIZE_BYTES);
359 }
362 }
366 const cpdmaRxCfg_t cpdmaEthRxCfg = {
368 DEVICE_PA_CDMA_RX_CHAN_CFG_BASE, /* Base address of PA CPDMA rx config registers */
369 DEVICE_PA_CDMA_RX_NUM_CHANNELS, /* Number of rx channels */
371 DEVICE_PA_CDMA_RX_FLOW_CFG_BASE, /* Base address of PA CPDMA rx flow registers */
372 DEVICE_PA_CDMA_RX_NUM_FLOWS, /* Number of rx flows */
374 0, /* Queue manager for descriptor / buffer for received packets */
375 DEVICE_QM_LNK_BUF_Q, /* Queue of descriptors /buffers for received packets */
377 0, /* Queue manager for received packets */
378 DEVICE_QM_RCV_Q, /* Queue for received packets (overridden by PA) */
380 DEVICE_RX_CDMA_TIMEOUT_COUNT /* Teardown maximum loop wait */
381 };
384 /**
385 * @brief
386 * Return the cpdma configuration information
387 */
388 void *targetGetCpdmaRxConfig (void)
389 {
390 return ((void *)&cpdmaEthRxCfg);
392 }
395 const cpdmaTxCfg_t cpdmaEthTxCfg = {
397 DEVICE_PA_CDMA_GLOBAL_CFG_BASE, /* Base address of global config registers */
398 DEVICE_PA_CDMA_TX_CHAN_CFG_BASE, /* Base address of PA CPDMA tx config registers */
399 DEVICE_PA_CDMA_TX_NUM_CHANNELS /* Number of tx channels */
401 };
404 /**
405 * @brief
406 * return the tx cpdma configuration information
407 */
408 void *targetGetCpdmaTxConfig (void)
409 {
410 return ((void *)&cpdmaEthTxCfg);
412 }
414 /**
415 * @brief
416 * Configure the PA
417 */
418 void targetPaConfig (uint8 *macAddr)
419 {
420 paConfig_t paCfg;
421 qmHostDesc_t *hd;
422 SINT16 ret;
424 /* Filter everything except the desired mac address and the broadcast mac */
425 paCfg.mac0ms = ((uint32)macAddr[0] << 24) | ((uint32)macAddr[1] << 16) | ((uint32)macAddr[2] << 8) | (uint32)(macAddr[3]);
426 paCfg.mac0ls = ((uint32)macAddr[4] << 24) | ((uint32)macAddr[5] << 16);
428 paCfg.mac1ms = 0xffffffff;
429 paCfg.mac1ls = 0xffff0000;
431 paCfg.rxQnum = DEVICE_QM_RCV_Q;
433 /* Form the configuration command in a buffer linked to a descriptor */
434 hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
435 paCfg.cmdBuf = (uint8 *)hd->origBuffPtr;
437 ret = hwPaEnable (&paCfg);
438 if (ret != 0) {
439 iblStatus.iblFail = ibl_FAIL_CODE_PA;
440 return;
441 }
444 /* Send the command to the PA through the QM */
445 hd->softwareInfo0 = PA_MAGIC_ID;
446 hd->buffLen = 16;
447 QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, 16);
449 /* Set the return Queue */
450 QM_DESC_PINFO_SET_QM (hd->packetInfo, 0);
451 QM_DESC_PINFO_SET_QUEUE (hd->packetInfo, DEVICE_QM_LNK_BUF_Q);
453 hwQmQueuePush (hd, DEVICE_QM_PA_CFG_Q, QM_DESC_SIZE_BYTES);
456 }
458 /**
459 * @brief
460 * Chip level SGMII serdes configuration
461 *
462 * @details
463 * Both lanes are always setup, regardless of the port value
464 */
465 void targetSgmiiSerdesConfig (int32 port, void *viblSgmii)
466 {
467 serdesConfig_t scfg;
468 iblSgmii_t *sgmii = (iblSgmii_t *)viblSgmii;
470 scfg.cfg = sgmii->auxConfig;
471 scfg.nLanes = 2;
472 scfg.rxCfg[0] = scfg.rxCfg[1] = sgmii->rxConfig;
473 scfg.txCfg[0] = scfg.txCfg[1] = sgmii->txConfig;
475 hwSerdesConfig (TARGET_SGMII_SERDES_BASE, &scfg);
477 hwSerdesWaitLock (TARGET_SGMII_SERDES_STATUS_BASE);
479 }
482 Int32 targetMacSend (void *vptr_device, Uint8* buffer, int num_bytes)
483 {
484 qmHostDesc_t *hd;
485 NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
486 int i;
489 /* Must always setup the descriptor to have the minimum packet length */
490 if (num_bytes < 64)
491 num_bytes = 64;
494 for (i = 0, hd = NULL; hd == NULL; i++, chipDelay32 (1000))
495 hd = hwQmQueuePop (DEVICE_QM_TX_Q);
497 if (hd == NULL)
498 return (-1);
500 QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, num_bytes);
502 hd->buffLen = num_bytes;
503 hd->origBufferLen = num_bytes;
505 hd->buffPtr = deviceLocalAddrToGlobal((UINT32)buffer);
506 hd->origBuffPtr = deviceLocalAddrToGlobal((UINT32)buffer);
509 /* Return the descriptor back to the transmit queue */
510 QM_DESC_PINFO_SET_QM(hd->packetInfo, 0);
511 QM_DESC_PINFO_SET_QUEUE(hd->packetInfo, DEVICE_QM_TX_Q);
513 hwQmQueuePush (hd, DEVICE_QM_ETH_TX_Q, QM_DESC_SIZE_BYTES);
515 return (0);
517 }
520 Int32 targetMacRcv (void *vptr_device, UINT8 *buffer)
521 {
522 Int32 pktSizeBytes;
523 qmHostDesc_t *hd;
524 NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
526 hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
527 if (hd == NULL)
528 return (0);
530 pktSizeBytes = QM_DESC_DESCINFO_GET_PKT_LEN(hd->descInfo);
531 iblMemcpy ((void *)buffer, (void *)hd->buffPtr, pktSizeBytes);
533 hd->buffLen = hd->origBufferLen;
534 hd->buffPtr = hd->origBuffPtr;
536 hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
538 return (pktSizeBytes);
540 }
542 void targetFreeQs (void)
543 {
544 qmHostDesc_t *hd;
546 do {
548 hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
550 } while (hd != NULL);
552 do {
554 hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
556 } while (hd != NULL);
558 do {
560 hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
562 } while (hd != NULL);
564 do {
566 hd = hwQmQueuePop (DEVICE_QM_TX_Q);
568 } while (hd != NULL);
570 }
572 extern nandCtbl_t nandEmifCtbl;
573 /**
574 * @brief Return the NAND interface (GPIO, EMIF25 or SPI) used based on the value
575 * of interface
576 */
577 #ifndef EXCLUDE_NAND_GPIO
578 nandCtbl_t nandGpioCtbl = {
580 nandHwGpioDriverInit,
581 nandHwGpioDriverReadBytes,
582 nandHwGpioDriverReadPage,
583 nandHwGpioDriverClose
585 };
586 #endif
588 #ifndef EXCLUDE_NAND_EMIF
589 extern Int32 nandHwEmifDriverInit (int32 cs, void *vdevInfo);
590 extern Int32 nandHwEmifDriverReadBytes (Uint32 block, Uint32 page, Uint32 byte, Uint32 nbytes, Uint8 *data);
591 extern Int32 nandHwEmifDriverReadPage (Uint32 block, Uint32 page, Uint8 *data);
592 extern Int32 nandHwEmifDriverClose (void);
594 nandCtbl_t nandEmifCtbl = {
596 nandHwEmifDriverInit,
597 nandHwEmifDriverReadBytes,
598 nandHwEmifDriverReadPage,
599 nandHwEmifDriverClose
601 };
602 #endif
604 #ifndef EXCLUDE_NAND_SPI
605 nandCtbl_t nandSpiCtbl = {
608 nandHwSpiDriverInit,
609 nandHwSpiDriverReadBytes,
610 nandHwSpiDriverReadPage,
611 nandHwSpiDriverClose
613 };
614 #endif
616 nandCtbl_t *deviceGetNandCtbl (int32 interface)
617 {
618 #ifndef EXCLUDE_NAND_GPIO
620 if (interface == ibl_PMEM_IF_GPIO)
621 return (&nandGpioCtbl);
623 #endif
625 #ifndef EXCLUDE_NAND_SPI
627 if (interface == ibl_PMEM_IF_SPI)
628 return (&nandSpiCtbl);
630 #endif
632 #ifndef EXCLUDE_NAND_EMIF
634 if ((interface >= ibl_PMEM_IF_CHIPSEL_2) && (interface <= ibl_PMEM_IF_CHIPSEL_5))
635 return (&nandEmifCtbl);
637 #endif
639 return (NULL);
641 }
644 /**
645 * @brief
646 * Get the nor call table for the specified nor interface
647 */
649 #ifndef EXCLUDE_NOR_EMIF
650 norCtbl_t norEmifCtbl = {
652 norHwEmifDriverInit,
653 norHwEmifDriverReadBytes,
654 norHwEmifDriverClose
656 };
658 #endif
660 #ifndef EXCLUDE_NOR_SPI
662 norCtbl_t norSpiCtbl = {
664 norHwSpiDriverInit,
665 norHwSpiDriverReadBytes,
666 norHwSpiDriverClose
668 };
670 #endif
672 norCtbl_t *deviceGetNorCtbl (int32 interface)
673 {
675 #ifndef EXCLUDE_NOR_SPI
677 if (interface == ibl_PMEM_IF_SPI)
678 return (&norSpiCtbl);
680 #endif
682 #ifndef EXCLUDE_NOR_EMIF
684 if ((interface >= ibl_PMEM_IF_CHIPSEL_2) && (interface <= ibl_PMEM_IF_CHIPSEL_5))
685 return (&norEmifCtbl);
687 #endif
689 return (NULL);
691 }