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>
69 #define PLL_DDR_INIT_LOOPMAX 10
70 extern cregister unsigned int DNUM;
72 /**
73 * @brief Determine if an address is local
74 *
75 * @details
76 * Examines an input address to determine if it is a local address. Using the largest
77 * L2 size on the C6670.
78 */
79 bool address_is_local (Uint32 addr)
80 {
81 /* L2 */
82 if ((addr >= 0x00800000) && (addr < 0x00900000))
83 return (TRUE);
85 /* L1P */
86 if ((addr >= 0x00e00000) && (addr < 0x00e08000))
87 return (TRUE);
89 /* L2D */
90 if ((addr >= 0x00f00000) && (addr < 0x00f08000))
91 return (TRUE);
93 return (FALSE);
95 }
98 /**
99 * @brief Convert a local l1d, l1p or l2 address to a global address
100 *
101 * @details
102 * The global address is formed. If the address is not local then
103 * the input address is returned
104 */
105 Uint32 deviceLocalAddrToGlobal (Uint32 addr)
106 {
108 if (address_is_local (addr))
109 addr = (1 << 28) | (DNUM << 24) | addr;
111 return (addr);
113 }
116 /**
117 * @brief
118 * Enable the DDR
119 *
120 * @details
121 * The DDR controller on the c66x is an emif 4.0. The controller is
122 * initialized directly with the supplied values
123 */
124 void deviceDdrConfig (void)
125 {
126 uint32 loopcount=0;
127 /* The emif registers must be made visible. MPAX mapping 2 is used */
128 DEVICE_REG_XMPAX_L(2) = 0x10000000 | 0xff; /* replacement addr + perm*/
129 DEVICE_REG_XMPAX_H(2) = 0x2100000B; /* base addr + seg size (64KB)*/
131 for (loopcount = 0; loopcount < PLL_DDR_INIT_LOOPMAX ; loopcount++)
132 {
133 /* Calling MAIN, PA, DDR PLL init before DDR controller init */
134 if (ibl.pllConfig[ibl_MAIN_PLL].doEnable == TRUE)
135 hwPllSetPll (MAIN_PLL,
136 ibl.pllConfig[ibl_MAIN_PLL].prediv,
137 ibl.pllConfig[ibl_MAIN_PLL].mult,
138 ibl.pllConfig[ibl_MAIN_PLL].postdiv);
140 if (ibl.pllConfig[ibl_NET_PLL].doEnable == TRUE)
141 hwPllSetCfgPll (DEVICE_PLL_BASE(NET_PLL),
142 ibl.pllConfig[ibl_NET_PLL].prediv,
143 ibl.pllConfig[ibl_NET_PLL].mult,
144 ibl.pllConfig[ibl_NET_PLL].postdiv,
145 ibl.pllConfig[ibl_MAIN_PLL].pllOutFreqMhz,
146 ibl.pllConfig[ibl_NET_PLL].pllOutFreqMhz);
148 if (ibl.pllConfig[ibl_DDR_PLL].doEnable == TRUE)
149 hwPllSetCfg2Pll (DEVICE_PLL_BASE(DDR_PLL),
150 ibl.pllConfig[ibl_DDR_PLL].prediv,
151 ibl.pllConfig[ibl_DDR_PLL].mult,
152 ibl.pllConfig[ibl_DDR_PLL].postdiv,
153 ibl.pllConfig[ibl_MAIN_PLL].pllOutFreqMhz,
154 ibl.pllConfig[ibl_DDR_PLL].pllOutFreqMhz);
155 if (ibl.ddrConfig.configDdr != 0)
156 hwEmif4p0Enable (&ibl.ddrConfig.uEmif.emif4p0);
157 }
159 }
163 /**
164 * @brief Enable EMIF25 or SPI interface to the NAND
165 *
166 */
167 int32 deviceConfigureForNand(void)
168 {
170 return (0);
172 }
174 /**
175 * @brief
176 * Return the base memory address for emif25 in a given chip select space
177 */
178 uint32 deviceEmif25MemBase (int32 cs)
179 {
180 switch (cs) {
182 case 2: return (TARGET_MEM_NAND_CS_2);
184 case 3: return (TARGET_MEM_NAND_CS_3);
186 case 4: return (TARGET_MEM_NAND_CS_4);
188 case 5: return (TARGET_MEM_NAND_CS_5);
190 }
192 return (0xffffffff);
194 }
197 /**
198 * @brief
199 * Return the PSC number for NAND/NOR through emif. Only 6678 has the emif
200 */
201 Int32 deviceEmifPscNum (void)
202 {
203 Uint32 v;
205 v = *((Uint32 *)DEVICE_JTAG_ID_REG);
206 v &= DEVICE_JTAG_ID_MASK;
207 if (v == DEVICE_C6678_JTAG_ID_VAL)
208 return (TARGET_PWR_EMIF_C6678);
210 /* Return a negative number to indicate no PSC module is associated with NAND */
211 return (-1);
213 }
217 /**
218 * @brief
219 * The e-fuse mac address is loaded
220 */
221 void deviceLoadDefaultEthAddress (uint8 *maddr)
222 {
223 uint32 macA, macB;
225 /* Read the e-fuse mac address */
226 macA = *((uint32 *)0x2620110);
227 macB = *((uint32 *)0x2620114);
229 maddr[0] = (macB >> 8) & 0xff;
230 maddr[1] = (macB >> 0) & 0xff;
231 maddr[2] = (macA >> 24) & 0xff;
232 maddr[3] = (macA >> 16) & 0xff;
233 maddr[4] = (macA >> 8) & 0xff;
234 maddr[5] = (macA >> 0) & 0xff;
235 }
238 /**
239 * @brief
240 * Compile time queue manager information
241 */
242 #define DEVICE_NUM_RX_CPPIS 1
243 #define DEVICE_NUM_TX_CPPIS 1
244 #define DEVICE_NUM_CPPIS (DEVICE_NUM_RX_CPPIS + DEVICE_NUM_TX_CPPIS)
246 /* The linking RAM */
247 #pragma DATA_SECTION(qm_linkram_buf, ".linkram")
248 #pragma DATA_ALIGN(qm_linkram_buf, 16)
249 uint8 qm_linkram_buf[DEVICE_NUM_CPPIS * 2 * (sizeof(uint32)/sizeof(uint8))];
252 /* The CPPI RAM */
253 #pragma DATA_SECTION(qm_cppi_buf, ".cppi")
254 #pragma DATA_ALIGN(qm_cppi_buf, 16)
255 uint8 qm_cppi_buf[QM_DESC_SIZE_BYTES * DEVICE_NUM_CPPIS];
258 /* The rx data buffers */
259 #pragma DATA_SECTION(qm_buffer, ".mac_buffer")
260 #pragma DATA_ALIGN(qm_buffer, 16)
261 uint8 qm_buffer[MAX_SIZE_STREAM_BUFFER * DEVICE_NUM_RX_CPPIS];
263 const qmConfig_t qmConfig = {
264 (UINT32) qm_linkram_buf,
265 sizeof (qm_cppi_buf),
266 (UINT32) qm_cppi_buf,
268 DEVICE_NUM_CPPIS,
269 DEVICE_QM_FREE_Q
270 };
272 /**
273 * @brief
274 * Return the queue manager memory configuration information
275 */
276 void *targetGetQmConfig (void)
277 {
278 return ((void *)&qmConfig);
279 }
281 /**
282 * @brief
283 * Attach a packet buffer to each descriptor and push onto the linked buffer queue
284 */
285 void targetInitQs (void)
286 {
287 int32 i;
288 qmHostDesc_t *hd;
290 for (i = 0; i < DEVICE_NUM_RX_CPPIS; i++) {
292 hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
293 hd->buffLen = sizeof (qm_buffer) / DEVICE_NUM_CPPIS;
294 hd->buffPtr = (UINT32) &(qm_buffer[MAX_SIZE_STREAM_BUFFER * i]);
295 hd->nextBDPtr = 0;
296 hd->origBufferLen = MAX_SIZE_STREAM_BUFFER;
297 hd->origBuffPtr = hd->buffPtr;
299 hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
301 }
304 for (i = 0; i < DEVICE_NUM_TX_CPPIS; i++) {
306 hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
307 hd->buffLen = 0;
308 hd->buffPtr = 0;
309 hd->nextBDPtr = 0;
310 hd->origBufferLen = 0;
311 hd->origBuffPtr = 0;
313 hwQmQueuePush (hd, DEVICE_QM_TX_Q, QM_DESC_SIZE_BYTES);
315 }
318 }
322 const cpdmaRxCfg_t cpdmaEthRxCfg = {
324 DEVICE_PA_CDMA_RX_CHAN_CFG_BASE, /* Base address of PA CPDMA rx config registers */
325 DEVICE_PA_CDMA_RX_NUM_CHANNELS, /* Number of rx channels */
327 DEVICE_PA_CDMA_RX_FLOW_CFG_BASE, /* Base address of PA CPDMA rx flow registers */
328 DEVICE_PA_CDMA_RX_NUM_FLOWS, /* Number of rx flows */
330 0, /* Queue manager for descriptor / buffer for received packets */
331 DEVICE_QM_LNK_BUF_Q, /* Queue of descriptors /buffers for received packets */
333 0, /* Queue manager for received packets */
334 DEVICE_QM_RCV_Q, /* Queue for received packets (overridden by PA) */
336 DEVICE_RX_CDMA_TIMEOUT_COUNT /* Teardown maximum loop wait */
337 };
340 /**
341 * @brief
342 * Return the cpdma configuration information
343 */
344 void *targetGetCpdmaRxConfig (void)
345 {
346 return ((void *)&cpdmaEthRxCfg);
348 }
351 const cpdmaTxCfg_t cpdmaEthTxCfg = {
353 DEVICE_PA_CDMA_GLOBAL_CFG_BASE, /* Base address of global config registers */
354 DEVICE_PA_CDMA_TX_CHAN_CFG_BASE, /* Base address of PA CPDMA tx config registers */
355 DEVICE_PA_CDMA_TX_NUM_CHANNELS /* Number of tx channels */
357 };
360 /**
361 * @brief
362 * return the tx cpdma configuration information
363 */
364 void *targetGetCpdmaTxConfig (void)
365 {
366 return ((void *)&cpdmaEthTxCfg);
368 }
370 /**
371 * @brief
372 * Configure the PA
373 */
374 void targetPaConfig (uint8 *macAddr)
375 {
376 paConfig_t paCfg;
377 qmHostDesc_t *hd;
378 SINT16 ret;
380 /* Filter everything except the desired mac address and the broadcast mac */
381 paCfg.mac0ms = ((uint32)macAddr[0] << 24) | ((uint32)macAddr[1] << 16) | ((uint32)macAddr[2] << 8) | (uint32)(macAddr[3]);
382 paCfg.mac0ls = ((uint32)macAddr[4] << 24) | ((uint32)macAddr[5] << 16);
384 paCfg.mac1ms = 0xffffffff;
385 paCfg.mac1ls = 0xffff0000;
387 paCfg.rxQnum = DEVICE_QM_RCV_Q;
389 /* Form the configuration command in a buffer linked to a descriptor */
390 hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
391 paCfg.cmdBuf = (uint8 *)hd->origBuffPtr;
393 ret = hwPaEnable (&paCfg);
394 if (ret != 0) {
395 iblStatus.iblFail = ibl_FAIL_CODE_PA;
396 return;
397 }
400 /* Send the command to the PA through the QM */
401 hd->softwareInfo0 = PA_MAGIC_ID;
402 hd->buffLen = 16;
403 QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, 16);
405 /* Set the return Queue */
406 QM_DESC_PINFO_SET_QM (hd->packetInfo, 0);
407 QM_DESC_PINFO_SET_QUEUE (hd->packetInfo, DEVICE_QM_LNK_BUF_Q);
409 hwQmQueuePush (hd, DEVICE_QM_PA_CFG_Q, QM_DESC_SIZE_BYTES);
412 }
414 /**
415 * @brief
416 * Chip level SGMII serdes configuration
417 *
418 * @details
419 * Both lanes are always setup, regardless of the port value
420 */
421 void targetSgmiiSerdesConfig (int32 port, void *viblSgmii)
422 {
423 serdesConfig_t scfg;
424 iblSgmii_t *sgmii = (iblSgmii_t *)viblSgmii;
426 scfg.cfg = sgmii->auxConfig;
427 scfg.nLanes = 2;
428 scfg.rxCfg[0] = scfg.rxCfg[1] = sgmii->rxConfig;
429 scfg.txCfg[0] = scfg.txCfg[1] = sgmii->txConfig;
431 hwSerdesConfig (TARGET_SGMII_SERDES_BASE, &scfg);
433 hwSerdesWaitLock (TARGET_SGMII_SERDES_STATUS_BASE);
435 }
438 Int32 targetMacSend (void *vptr_device, Uint8* buffer, int num_bytes)
439 {
440 qmHostDesc_t *hd;
441 NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
442 int i;
445 /* Must always setup the descriptor to have the minimum packet length */
446 if (num_bytes < 64)
447 num_bytes = 64;
450 for (i = 0, hd = NULL; hd == NULL; i++, chipDelay32 (1000))
451 hd = hwQmQueuePop (DEVICE_QM_TX_Q);
453 if (hd == NULL)
454 return (-1);
456 QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, num_bytes);
458 hd->buffLen = num_bytes;
459 hd->origBufferLen = num_bytes;
461 hd->buffPtr = deviceLocalAddrToGlobal((UINT32)buffer);
462 hd->origBuffPtr = deviceLocalAddrToGlobal((UINT32)buffer);
465 /* Return the descriptor back to the transmit queue */
466 QM_DESC_PINFO_SET_QM(hd->packetInfo, 0);
467 QM_DESC_PINFO_SET_QUEUE(hd->packetInfo, DEVICE_QM_TX_Q);
469 hwQmQueuePush (hd, DEVICE_QM_ETH_TX_Q, QM_DESC_SIZE_BYTES);
471 return (0);
473 }
476 Int32 targetMacRcv (void *vptr_device, UINT8 *buffer)
477 {
478 Int32 pktSizeBytes;
479 qmHostDesc_t *hd;
480 NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
482 hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
483 if (hd == NULL)
484 return (0);
486 pktSizeBytes = QM_DESC_DESCINFO_GET_PKT_LEN(hd->descInfo);
487 iblMemcpy ((void *)buffer, (void *)hd->buffPtr, pktSizeBytes);
489 hd->buffLen = hd->origBufferLen;
490 hd->buffPtr = hd->origBuffPtr;
492 hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
494 return (pktSizeBytes);
496 }
498 void targetFreeQs (void)
499 {
500 qmHostDesc_t *hd;
502 do {
504 hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
506 } while (hd != NULL);
508 do {
510 hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
512 } while (hd != NULL);
514 do {
516 hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
518 } while (hd != NULL);
520 do {
522 hd = hwQmQueuePop (DEVICE_QM_TX_Q);
524 } while (hd != NULL);
526 }
528 extern nandCtbl_t nandEmifCtbl;
529 /**
530 * @brief Return the NAND interface (GPIO, EMIF25 or SPI) used based on the value
531 * of interface
532 */
533 #ifndef EXCLUDE_NAND_GPIO
534 nandCtbl_t nandGpioCtbl = {
536 nandHwGpioDriverInit,
537 nandHwGpioDriverReadBytes,
538 nandHwGpioDriverReadPage,
539 nandHwGpioDriverClose
541 };
542 #endif
544 #ifndef EXCLUDE_NAND_EMIF
545 extern Int32 nandHwEmifDriverInit (int32 cs, void *vdevInfo);
546 extern Int32 nandHwEmifDriverReadBytes (Uint32 block, Uint32 page, Uint32 byte, Uint32 nbytes, Uint8 *data);
547 extern Int32 nandHwEmifDriverReadPage (Uint32 block, Uint32 page, Uint8 *data);
548 extern Int32 nandHwEmifDriverClose (void);
550 nandCtbl_t nandEmifCtbl = {
552 nandHwEmifDriverInit,
553 nandHwEmifDriverReadBytes,
554 nandHwEmifDriverReadPage,
555 nandHwEmifDriverClose
557 };
558 #endif
560 #ifndef EXCLUDE_NAND_SPI
561 nandCtbl_t nandSpiCtbl = {
564 nandHwSpiDriverInit,
565 nandHwSpiDriverReadBytes,
566 nandHwSpiDriverReadPage,
567 nandHwSpiDriverClose
569 };
570 #endif
572 nandCtbl_t *deviceGetNandCtbl (int32 interface)
573 {
574 #ifndef EXCLUDE_NAND_GPIO
576 if (interface == ibl_PMEM_IF_GPIO)
577 return (&nandGpioCtbl);
579 #endif
581 #ifndef EXCLUDE_NAND_SPI
583 if (interface == ibl_PMEM_IF_SPI)
584 return (&nandSpiCtbl);
586 #endif
588 #ifndef EXCLUDE_NAND_EMIF
590 if ((interface >= ibl_PMEM_IF_CHIPSEL_2) && (interface <= ibl_PMEM_IF_CHIPSEL_5))
591 return (&nandEmifCtbl);
593 #endif
595 return (NULL);
597 }
600 /**
601 * @brief
602 * Get the nor call table for the specified nor interface
603 */
605 #ifndef EXCLUDE_NOR_EMIF
606 norCtbl_t norEmifCtbl = {
608 norHwEmifDriverInit,
609 norHwEmifDriverReadBytes,
610 norHwEmifDriverClose
612 };
614 #endif
616 #ifndef EXCLUDE_NOR_SPI
618 norCtbl_t norSpiCtbl = {
620 norHwSpiDriverInit,
621 norHwSpiDriverReadBytes,
622 norHwSpiDriverClose
624 };
626 #endif
628 norCtbl_t *deviceGetNorCtbl (int32 interface)
629 {
631 #ifndef EXCLUDE_NOR_SPI
633 if (interface == ibl_PMEM_IF_SPI)
634 return (&norSpiCtbl);
636 #endif
638 #ifndef EXCLUDE_NOR_EMIF
640 if ((interface >= ibl_PMEM_IF_CHIPSEL_2) && (interface <= ibl_PMEM_IF_CHIPSEL_5))
641 return (&norEmifCtbl);
643 #endif
645 return (NULL);
647 }