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 extern cregister unsigned int DNUM;
71 /**
72 * @brief Determine if an address is local
73 *
74 * @details
75 * Examines an input address to determine if it is a local address. Using the largest
76 * L2 size on the C6670.
77 */
78 bool address_is_local (Uint32 addr)
79 {
80 /* L2 */
81 if ((addr >= 0x00800000) && (addr < 0x00900000))
82 return (TRUE);
84 /* L1P */
85 if ((addr >= 0x00e00000) && (addr < 0x00e08000))
86 return (TRUE);
88 /* L2D */
89 if ((addr >= 0x00f00000) && (addr < 0x00f08000))
90 return (TRUE);
92 return (FALSE);
94 }
97 /**
98 * @brief Convert a local l1d, l1p or l2 address to a global address
99 *
100 * @details
101 * The global address is formed. If the address is not local then
102 * the input address is returned
103 */
104 Uint32 deviceLocalAddrToGlobal (Uint32 addr)
105 {
107 if (address_is_local (addr))
108 addr = (1 << 28) | (DNUM << 24) | addr;
110 return (addr);
112 }
115 /**
116 * @brief
117 * Enable the DDR
118 *
119 * @details
120 * The DDR controller on the c66x is an emif 4.0. The controller is
121 * initialized directly with the supplied values
122 */
123 void deviceDdrConfig (void)
124 {
125 /* The emif registers must be made visible. MPAX mapping 2 is used */
126 DEVICE_REG_XMPAX_L(2) = 0x10000000 | 0xff; /* replacement addr + perm*/
127 DEVICE_REG_XMPAX_H(2) = 0x2100000B; /* base addr + seg size (64KB)*/
129 if (ibl.ddrConfig.configDdr != 0)
130 hwEmif4p0Enable (&ibl.ddrConfig.uEmif.emif4p0);
132 }
136 /**
137 * @brief Enable EMIF25 or SPI interface to the NAND
138 *
139 */
140 int32 deviceConfigureForNand(void)
141 {
143 return (0);
145 }
147 /**
148 * @brief
149 * Return the base memory address for emif25 in a given chip select space
150 */
151 uint32 deviceEmif25MemBase (int32 cs)
152 {
153 switch (cs) {
155 case 2: return (TARGET_MEM_NAND_CS_2);
157 case 3: return (TARGET_MEM_NAND_CS_3);
159 case 4: return (TARGET_MEM_NAND_CS_4);
161 case 5: return (TARGET_MEM_NAND_CS_5);
163 }
165 return (0xffffffff);
167 }
170 /**
171 * @brief
172 * Return the PSC number for NAND/NOR through emif. Only 6678 has the emif
173 */
174 Int32 deviceEmifPscNum (void)
175 {
176 Uint32 v;
178 v = *((Uint32 *)DEVICE_JTAG_ID_REG);
179 v &= DEVICE_JTAG_ID_MASK;
180 if (v == DEVICE_C6678_JTAG_ID_VAL)
181 return (TARGET_PWR_EMIF_C6678);
183 /* Return a negative number to indicate no PSC module is associated with NAND */
184 return (-1);
186 }
190 /**
191 * @brief
192 * The e-fuse mac address is loaded
193 */
194 void deviceLoadDefaultEthAddress (uint8 *maddr)
195 {
196 uint32 macA, macB;
198 /* Read the e-fuse mac address */
199 macA = *((uint32 *)0x2620110);
200 macB = *((uint32 *)0x2620114);
202 maddr[0] = (macB >> 8) & 0xff;
203 maddr[1] = (macB >> 0) & 0xff;
204 maddr[2] = (macA >> 24) & 0xff;
205 maddr[3] = (macA >> 16) & 0xff;
206 maddr[4] = (macA >> 8) & 0xff;
207 maddr[5] = (macA >> 0) & 0xff;
208 }
211 /**
212 * @brief
213 * Compile time queue manager information
214 */
215 #define DEVICE_NUM_RX_CPPIS 1
216 #define DEVICE_NUM_TX_CPPIS 1
217 #define DEVICE_NUM_CPPIS (DEVICE_NUM_RX_CPPIS + DEVICE_NUM_TX_CPPIS)
219 /* The linking RAM */
220 #pragma DATA_SECTION(qm_linkram_buf, ".linkram")
221 #pragma DATA_ALIGN(qm_linkram_buf, 16)
222 uint8 qm_linkram_buf[DEVICE_NUM_CPPIS * 2 * (sizeof(uint32)/sizeof(uint8))];
225 /* The CPPI RAM */
226 #pragma DATA_SECTION(qm_cppi_buf, ".cppi")
227 #pragma DATA_ALIGN(qm_cppi_buf, 16)
228 uint8 qm_cppi_buf[QM_DESC_SIZE_BYTES * DEVICE_NUM_CPPIS];
231 /* The rx data buffers */
232 #pragma DATA_SECTION(qm_buffer, ".mac_buffer")
233 #pragma DATA_ALIGN(qm_buffer, 16)
234 uint8 qm_buffer[MAX_SIZE_STREAM_BUFFER * DEVICE_NUM_RX_CPPIS];
236 const qmConfig_t qmConfig = {
237 (UINT32) qm_linkram_buf,
238 sizeof (qm_cppi_buf),
239 (UINT32) qm_cppi_buf,
241 DEVICE_NUM_CPPIS,
242 DEVICE_QM_FREE_Q
243 };
245 /**
246 * @brief
247 * Return the queue manager memory configuration information
248 */
249 void *targetGetQmConfig (void)
250 {
251 return ((void *)&qmConfig);
252 }
254 /**
255 * @brief
256 * Attach a packet buffer to each descriptor and push onto the linked buffer queue
257 */
258 void targetInitQs (void)
259 {
260 int32 i;
261 qmHostDesc_t *hd;
263 for (i = 0; i < DEVICE_NUM_RX_CPPIS; i++) {
265 hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
266 hd->buffLen = sizeof (qm_buffer) / DEVICE_NUM_CPPIS;
267 hd->buffPtr = (UINT32) &(qm_buffer[MAX_SIZE_STREAM_BUFFER * i]);
268 hd->nextBDPtr = 0;
269 hd->origBufferLen = MAX_SIZE_STREAM_BUFFER;
270 hd->origBuffPtr = hd->buffPtr;
272 hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
274 }
277 for (i = 0; i < DEVICE_NUM_TX_CPPIS; i++) {
279 hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
280 hd->buffLen = 0;
281 hd->buffPtr = 0;
282 hd->nextBDPtr = 0;
283 hd->origBufferLen = 0;
284 hd->origBuffPtr = 0;
286 hwQmQueuePush (hd, DEVICE_QM_TX_Q, QM_DESC_SIZE_BYTES);
288 }
291 }
295 const cpdmaRxCfg_t cpdmaEthRxCfg = {
297 DEVICE_PA_CDMA_RX_CHAN_CFG_BASE, /* Base address of PA CPDMA rx config registers */
298 DEVICE_PA_CDMA_RX_NUM_CHANNELS, /* Number of rx channels */
300 DEVICE_PA_CDMA_RX_FLOW_CFG_BASE, /* Base address of PA CPDMA rx flow registers */
301 DEVICE_PA_CDMA_RX_NUM_FLOWS, /* Number of rx flows */
303 0, /* Queue manager for descriptor / buffer for received packets */
304 DEVICE_QM_LNK_BUF_Q, /* Queue of descriptors /buffers for received packets */
306 0, /* Queue manager for received packets */
307 DEVICE_QM_RCV_Q, /* Queue for received packets (overridden by PA) */
309 DEVICE_RX_CDMA_TIMEOUT_COUNT /* Teardown maximum loop wait */
310 };
313 /**
314 * @brief
315 * Return the cpdma configuration information
316 */
317 void *targetGetCpdmaRxConfig (void)
318 {
319 return ((void *)&cpdmaEthRxCfg);
321 }
324 const cpdmaTxCfg_t cpdmaEthTxCfg = {
326 DEVICE_PA_CDMA_GLOBAL_CFG_BASE, /* Base address of global config registers */
327 DEVICE_PA_CDMA_TX_CHAN_CFG_BASE, /* Base address of PA CPDMA tx config registers */
328 DEVICE_PA_CDMA_TX_NUM_CHANNELS /* Number of tx channels */
330 };
333 /**
334 * @brief
335 * return the tx cpdma configuration information
336 */
337 void *targetGetCpdmaTxConfig (void)
338 {
339 return ((void *)&cpdmaEthTxCfg);
341 }
343 /**
344 * @brief
345 * Configure the PA
346 */
347 void targetPaConfig (uint8 *macAddr)
348 {
349 paConfig_t paCfg;
350 qmHostDesc_t *hd;
351 SINT16 ret;
353 /* Filter everything except the desired mac address and the broadcast mac */
354 paCfg.mac0ms = ((uint32)macAddr[0] << 24) | ((uint32)macAddr[1] << 16) | ((uint32)macAddr[2] << 8) | (uint32)(macAddr[3]);
355 paCfg.mac0ls = ((uint32)macAddr[4] << 24) | ((uint32)macAddr[5] << 16);
357 paCfg.mac1ms = 0xffffffff;
358 paCfg.mac1ls = 0xffff0000;
360 paCfg.rxQnum = DEVICE_QM_RCV_Q;
362 /* Form the configuration command in a buffer linked to a descriptor */
363 hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
364 paCfg.cmdBuf = (uint8 *)hd->origBuffPtr;
366 ret = hwPaEnable (&paCfg);
367 if (ret != 0) {
368 iblStatus.iblFail = ibl_FAIL_CODE_PA;
369 return;
370 }
373 /* Send the command to the PA through the QM */
374 hd->softwareInfo0 = PA_MAGIC_ID;
375 hd->buffLen = 16;
376 QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, 16);
378 /* Set the return Queue */
379 QM_DESC_PINFO_SET_QM (hd->packetInfo, 0);
380 QM_DESC_PINFO_SET_QUEUE (hd->packetInfo, DEVICE_QM_LNK_BUF_Q);
382 hwQmQueuePush (hd, DEVICE_QM_PA_CFG_Q, QM_DESC_SIZE_BYTES);
385 }
387 /**
388 * @brief
389 * Chip level SGMII serdes configuration
390 *
391 * @details
392 * Both lanes are always setup, regardless of the port value
393 */
394 void targetSgmiiSerdesConfig (int32 port, void *viblSgmii)
395 {
396 serdesConfig_t scfg;
397 iblSgmii_t *sgmii = (iblSgmii_t *)viblSgmii;
399 scfg.cfg = sgmii->auxConfig;
400 scfg.nLanes = 2;
401 scfg.rxCfg[0] = scfg.rxCfg[1] = sgmii->rxConfig;
402 scfg.txCfg[0] = scfg.txCfg[1] = sgmii->txConfig;
404 hwSerdesConfig (TARGET_SGMII_SERDES_BASE, &scfg);
406 hwSerdesWaitLock (TARGET_SGMII_SERDES_STATUS_BASE);
408 }
411 Int32 targetMacSend (void *vptr_device, Uint8* buffer, int num_bytes)
412 {
413 qmHostDesc_t *hd;
414 NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
415 int i;
418 /* Must always setup the descriptor to have the minimum packet length */
419 if (num_bytes < 64)
420 num_bytes = 64;
423 for (i = 0, hd = NULL; hd == NULL; i++, chipDelay32 (1000))
424 hd = hwQmQueuePop (DEVICE_QM_TX_Q);
426 if (hd == NULL)
427 return (-1);
429 QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, num_bytes);
431 hd->buffLen = num_bytes;
432 hd->origBufferLen = num_bytes;
434 hd->buffPtr = deviceLocalAddrToGlobal((UINT32)buffer);
435 hd->origBuffPtr = deviceLocalAddrToGlobal((UINT32)buffer);
438 /* Return the descriptor back to the transmit queue */
439 QM_DESC_PINFO_SET_QM(hd->packetInfo, 0);
440 QM_DESC_PINFO_SET_QUEUE(hd->packetInfo, DEVICE_QM_TX_Q);
442 hwQmQueuePush (hd, DEVICE_QM_ETH_TX_Q, QM_DESC_SIZE_BYTES);
444 return (0);
446 }
449 Int32 targetMacRcv (void *vptr_device, UINT8 *buffer)
450 {
451 Int32 pktSizeBytes;
452 qmHostDesc_t *hd;
453 NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
455 hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
456 if (hd == NULL)
457 return (0);
459 pktSizeBytes = QM_DESC_DESCINFO_GET_PKT_LEN(hd->descInfo);
460 iblMemcpy ((void *)buffer, (void *)hd->buffPtr, pktSizeBytes);
462 hd->buffLen = hd->origBufferLen;
463 hd->buffPtr = hd->origBuffPtr;
465 hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
467 return (pktSizeBytes);
469 }
471 void targetFreeQs (void)
472 {
473 qmHostDesc_t *hd;
475 do {
477 hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
479 } while (hd != NULL);
481 do {
483 hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
485 } while (hd != NULL);
487 do {
489 hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
491 } while (hd != NULL);
493 do {
495 hd = hwQmQueuePop (DEVICE_QM_TX_Q);
497 } while (hd != NULL);
499 }
501 extern nandCtbl_t nandEmifCtbl;
502 /**
503 * @brief Return the NAND interface (GPIO, EMIF25 or SPI) used based on the value
504 * of interface
505 */
506 #ifndef EXCLUDE_NAND_GPIO
507 nandCtbl_t nandGpioCtbl = {
509 nandHwGpioDriverInit,
510 nandHwGpioDriverReadBytes,
511 nandHwGpioDriverReadPage,
512 nandHwGpioDriverClose
514 };
515 #endif
517 #ifndef EXCLUDE_NAND_EMIF
518 extern Int32 nandHwEmifDriverInit (int32 cs, void *vdevInfo);
519 extern Int32 nandHwEmifDriverReadBytes (Uint32 block, Uint32 page, Uint32 byte, Uint32 nbytes, Uint8 *data);
520 extern Int32 nandHwEmifDriverReadPage (Uint32 block, Uint32 page, Uint8 *data);
521 extern Int32 nandHwEmifDriverClose (void);
523 nandCtbl_t nandEmifCtbl = {
525 nandHwEmifDriverInit,
526 nandHwEmifDriverReadBytes,
527 nandHwEmifDriverReadPage,
528 nandHwEmifDriverClose
530 };
531 #endif
533 #ifndef EXCLUDE_NAND_SPI
534 nandCtbl_t nandSpiCtbl = {
537 nandHwSpiDriverInit,
538 nandHwSpiDriverReadBytes,
539 nandHwSpiDriverReadPage,
540 nandHwSpiDriverClose
542 };
543 #endif
545 nandCtbl_t *deviceGetNandCtbl (int32 interface)
546 {
547 #ifndef EXCLUDE_NAND_GPIO
549 if (interface == ibl_PMEM_IF_GPIO)
550 return (&nandGpioCtbl);
552 #endif
554 #ifndef EXCLUDE_NAND_SPI
556 if (interface == ibl_PMEM_IF_SPI)
557 return (&nandSpiCtbl);
559 #endif
561 #ifndef EXCLUDE_NAND_EMIF
563 if ((interface >= ibl_PMEM_IF_CHIPSEL_2) && (interface <= ibl_PMEM_IF_CHIPSEL_5))
564 return (&nandEmifCtbl);
566 #endif
568 return (NULL);
570 }
573 /**
574 * @brief
575 * Get the nor call table for the specified nor interface
576 */
578 #ifndef EXCLUDE_NOR_EMIF
579 norCtbl_t norEmifCtbl = {
581 norHwEmifDriverInit,
582 norHwEmifDriverReadBytes,
583 norHwEmifDriverClose
585 };
587 #endif
589 #ifndef EXCLUDE_NOR_SPI
591 norCtbl_t norSpiCtbl = {
593 norHwSpiDriverInit,
594 norHwSpiDriverReadBytes,
595 norHwSpiDriverClose
597 };
599 #endif
601 norCtbl_t *deviceGetNorCtbl (int32 interface)
602 {
604 #ifndef EXCLUDE_NOR_SPI
606 if (interface == ibl_PMEM_IF_SPI)
607 return (&norSpiCtbl);
609 #endif
611 #ifndef EXCLUDE_NOR_EMIF
613 if ((interface >= ibl_PMEM_IF_CHIPSEL_2) && (interface <= ibl_PMEM_IF_CHIPSEL_5))
614 return (&norEmifCtbl);
616 #endif
618 return (NULL);
620 }