0fcdd99e7628988472d1e4754a262565eab150e7
[keystone-rtos/ibl.git] / src / device / c66x / c66x.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: 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);
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)
114     if (address_is_local (addr))
115         addr = (1 << 28) | (DNUM << 24) | addr;
117     return (addr);
120         
121         
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)
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)*/       
137     
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);
150     
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);
158     
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);
166           
167         if (ibl.ddrConfig.configDdr != 0)
168             hwEmif4p0Enable (&ibl.ddrConfig.uEmif.emif4p0);
169                         
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
204         
207 /**
208  *  @brief  Enable EMIF25 or SPI interface to the NAND
209  *
210  */
211 int32 deviceConfigureForNand(void)
214     return (0);
218 /**
219  *  @brief
220  *      Return the base memory address for emif25 in a given chip select space
221  */
222 uint32 deviceEmif25MemBase (int32 cs)
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);
241 /**
242  *  @brief
243  *      Return the PSC number for NAND/NOR through emif. Only 6678 has the emif
244  */
245 Int32 deviceEmifPscNum (void)
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);
261 /**
262  *  @brief
263  *    The e-fuse mac address is loaded
264  */
265 void deviceLoadDefaultEthAddress (uint8 *maddr)
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;
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)
322     return ((void *)&qmConfig);
325 /**
326  *  @brief
327  *      Attach a packet buffer to each descriptor and push onto the linked buffer queue
328  */
329 void targetInitQs (void)
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     }
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)
390     return ((void *)&cpdmaEthRxCfg);
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)
410     return ((void *)&cpdmaEthTxCfg);
414 /**
415  *  @brief
416  *     Configure the PA
417  */
418 void targetPaConfig (uint8 *macAddr)
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);
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)
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);
482 Int32 targetMacSend (void *vptr_device, Uint8* buffer, int num_bytes) 
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);
496     
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);
508     
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);
520 Int32 targetMacRcv (void *vptr_device, UINT8 *buffer)
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);
542 void targetFreeQs (void)
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);
557     
558     do  {
560         hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
562     } while (hd != NULL);
563     
564     do  {
566         hd = hwQmQueuePop (DEVICE_QM_TX_Q);
568     } while (hd != NULL);
569     
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)
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);
644 /**
645  * @brief
646  *      Get the nor call table for the specified nor interface
647  */
649 #ifndef EXCLUDE_NOR_EMIF
650 norCtbl_t norEmifCtbl = {
651     
652     norHwEmifDriverInit,
653     norHwEmifDriverReadBytes,
654     norHwEmifDriverClose
656 };
658 #endif
660 #ifndef EXCLUDE_NOR_SPI
662 norCtbl_t norSpiCtbl = {
663     
664     norHwSpiDriverInit,
665     norHwSpiDriverReadBytes,
666     norHwSpiDriverClose
668 };
670 #endif
672 norCtbl_t *deviceGetNorCtbl (int32 interface)
675 #ifndef EXCLUDE_NOR_SPI
676     
677     if (interface == ibl_PMEM_IF_SPI)
678         return (&norSpiCtbl);
680 #endif
682 #ifndef EXCLUDE_NOR_EMIF
683    
684     if ((interface >= ibl_PMEM_IF_CHIPSEL_2) && (interface <= ibl_PMEM_IF_CHIPSEL_5))
685         return (&norEmifCtbl);
687 #endif
689     return (NULL);
692     
695     
701