Initial bug fixes for Nyquist IBL
[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 <string.h>
66 extern cregister unsigned int DNUM;
69 /**
70  *  @brief Determine if an address is local
71  *
72  *  @details
73  *    Examines an input address to determine if it is a local address. Using the largest
74  *    L2 size on the 6616.
75  */
76 bool address_is_local (Uint32 addr)
77 {
78     /* L2 */
79     if ((addr >= 0x00800000) && (addr < 0x00900000))
80         return (TRUE);
82     /* L1P */
83     if ((addr >= 0x00e00000) && (addr < 0x00e08000))
84         return (TRUE);
86     /* L2D */
87     if ((addr >= 0x00f00000) && (addr < 0x00f08000))
88         return (TRUE);
90     return (FALSE);
92 }
95 /**
96  * @brief  Convert a local l1d, l1p or l2 address to a global address
97  *
98  * @details
99  *  The global address is formed. If the address is not local then
100  *  the input address is returned
101  */
102 Uint32 deviceLocalAddrToGlobal (Uint32 addr)
105     if (address_is_local (addr))
106         addr = (1 << 28) | (DNUM << 24) | addr;
108     return (addr);
111         
112         
113 /**
114  * @brief
115  *   Enable the DDR
116  *
117  * @details
118  *   The DDR controller on the c661x is an emif 4.0. The controller is
119  *   initialized directly with the supplied values
120  */
121 void deviceDdrConfig (void)
123     /* The emif registers must be made visible. MPAX mapping 2 is used */
124     DEVICE_REG_XMPAX_L(2) =  0x10000000 | 0xf6;     /* replacement addr + perm*/
125     DEVICE_REG_XMPAX_H(2) =  0x2100000B;         /* base addr + seg size (64KB)*/       
127     if (ibl.ddrConfig.configDdr != 0)
128         hwEmif4p0Enable (&ibl.ddrConfig.uEmif.emif4p0);
131         
133 /**
134  *  @brief Power up a peripheral
135  *
136  *  @details
137  *    Boot peripherals are powered up
138  */
139 int32 devicePowerPeriph (int32 modNum)
141     int32 ret;
143     /* If the input value is < 0 there is nothing to power up */
144     if (modNum < 0)
145         return (0);
148     if (modNum >= TARGET_PWR_MAX_MOD)
149         return (-1);
152     /* Note that if the sgmii power enable is requested the PA must be
153      * powered up first */
154     if (modNum == TARGET_PWR_ETH(x))  {
155         ret = (int32)pscEnableModule (TARGET_PWR_PA);
156         if (ret != 0)
157             return (ret);
158     }
160     return ((int32)pscEnableModule(modNum));
161         
165 /**
166  *  @brief  Enable the pass through version of the nand controller
167  *
168  *  @details  On the evm the nand controller is enabled by setting 
169  *            gpio 14 high
170  */
171 #ifndef EXCLUDE_NAND
172 int32 deviceConfigureForNand(void)
174     return (0);
178 /**
179  *  @brief
180  *      Return the base memory address for NAND in a given chip select space
181  */
182 uint32 deviceNandMemBase (int32 cs)
184     switch (cs)  {
186         case 2:  return (TARGET_MEM_NAND_CS_2);
188         case 3:  return (TARGET_MEM_NAND_CS_3);
190         case 4:  return (TARGET_MEM_NAND_CS_4);
192         case 5:  return (TARGET_MEM_NAND_CS_5);
194     }
196     return (0xffffffff);
200 /**
201  *  @brief
202  *      Return the PSC number for NAND. Only 6618 has NAND
203  */
204 Int32 deviceNandPscNum (void)
206     Uint32 v;
208     v = *((Uint32 *)DEVICE_JTAG_ID_REG);
209     if (v == DEVICE_C6618_JTAG_ID_VAL)
210         return (TARGET_PWR_NAND_C6618);
212     /* Return a negative number to indicate no PSC module is associated with NAND */
213     return (-1);
218 #endif
221 /**
222  *  @brief
223  *    The e-fuse mac address is loaded
224  */
225 void deviceLoadDefaultEthAddress (uint8 *maddr)
227     uint32 macA, macB;
229     /* Read the e-fuse mac address */
230     macA = *((uint32 *)0x2620110);
231     macB = *((uint32 *)0x2620114);
233     maddr[0] = (macB >>  8) & 0xff;
234     maddr[1] = (macB >>  0) & 0xff;
235     maddr[2] = (macA >> 24) & 0xff;
236     maddr[3] = (macA >> 16) & 0xff;
237     maddr[4] = (macA >>  8) & 0xff;
238     maddr[5] = (macA >>  0) & 0xff;
242 /**
243  *  @brief
244  *    Compile time queue manager information
245  */
246 #define DEVICE_NUM_RX_CPPIS     1
247 #define DEVICE_NUM_TX_CPPIS     1
248 #define DEVICE_NUM_CPPIS        (DEVICE_NUM_RX_CPPIS + DEVICE_NUM_TX_CPPIS)
250 /* The linking RAM */
251 #pragma DATA_SECTION(qm_linkram_buf, ".linkram")
252 #pragma DATA_ALIGN(qm_linkram_buf, 16)
253 uint8 qm_linkram_buf[DEVICE_NUM_CPPIS * 2 * (sizeof(uint32)/sizeof(uint8))];
256 /* The CPPI RAM */
257 #pragma DATA_SECTION(qm_cppi_buf, ".cppi")
258 #pragma DATA_ALIGN(qm_cppi_buf, 16)
259 uint8 qm_cppi_buf[QM_DESC_SIZE_BYTES * DEVICE_NUM_CPPIS];
262 /* The rx data buffers */
263 #pragma DATA_SECTION(qm_buffer, ".mac_buffer")
264 #pragma DATA_ALIGN(qm_buffer, 16)
265 uint8 qm_buffer[MAX_SIZE_STREAM_BUFFER * DEVICE_NUM_RX_CPPIS];
267 const qmConfig_t qmConfig =  {
268     (UINT32) qm_linkram_buf,
269     sizeof  (qm_cppi_buf),
270     (UINT32) qm_cppi_buf,
272     DEVICE_NUM_CPPIS,
273     DEVICE_QM_FREE_Q
274 };
276 /**
277  *  @brief
278  *      Return the queue manager memory configuration information
279  */
280 void *targetGetQmConfig (void)
282     return ((void *)&qmConfig);
285 /**
286  *  @brief
287  *      Attach a packet buffer to each descriptor and push onto the linked buffer queue
288  */
289 void targetInitQs (void)
291     int32 i;
292     qmHostDesc_t *hd;
294     for (i = 0; i < DEVICE_NUM_RX_CPPIS; i++)  {
296         hd                = hwQmQueuePop (DEVICE_QM_FREE_Q);
297         hd->buffLen       = sizeof (qm_buffer) / DEVICE_NUM_CPPIS;
298         hd->buffPtr       = (UINT32) &(qm_buffer[MAX_SIZE_STREAM_BUFFER * i]);
299         hd->nextBDPtr     = 0;
300         hd->origBufferLen = MAX_SIZE_STREAM_BUFFER;
301         hd->origBuffPtr   = hd->buffPtr;
303         hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
305     }
308     for (i = 0; i < DEVICE_NUM_TX_CPPIS; i++)  {
310         hd                = hwQmQueuePop (DEVICE_QM_FREE_Q);
311         hd->buffLen       = 0;
312         hd->buffPtr       = 0;
313         hd->nextBDPtr     = 0;
314         hd->origBufferLen = 0;
315         hd->origBuffPtr   = 0;
317         hwQmQueuePush (hd, DEVICE_QM_TX_Q, QM_DESC_SIZE_BYTES);
319     }
326 const cpdmaRxCfg_t cpdmaEthRxCfg =  {
328     DEVICE_PA_CDMA_RX_CHAN_CFG_BASE,    /* Base address of PA CPDMA rx config registers */
329     DEVICE_PA_CDMA_RX_NUM_CHANNELS,     /* Number of rx channels */
331     DEVICE_PA_CDMA_RX_FLOW_CFG_BASE,    /* Base address of PA CPDMA rx flow registers */
332     DEVICE_PA_CDMA_RX_NUM_FLOWS,        /* Number of rx flows */
334     0,                                  /* Queue manager for descriptor / buffer for received packets */
335     DEVICE_QM_LNK_BUF_Q,                /* Queue of descriptors /buffers for received packets */
337     0,                                  /* Queue manager for received packets */
338     DEVICE_QM_RCV_Q,                    /* Queue for received packets (overridden by PA)  */
340     DEVICE_RX_CDMA_TIMEOUT_COUNT        /* Teardown maximum loop wait */
341 };
344 /**
345  *  @brief
346  *      Return the cpdma configuration information
347  */
348 void *targetGetCpdmaRxConfig (void)
350     return ((void *)&cpdmaEthRxCfg);
355 const cpdmaTxCfg_t cpdmaEthTxCfg = {
357     DEVICE_PA_CDMA_GLOBAL_CFG_BASE,     /* Base address of global config registers      */
358     DEVICE_PA_CDMA_TX_CHAN_CFG_BASE,    /* Base address of PA CPDMA tx config registers */
359     DEVICE_PA_CDMA_TX_NUM_CHANNELS      /* Number of tx channels */
361 };
364 /**
365  *  @brief
366  *      return the tx cpdma configuration information
367  */
368 void *targetGetCpdmaTxConfig (void)
370     return ((void *)&cpdmaEthTxCfg);
374 /**
375  *  @brief
376  *     Configure the PA
377  */
378 void targetPaConfig (uint8 *macAddr)
380     paConfig_t     paCfg;
381     qmHostDesc_t  *hd;
382     SINT16         ret;
384     /* Filter everything except the desired mac address and the broadcast mac */
385     paCfg.mac0ms = ((uint32)macAddr[0] << 24) | ((uint32)macAddr[1] << 16) | ((uint32)macAddr[2] << 8) | (uint32)(macAddr[3]);
386     paCfg.mac0ls = ((uint32)macAddr[4] << 24) | ((uint32)macAddr[5] << 16);
388     paCfg.mac1ms = 0xffffffff;
389     paCfg.mac1ls = 0xffff0000;
391     paCfg.rxQnum = DEVICE_QM_RCV_Q;
393     /* Form the configuration command in a buffer linked to a descriptor */
394     hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
395     paCfg.cmdBuf = (uint8 *)hd->origBuffPtr;
397     ret = hwPaEnable (&paCfg);
398     if (ret != 0)  {
399         iblStatus.iblFail = ibl_FAIL_CODE_PA;
400         return;
401     }
404     /* Send the command to the PA through the QM */
405     hd->softwareInfo0 = PA_MAGIC_ID;
406     hd->buffLen = 16;
407     QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, 16);
409     /* Set the return Queue */
410     QM_DESC_PINFO_SET_QM    (hd->packetInfo, 0);
411     QM_DESC_PINFO_SET_QUEUE (hd->packetInfo, DEVICE_QM_LNK_BUF_Q);
413     hwQmQueuePush (hd, DEVICE_QM_PA_CFG_Q, QM_DESC_SIZE_BYTES);
418 /**
419  *  @brief
420  *      Chip level SGMII serdes configuration
421  *
422  *  @details
423  *      Both lanes are always setup, regardless of the port value
424  */
425 void targetSgmiiSerdesConfig (int32 port, void *viblSgmii)
427   serdesConfig_t scfg;
428   iblSgmii_t     *sgmii = (iblSgmii_t *)viblSgmii;
430   scfg.cfg      = sgmii->auxConfig;
431   scfg.nLanes   = 2;
432   scfg.rxCfg[0] = scfg.rxCfg[1] = sgmii->rxConfig;
433   scfg.txCfg[0] = scfg.txCfg[1] = sgmii->txConfig;
435   hwSerdesConfig (TARGET_SGMII_SERDES_BASE, &scfg);
437   hwSerdesWaitLock (TARGET_SGMII_SERDES_STATUS_BASE);
442 Int32 targetMacSend (void *vptr_device, Uint8* buffer, int num_bytes) 
444     qmHostDesc_t   *hd;
445     NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
446     int             i;
449     for (i = 0, hd = NULL; hd == NULL; i++, chipDelay32 (1000)) 
450         hd = hwQmQueuePop (DEVICE_QM_TX_Q);
451     
452     if (hd == NULL)
453         return (-1);
455     QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, num_bytes);
457     hd->buffLen       = num_bytes;
458     hd->origBufferLen = num_bytes;
460     hd->buffPtr     = deviceLocalAddrToGlobal((UINT32)buffer);
461     hd->origBuffPtr = deviceLocalAddrToGlobal((UINT32)buffer);
463     
464     /* Return the descriptor back to the transmit queue */
465     QM_DESC_PINFO_SET_QM(hd->packetInfo, 0);
466     QM_DESC_PINFO_SET_QUEUE(hd->packetInfo, DEVICE_QM_TX_Q);
468     hwQmQueuePush (hd, DEVICE_QM_ETH_TX_Q, QM_DESC_SIZE_BYTES);
470     return (0);
475 Int32 targetMacRcv (void *vptr_device, UINT8 *buffer)
477     Int32           pktSizeBytes; 
478     qmHostDesc_t   *hd;
479     NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
481     hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
482     if (hd == NULL)
483         return (0);
485     pktSizeBytes = QM_DESC_DESCINFO_GET_PKT_LEN(hd->descInfo);
486     iblMemcpy ((void *)buffer, (void *)hd->buffPtr, pktSizeBytes);
488     hd->buffLen = hd->origBufferLen;
489     hd->buffPtr = hd->origBuffPtr;
491     hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
493     return (pktSizeBytes);
497 void targetFreeQs (void)
499     qmHostDesc_t   *hd;
501     do  {
503         hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
505     } while (hd != NULL);
507     do  {
509         hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
511     } while (hd != NULL);
512     
513     do  {
515         hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
517     } while (hd != NULL);
518     
519     do  {
521         hd = hwQmQueuePop (DEVICE_QM_TX_Q);
523     } while (hd != NULL);
524     
525 }    
528     
534