]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/ibl.git/blob - src/device/c661x/c661x.c
First working version (Ethernet) on EVM with I2C boot
[keystone-rtos/ibl.git] / src / device / c661x / c661x.c
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: C661x Device Specific functions
40  ************************************************************************************
41  * FILE NAME: c661x.c
42  *
43  * DESCRIPTION: Implements the device specific functions for the IBL
44  *
45  * @file c661x.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 6616.
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)
107     if (address_is_local (addr))
108         addr = (1 << 28) | (DNUM << 24) | addr;
110     return (addr);
113         
114         
115 /**
116  * @brief
117  *   Enable the DDR
118  *
119  * @details
120  *   The DDR controller on the c661x is an emif 4.0. The controller is
121  *   initialized directly with the supplied values
122  */
123 void deviceDdrConfig (void)
125     /* The emif registers must be made visible. MPAX mapping 2 is used */
126     DEVICE_REG_XMPAX_L(2) =  0x10000000 | 0xf6;     /* 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);
133         
135 /**
136  *  @brief Power up a peripheral
137  *
138  *  @details
139  *    Boot peripherals are powered up
140  */
141 int32 devicePowerPeriph (int32 modNum)
143     int32 ret;
145     /* If the input value is < 0 there is nothing to power up */
146     if (modNum < 0)
147         return (0);
150     if (modNum >= TARGET_PWR_MAX_MOD)
151         return (-1);
154     /* Note that if the sgmii power enable is requested the PA must be
155      * powered up first */
156     if (modNum == TARGET_PWR_ETH(x))  {
157         ret = (int32)pscEnableModule (TARGET_PWR_PA);
158         if (ret != 0)
159             return (ret);
160     }
162     return ((int32)pscEnableModule(modNum));
163         
166 /**
167  *  @brief return the PSC module number for SPI
168  */
169 int32 deviceSpiPscNum (void)
171     uint32 v;
173     /* SPI is module number 3 only on the c6618. On the c6616 the SPI is in the
174      * always on domain */
175     v = *((Uint32 *)DEVICE_JTAG_ID_REG);
176     if (v == DEVICE_C6618_JTAG_ID_VAL)
177         return (3);
179     return (-1);  /* A negative number indicates the always on domain */
184 /**
185  *  @brief  Enable EMIF25 or SPI interface to the NAND
186  *
187  */
188 int32 deviceConfigureForNand(void)
191     return (0);
195 /**
196  *  @brief
197  *      Return the base memory address for emif25 in a given chip select space
198  */
199 uint32 deviceEmif25MemBase (int32 cs)
201     switch (cs)  {
203         case 2:  return (TARGET_MEM_NAND_CS_2);
205         case 3:  return (TARGET_MEM_NAND_CS_3);
207         case 4:  return (TARGET_MEM_NAND_CS_4);
209         case 5:  return (TARGET_MEM_NAND_CS_5);
211     }
213     return (0xffffffff);
218 /**
219  *  @brief
220  *      Return the PSC number for NAND/NOR through emif. Only 6618 has the emif
221  */
222 Int32 deviceEmifPscNum (void)
224     Uint32 v;
226     v = *((Uint32 *)DEVICE_JTAG_ID_REG);
227     if (v == DEVICE_C6618_JTAG_ID_VAL)
228         return (TARGET_PWR_EMIF_C6618);
230     /* Return a negative number to indicate no PSC module is associated with NAND */
231     return (-1);
237 /**
238  *  @brief
239  *    The e-fuse mac address is loaded
240  */
241 void deviceLoadDefaultEthAddress (uint8 *maddr)
243     uint32 macA, macB;
245     /* Read the e-fuse mac address */
246     macA = *((uint32 *)0x2620110);
247     macB = *((uint32 *)0x2620114);
249     maddr[0] = (macB >>  8) & 0xff;
250     maddr[1] = (macB >>  0) & 0xff;
251     maddr[2] = (macA >> 24) & 0xff;
252     maddr[3] = (macA >> 16) & 0xff;
253     maddr[4] = (macA >>  8) & 0xff;
254     maddr[5] = (macA >>  0) & 0xff;
258 /**
259  *  @brief
260  *    Compile time queue manager information
261  */
262 #define DEVICE_NUM_RX_CPPIS     1
263 #define DEVICE_NUM_TX_CPPIS     1
264 #define DEVICE_NUM_CPPIS        (DEVICE_NUM_RX_CPPIS + DEVICE_NUM_TX_CPPIS)
266 /* The linking RAM */
267 #pragma DATA_SECTION(qm_linkram_buf, ".linkram")
268 #pragma DATA_ALIGN(qm_linkram_buf, 16)
269 uint8 qm_linkram_buf[DEVICE_NUM_CPPIS * 2 * (sizeof(uint32)/sizeof(uint8))];
272 /* The CPPI RAM */
273 #pragma DATA_SECTION(qm_cppi_buf, ".cppi")
274 #pragma DATA_ALIGN(qm_cppi_buf, 16)
275 uint8 qm_cppi_buf[QM_DESC_SIZE_BYTES * DEVICE_NUM_CPPIS];
278 /* The rx data buffers */
279 #pragma DATA_SECTION(qm_buffer, ".mac_buffer")
280 #pragma DATA_ALIGN(qm_buffer, 16)
281 uint8 qm_buffer[MAX_SIZE_STREAM_BUFFER * DEVICE_NUM_RX_CPPIS];
283 const qmConfig_t qmConfig =  {
284     (UINT32) qm_linkram_buf,
285     sizeof  (qm_cppi_buf),
286     (UINT32) qm_cppi_buf,
288     DEVICE_NUM_CPPIS,
289     DEVICE_QM_FREE_Q
290 };
292 /**
293  *  @brief
294  *      Return the queue manager memory configuration information
295  */
296 void *targetGetQmConfig (void)
298     return ((void *)&qmConfig);
301 /**
302  *  @brief
303  *      Attach a packet buffer to each descriptor and push onto the linked buffer queue
304  */
305 void targetInitQs (void)
307     int32 i;
308     qmHostDesc_t *hd;
310     for (i = 0; i < DEVICE_NUM_RX_CPPIS; i++)  {
312         hd                = hwQmQueuePop (DEVICE_QM_FREE_Q);
313         hd->buffLen       = sizeof (qm_buffer) / DEVICE_NUM_CPPIS;
314         hd->buffPtr       = (UINT32) &(qm_buffer[MAX_SIZE_STREAM_BUFFER * i]);
315         hd->nextBDPtr     = 0;
316         hd->origBufferLen = MAX_SIZE_STREAM_BUFFER;
317         hd->origBuffPtr   = hd->buffPtr;
319         hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
321     }
324     for (i = 0; i < DEVICE_NUM_TX_CPPIS; i++)  {
326         hd                = hwQmQueuePop (DEVICE_QM_FREE_Q);
327         hd->buffLen       = 0;
328         hd->buffPtr       = 0;
329         hd->nextBDPtr     = 0;
330         hd->origBufferLen = 0;
331         hd->origBuffPtr   = 0;
333         hwQmQueuePush (hd, DEVICE_QM_TX_Q, QM_DESC_SIZE_BYTES);
335     }
342 const cpdmaRxCfg_t cpdmaEthRxCfg =  {
344     DEVICE_PA_CDMA_RX_CHAN_CFG_BASE,    /* Base address of PA CPDMA rx config registers */
345     DEVICE_PA_CDMA_RX_NUM_CHANNELS,     /* Number of rx channels */
347     DEVICE_PA_CDMA_RX_FLOW_CFG_BASE,    /* Base address of PA CPDMA rx flow registers */
348     DEVICE_PA_CDMA_RX_NUM_FLOWS,        /* Number of rx flows */
350     0,                                  /* Queue manager for descriptor / buffer for received packets */
351     DEVICE_QM_LNK_BUF_Q,                /* Queue of descriptors /buffers for received packets */
353     0,                                  /* Queue manager for received packets */
354     DEVICE_QM_RCV_Q,                    /* Queue for received packets (overridden by PA)  */
356     DEVICE_RX_CDMA_TIMEOUT_COUNT        /* Teardown maximum loop wait */
357 };
360 /**
361  *  @brief
362  *      Return the cpdma configuration information
363  */
364 void *targetGetCpdmaRxConfig (void)
366     return ((void *)&cpdmaEthRxCfg);
371 const cpdmaTxCfg_t cpdmaEthTxCfg = {
373     DEVICE_PA_CDMA_GLOBAL_CFG_BASE,     /* Base address of global config registers      */
374     DEVICE_PA_CDMA_TX_CHAN_CFG_BASE,    /* Base address of PA CPDMA tx config registers */
375     DEVICE_PA_CDMA_TX_NUM_CHANNELS      /* Number of tx channels */
377 };
380 /**
381  *  @brief
382  *      return the tx cpdma configuration information
383  */
384 void *targetGetCpdmaTxConfig (void)
386     return ((void *)&cpdmaEthTxCfg);
390 /**
391  *  @brief
392  *     Configure the PA
393  */
394 void targetPaConfig (uint8 *macAddr)
396     paConfig_t     paCfg;
397     qmHostDesc_t  *hd;
398     SINT16         ret;
400     /* Filter everything except the desired mac address and the broadcast mac */
401     paCfg.mac0ms = ((uint32)macAddr[0] << 24) | ((uint32)macAddr[1] << 16) | ((uint32)macAddr[2] << 8) | (uint32)(macAddr[3]);
402     paCfg.mac0ls = ((uint32)macAddr[4] << 24) | ((uint32)macAddr[5] << 16);
404     paCfg.mac1ms = 0xffffffff;
405     paCfg.mac1ls = 0xffff0000;
407     paCfg.rxQnum = DEVICE_QM_RCV_Q;
409     /* Form the configuration command in a buffer linked to a descriptor */
410     hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
411     paCfg.cmdBuf = (uint8 *)hd->origBuffPtr;
413     ret = hwPaEnable (&paCfg);
414     if (ret != 0)  {
415         iblStatus.iblFail = ibl_FAIL_CODE_PA;
416         return;
417     }
420     /* Send the command to the PA through the QM */
421     hd->softwareInfo0 = PA_MAGIC_ID;
422     hd->buffLen = 16;
423     QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, 16);
425     /* Set the return Queue */
426     QM_DESC_PINFO_SET_QM    (hd->packetInfo, 0);
427     QM_DESC_PINFO_SET_QUEUE (hd->packetInfo, DEVICE_QM_LNK_BUF_Q);
429     hwQmQueuePush (hd, DEVICE_QM_PA_CFG_Q, QM_DESC_SIZE_BYTES);
434 /**
435  *  @brief
436  *      Chip level SGMII serdes configuration
437  *
438  *  @details
439  *      Both lanes are always setup, regardless of the port value
440  */
441 void targetSgmiiSerdesConfig (int32 port, void *viblSgmii)
443   serdesConfig_t scfg;
444   iblSgmii_t     *sgmii = (iblSgmii_t *)viblSgmii;
446   scfg.cfg      = sgmii->auxConfig;
447   scfg.nLanes   = 2;
448   scfg.rxCfg[0] = scfg.rxCfg[1] = sgmii->rxConfig;
449   scfg.txCfg[0] = scfg.txCfg[1] = sgmii->txConfig;
451   hwSerdesConfig (TARGET_SGMII_SERDES_BASE, &scfg);
453   hwSerdesWaitLock (TARGET_SGMII_SERDES_STATUS_BASE);
458 Int32 targetMacSend (void *vptr_device, Uint8* buffer, int num_bytes) 
460     qmHostDesc_t   *hd;
461     NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
462     int             i;
465     /* Must always setup the descriptor to have the minimum packet length */
466     if (num_bytes < 64)
467         num_bytes = 64;
470     for (i = 0, hd = NULL; hd == NULL; i++, chipDelay32 (1000)) 
471         hd = hwQmQueuePop (DEVICE_QM_TX_Q);
472     
473     if (hd == NULL)
474         return (-1);
476     QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, num_bytes);
478     hd->buffLen       = num_bytes;
479     hd->origBufferLen = num_bytes;
481     hd->buffPtr     = deviceLocalAddrToGlobal((UINT32)buffer);
482     hd->origBuffPtr = deviceLocalAddrToGlobal((UINT32)buffer);
484     
485     /* Return the descriptor back to the transmit queue */
486     QM_DESC_PINFO_SET_QM(hd->packetInfo, 0);
487     QM_DESC_PINFO_SET_QUEUE(hd->packetInfo, DEVICE_QM_TX_Q);
489     hwQmQueuePush (hd, DEVICE_QM_ETH_TX_Q, QM_DESC_SIZE_BYTES);
491     return (0);
496 Int32 targetMacRcv (void *vptr_device, UINT8 *buffer)
498     Int32           pktSizeBytes; 
499     qmHostDesc_t   *hd;
500     NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
502     hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
503     if (hd == NULL)
504         return (0);
506     pktSizeBytes = QM_DESC_DESCINFO_GET_PKT_LEN(hd->descInfo);
507     iblMemcpy ((void *)buffer, (void *)hd->buffPtr, pktSizeBytes);
509     hd->buffLen = hd->origBufferLen;
510     hd->buffPtr = hd->origBuffPtr;
512     hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
514     return (pktSizeBytes);
518 void targetFreeQs (void)
520     qmHostDesc_t   *hd;
522     do  {
524         hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
526     } while (hd != NULL);
528     do  {
530         hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
532     } while (hd != NULL);
533     
534     do  {
536         hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
538     } while (hd != NULL);
539     
540     do  {
542         hd = hwQmQueuePop (DEVICE_QM_TX_Q);
544     } while (hd != NULL);
545     
546 }    
549 /**
550  *  @brief Return the NAND interface (EMIF25 or SPI) used based on the value
551  *         of interface
552  */
553 #ifndef EXCLUDE_NAND_EMIF
554 nandCtbl_t nandEmifCtbl =  {
556     nandHwDriverInit,
557     nandHwDriverReadBytes,
558     nandHwDriverReadPage,
559     nandHwDriverClose
561 };
562 #endif
564 #ifndef EXCLUDE_NAND_SPI
565 nandCtbl_t nandSpiCtbl =  {
568     nandHwSpiDriverInit,
569     nandHwSpiDriverReadBytes,
570     nandHwSpiDriverReadPage,
571     nandHwSpiDriverClose
573 };
574 #endif
576 nandCtbl_t *deviceGetNandCtbl (int32 interface)
579 #ifndef EXCLUDE_NAND_SPI
581     if (interface == ibl_PMEM_IF_SPI)
582         return (&nandSpiCtbl);
584 #endif
586 #ifndef EXCLUDE_NAND_EMIF
588     if ((interface >= ibl_PMEM_IF_CHIPSEL_2) && (interface <= ibl_PMEM_IF_CHIPSEL_5))
589         return (&nandEmifCtbl);
591 #endif
593     return (NULL);
598 /**
599  * @brief
600  *      Get the nor call table for the specified nor interface
601  */
603 #ifndef EXCLUDE_NOR_EMIF
604 norCtbl_t norEmifCtbl = {
605     
606     norHwEmifDriverInit,
607     norHwEmifDriverReadBytes,
608     norHwEmifDriverClose
610 };
612 #endif
614 #ifndef EXCLUDE_NOR_SPI
616 norCtbl_t norSpiCtbl = {
617     
618     norHwSpiDriverInit,
619     norHwSpiDriverReadBytes,
620     norHwSpiDriverClose
622 };
624 #endif
626 norCtbl_t *deviceGetNorCtbl (int32 interface)
629 #ifndef EXCLUDE_NOR_SPI
630     
631     if (interface == ibl_PMEM_IF_SPI)
632         return (&norSpiCtbl);
634 #endif
636 #ifndef EXCLUDE_NOR_EMIF
637    
638     if ((interface >= ibl_PMEM_IF_CHIPSEL_2) && (interface <= ibl_PMEM_IF_CHIPSEL_5))
639         return (&norEmifCtbl);
641 #endif
643     return (NULL);
646     
649     
655