22f0e088fd0ea47ecfe322385654f00240b15277
[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 "evmc66x_uart.h"
71 #define PLL_DDR_INIT_LOOPMAX 10
72 #define IBL_STR_LEN          20
74 extern cregister unsigned int DNUM;
75 #define DDR3_TEST_ENABLE
77 #ifdef DDR3_TEST_ENABLE
78 /**
79  *  @brief Simple DDR3 test
80  *
81  *  @details
82  *      This function performs a simple DDR3 test for a memory range
83  *      specified below and returns -1 for failure and 0 for success.
84  */
86 #define DDR3_TEST_START_ADDRESS 0x80000000
88 #define DDR3_TEST_END_ADDRESS   (DDR3_TEST_START_ADDRESS + (128 *1024))
90 static int32_t ddr3_memory_test (void)
91 {
92         uint32_t index, value;
94         /* Write a pattern */
95         for (index = DDR3_TEST_START_ADDRESS; index < DDR3_TEST_END_ADDRESS; index += 4) {
96                 *(volatile uint32_t *) index = (uint32_t)index;
97         }
99         /* Read and check the pattern */
100         for (index = DDR3_TEST_START_ADDRESS; index < DDR3_TEST_END_ADDRESS; index += 4) {
102                 value = *(uint32_t *) index;
104                 if (value  != index) {
105                         return -1;
106                 }
107         }
109         /* Write a pattern for complementary values */
110         for (index = DDR3_TEST_START_ADDRESS; index < DDR3_TEST_END_ADDRESS; index += 4) {
111                 *(volatile uint32_t *) index = (uint32_t)~index;
112         }
114         /* Read and check the pattern */
115         for (index = DDR3_TEST_START_ADDRESS; index < DDR3_TEST_END_ADDRESS; index += 4) {
117                 value = *(uint32_t *) index;
119                 if (value  != ~index) {
120                         return -1;
121                 }
122         }
124         return 0;
127 #endif
129 /**
130  *  @brief Determine if an address is local
131  *
132  *  @details
133  *    Examines an input address to determine if it is a local address. Using the largest
134  *    L2 size on the C6670.
135  */
136 bool address_is_local (Uint32 addr)
138     /* L2 */
139     if ((addr >= 0x00800000) && (addr < 0x00900000))
140         return (TRUE);
142     /* L1P */
143     if ((addr >= 0x00e00000) && (addr < 0x00e08000))
144         return (TRUE);
146     /* L2D */
147     if ((addr >= 0x00f00000) && (addr < 0x00f08000))
148         return (TRUE);
150     return (FALSE);
155 /**
156  * @brief  Convert a local l1d, l1p or l2 address to a global address
157  *
158  * @details
159  *  The global address is formed. If the address is not local then
160  *  the input address is returned
161  */
162 Uint32 deviceLocalAddrToGlobal (Uint32 addr)
165     if (address_is_local (addr))
166         addr = (1 << 28) | (DNUM << 24) | addr;
168     return (addr);
171         
172         
173 /**
174  * @brief
175  *   Enable the DDR
176  *
177  * @details
178  *   The DDR controller on the c66x is an emif 4.0. The controller is
179  *   initialized directly with the supplied values
180  */
181 void deviceDdrConfig (void)
183     uint32 loopcount=0;
184     int8  ddr_pass_str[IBL_STR_LEN] = "IBL: DDR TEST PASS\n";
185     int8  ddr_fail_str[IBL_STR_LEN] = "IBL: DDR TEST FAIL\n";
186     int8  ibl_msg_str1[IBL_STR_LEN] = "IBL: PLL SEQ DONE \n";
187         
188                 
189     /* The emif registers must be made visible. MPAX mapping 2 is used */
190     DEVICE_REG_XMPAX_L(2) =  0x10000000 | 0xff;     /* replacement addr + perm*/
191     DEVICE_REG_XMPAX_H(2) =  0x2100000B;         /* base addr + seg size (64KB)*/       
192     
193     for (loopcount = 0; loopcount < PLL_DDR_INIT_LOOPMAX ; loopcount++)
194     {
195         if(loopcount !=0) /*Do not call PLL sequence for the first time */
196         {
197         /* Calling MAIN, PA, DDR PLL init  */
198             if (ibl.pllConfig[ibl_MAIN_PLL].doEnable == TRUE)
199                 hwPllSetPll (MAIN_PLL, 
200                              ibl.pllConfig[ibl_MAIN_PLL].prediv,
201                                  ibl.pllConfig[ibl_MAIN_PLL].mult,
202                                  ibl.pllConfig[ibl_MAIN_PLL].postdiv);
203     
204             if (ibl.pllConfig[ibl_NET_PLL].doEnable == TRUE)
205                 hwPllSetCfgPll (DEVICE_PLL_BASE(NET_PLL),
206                                 ibl.pllConfig[ibl_NET_PLL].prediv,
207                                 ibl.pllConfig[ibl_NET_PLL].mult,
208                                 ibl.pllConfig[ibl_NET_PLL].postdiv,
209                                 ibl.pllConfig[ibl_MAIN_PLL].pllOutFreqMhz,
210                                 ibl.pllConfig[ibl_NET_PLL].pllOutFreqMhz);
211     
212             if (ibl.pllConfig[ibl_DDR_PLL].doEnable == TRUE)
213                 hwPllSetCfg2Pll (DEVICE_PLL_BASE(DDR_PLL),
214                                  ibl.pllConfig[ibl_DDR_PLL].prediv,
215                                  ibl.pllConfig[ibl_DDR_PLL].mult,
216                                  ibl.pllConfig[ibl_DDR_PLL].postdiv,
217                                  ibl.pllConfig[ibl_MAIN_PLL].pllOutFreqMhz,
218                                  ibl.pllConfig[ibl_DDR_PLL].pllOutFreqMhz);
219           }
220           
221         if (ibl.ddrConfig.configDdr != 0)
222             hwEmif4p0Enable (&ibl.ddrConfig.uEmif.emif4p0);
223         /* Init UART */
224          uart_init();
225         /* Write something to UART */
226          uart_write_string(ibl_msg_str1,IBL_STR_LEN);
227 #ifdef DDR3_TEST_ENABLE
228         if (ddr3_memory_test() == 0) 
229         {
230             uart_write_string(ddr_pass_str,IBL_STR_LEN);
231             break;
232         }
233 #endif
234       uart_write_string(ddr_fail_str,IBL_STR_LEN);
236     }
239         
242 /**
243  *  @brief  Enable EMIF25 or SPI interface to the NAND
244  *
245  */
246 int32 deviceConfigureForNand(void)
249     return (0);
253 /**
254  *  @brief
255  *      Return the base memory address for emif25 in a given chip select space
256  */
257 uint32 deviceEmif25MemBase (int32 cs)
259     switch (cs)  {
261         case 2:  return (TARGET_MEM_NAND_CS_2);
263         case 3:  return (TARGET_MEM_NAND_CS_3);
265         case 4:  return (TARGET_MEM_NAND_CS_4);
267         case 5:  return (TARGET_MEM_NAND_CS_5);
269     }
271     return (0xffffffff);
276 /**
277  *  @brief
278  *      Return the PSC number for NAND/NOR through emif. Only 6678 has the emif
279  */
280 Int32 deviceEmifPscNum (void)
282     Uint32 v;
284     v = *((Uint32 *)DEVICE_JTAG_ID_REG);
285     v &= DEVICE_JTAG_ID_MASK;
286     if (v == DEVICE_C6678_JTAG_ID_VAL)
287         return (TARGET_PWR_EMIF_C6678);
289     /* Return a negative number to indicate no PSC module is associated with NAND */
290     return (-1);
296 /**
297  *  @brief
298  *    The e-fuse mac address is loaded
299  */
300 void deviceLoadDefaultEthAddress (uint8 *maddr)
302     uint32 macA, macB;
304     /* Read the e-fuse mac address */
305     macA = *((uint32 *)0x2620110);
306     macB = *((uint32 *)0x2620114);
308     maddr[0] = (macB >>  8) & 0xff;
309     maddr[1] = (macB >>  0) & 0xff;
310     maddr[2] = (macA >> 24) & 0xff;
311     maddr[3] = (macA >> 16) & 0xff;
312     maddr[4] = (macA >>  8) & 0xff;
313     maddr[5] = (macA >>  0) & 0xff;
317 /**
318  *  @brief
319  *    Compile time queue manager information
320  */
321 #define DEVICE_NUM_RX_CPPIS     1
322 #define DEVICE_NUM_TX_CPPIS     1
323 #define DEVICE_NUM_CPPIS        (DEVICE_NUM_RX_CPPIS + DEVICE_NUM_TX_CPPIS)
325 /* The linking RAM */
326 #pragma DATA_SECTION(qm_linkram_buf, ".linkram")
327 #pragma DATA_ALIGN(qm_linkram_buf, 16)
328 uint8 qm_linkram_buf[DEVICE_NUM_CPPIS * 2 * (sizeof(uint32)/sizeof(uint8))];
331 /* The CPPI RAM */
332 #pragma DATA_SECTION(qm_cppi_buf, ".cppi")
333 #pragma DATA_ALIGN(qm_cppi_buf, 16)
334 uint8 qm_cppi_buf[QM_DESC_SIZE_BYTES * DEVICE_NUM_CPPIS];
337 /* The rx data buffers */
338 #pragma DATA_SECTION(qm_buffer, ".mac_buffer")
339 #pragma DATA_ALIGN(qm_buffer, 16)
340 uint8 qm_buffer[MAX_SIZE_STREAM_BUFFER * DEVICE_NUM_RX_CPPIS];
342 const qmConfig_t qmConfig =  {
343     (UINT32) qm_linkram_buf,
344     sizeof  (qm_cppi_buf),
345     (UINT32) qm_cppi_buf,
347     DEVICE_NUM_CPPIS,
348     DEVICE_QM_FREE_Q
349 };
351 /**
352  *  @brief
353  *      Return the queue manager memory configuration information
354  */
355 void *targetGetQmConfig (void)
357     return ((void *)&qmConfig);
360 /**
361  *  @brief
362  *      Attach a packet buffer to each descriptor and push onto the linked buffer queue
363  */
364 void targetInitQs (void)
366     int32 i;
367     qmHostDesc_t *hd;
369     for (i = 0; i < DEVICE_NUM_RX_CPPIS; i++)  {
371         hd                = hwQmQueuePop (DEVICE_QM_FREE_Q);
372         hd->buffLen       = sizeof (qm_buffer) / DEVICE_NUM_CPPIS;
373         hd->buffPtr       = (UINT32) &(qm_buffer[MAX_SIZE_STREAM_BUFFER * i]);
374         hd->nextBDPtr     = 0;
375         hd->origBufferLen = MAX_SIZE_STREAM_BUFFER;
376         hd->origBuffPtr   = hd->buffPtr;
378         hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
380     }
383     for (i = 0; i < DEVICE_NUM_TX_CPPIS; i++)  {
385         hd                = hwQmQueuePop (DEVICE_QM_FREE_Q);
386         hd->buffLen       = 0;
387         hd->buffPtr       = 0;
388         hd->nextBDPtr     = 0;
389         hd->origBufferLen = 0;
390         hd->origBuffPtr   = 0;
392         hwQmQueuePush (hd, DEVICE_QM_TX_Q, QM_DESC_SIZE_BYTES);
394     }
401 const cpdmaRxCfg_t cpdmaEthRxCfg =  {
403     DEVICE_PA_CDMA_RX_CHAN_CFG_BASE,    /* Base address of PA CPDMA rx config registers */
404     DEVICE_PA_CDMA_RX_NUM_CHANNELS,     /* Number of rx channels */
406     DEVICE_PA_CDMA_RX_FLOW_CFG_BASE,    /* Base address of PA CPDMA rx flow registers */
407     DEVICE_PA_CDMA_RX_NUM_FLOWS,        /* Number of rx flows */
409     0,                                  /* Queue manager for descriptor / buffer for received packets */
410     DEVICE_QM_LNK_BUF_Q,                /* Queue of descriptors /buffers for received packets */
412     0,                                  /* Queue manager for received packets */
413     DEVICE_QM_RCV_Q,                    /* Queue for received packets (overridden by PA)  */
415     DEVICE_RX_CDMA_TIMEOUT_COUNT        /* Teardown maximum loop wait */
416 };
419 /**
420  *  @brief
421  *      Return the cpdma configuration information
422  */
423 void *targetGetCpdmaRxConfig (void)
425     return ((void *)&cpdmaEthRxCfg);
430 const cpdmaTxCfg_t cpdmaEthTxCfg = {
432     DEVICE_PA_CDMA_GLOBAL_CFG_BASE,     /* Base address of global config registers      */
433     DEVICE_PA_CDMA_TX_CHAN_CFG_BASE,    /* Base address of PA CPDMA tx config registers */
434     DEVICE_PA_CDMA_TX_NUM_CHANNELS      /* Number of tx channels */
436 };
439 /**
440  *  @brief
441  *      return the tx cpdma configuration information
442  */
443 void *targetGetCpdmaTxConfig (void)
445     return ((void *)&cpdmaEthTxCfg);
449 /**
450  *  @brief
451  *     Configure the PA
452  */
453 void targetPaConfig (uint8 *macAddr)
455     paConfig_t     paCfg;
456     qmHostDesc_t  *hd;
457     SINT16         ret;
459     /* Filter everything except the desired mac address and the broadcast mac */
460     paCfg.mac0ms = ((uint32)macAddr[0] << 24) | ((uint32)macAddr[1] << 16) | ((uint32)macAddr[2] << 8) | (uint32)(macAddr[3]);
461     paCfg.mac0ls = ((uint32)macAddr[4] << 24) | ((uint32)macAddr[5] << 16);
463     paCfg.mac1ms = 0xffffffff;
464     paCfg.mac1ls = 0xffff0000;
466     paCfg.rxQnum = DEVICE_QM_RCV_Q;
468     /* Form the configuration command in a buffer linked to a descriptor */
469     hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
470     paCfg.cmdBuf = (uint8 *)hd->origBuffPtr;
472     ret = hwPaEnable (&paCfg);
473     if (ret != 0)  {
474         iblStatus.iblFail = ibl_FAIL_CODE_PA;
475         return;
476     }
479     /* Send the command to the PA through the QM */
480     hd->softwareInfo0 = PA_MAGIC_ID;
481     hd->buffLen = 16;
482     QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, 16);
484     /* Set the return Queue */
485     QM_DESC_PINFO_SET_QM    (hd->packetInfo, 0);
486     QM_DESC_PINFO_SET_QUEUE (hd->packetInfo, DEVICE_QM_LNK_BUF_Q);
488     hwQmQueuePush (hd, DEVICE_QM_PA_CFG_Q, QM_DESC_SIZE_BYTES);
493 /**
494  *  @brief
495  *      Chip level SGMII serdes configuration
496  *
497  *  @details
498  *      Both lanes are always setup, regardless of the port value
499  */
500 void targetSgmiiSerdesConfig (int32 port, void *viblSgmii)
502   serdesConfig_t scfg;
503   iblSgmii_t     *sgmii = (iblSgmii_t *)viblSgmii;
505   scfg.cfg      = sgmii->auxConfig;
506   scfg.nLanes   = 2;
507   scfg.rxCfg[0] = scfg.rxCfg[1] = sgmii->rxConfig;
508   scfg.txCfg[0] = scfg.txCfg[1] = sgmii->txConfig;
510   hwSerdesConfig (TARGET_SGMII_SERDES_BASE, &scfg);
512   hwSerdesWaitLock (TARGET_SGMII_SERDES_STATUS_BASE);
517 Int32 targetMacSend (void *vptr_device, Uint8* buffer, int num_bytes) 
519     qmHostDesc_t   *hd;
520     NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
521     int             i;
524     /* Must always setup the descriptor to have the minimum packet length */
525     if (num_bytes < 64)
526         num_bytes = 64;
529     for (i = 0, hd = NULL; hd == NULL; i++, chipDelay32 (1000)) 
530         hd = hwQmQueuePop (DEVICE_QM_TX_Q);
531     
532     if (hd == NULL)
533         return (-1);
535     QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, num_bytes);
537     hd->buffLen       = num_bytes;
538     hd->origBufferLen = num_bytes;
540     hd->buffPtr     = deviceLocalAddrToGlobal((UINT32)buffer);
541     hd->origBuffPtr = deviceLocalAddrToGlobal((UINT32)buffer);
543     
544     /* Return the descriptor back to the transmit queue */
545     QM_DESC_PINFO_SET_QM(hd->packetInfo, 0);
546     QM_DESC_PINFO_SET_QUEUE(hd->packetInfo, DEVICE_QM_TX_Q);
548     hwQmQueuePush (hd, DEVICE_QM_ETH_TX_Q, QM_DESC_SIZE_BYTES);
550     return (0);
555 Int32 targetMacRcv (void *vptr_device, UINT8 *buffer)
557     Int32           pktSizeBytes; 
558     qmHostDesc_t   *hd;
559     NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
561     hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
562     if (hd == NULL)
563         return (0);
565     pktSizeBytes = QM_DESC_DESCINFO_GET_PKT_LEN(hd->descInfo);
566     iblMemcpy ((void *)buffer, (void *)hd->buffPtr, pktSizeBytes);
568     hd->buffLen = hd->origBufferLen;
569     hd->buffPtr = hd->origBuffPtr;
571     hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
573     return (pktSizeBytes);
577 void targetFreeQs (void)
579     qmHostDesc_t   *hd;
581     do  {
583         hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
585     } while (hd != NULL);
587     do  {
589         hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
591     } while (hd != NULL);
592     
593     do  {
595         hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
597     } while (hd != NULL);
598     
599     do  {
601         hd = hwQmQueuePop (DEVICE_QM_TX_Q);
603     } while (hd != NULL);
604     
605 }    
607 extern nandCtbl_t nandEmifCtbl;
608 /**
609  *  @brief Return the NAND interface (GPIO, EMIF25 or SPI) used based on the value
610  *         of interface
611  */
612 #ifndef EXCLUDE_NAND_GPIO
613 nandCtbl_t nandGpioCtbl =  {
615     nandHwGpioDriverInit,
616     nandHwGpioDriverReadBytes,
617     nandHwGpioDriverReadPage,
618     nandHwGpioDriverClose
620 };
621 #endif
623 #ifndef EXCLUDE_NAND_EMIF
624 extern Int32 nandHwEmifDriverInit (int32 cs, void *vdevInfo);
625 extern Int32 nandHwEmifDriverReadBytes (Uint32 block, Uint32 page, Uint32 byte, Uint32 nbytes, Uint8 *data);
626 extern Int32 nandHwEmifDriverReadPage (Uint32 block, Uint32 page, Uint8 *data);
627 extern Int32 nandHwEmifDriverClose (void);
629 nandCtbl_t nandEmifCtbl =  {
631     nandHwEmifDriverInit,
632     nandHwEmifDriverReadBytes,
633     nandHwEmifDriverReadPage,
634     nandHwEmifDriverClose
636 };
637 #endif
639 #ifndef EXCLUDE_NAND_SPI
640 nandCtbl_t nandSpiCtbl =  {
643     nandHwSpiDriverInit,
644     nandHwSpiDriverReadBytes,
645     nandHwSpiDriverReadPage,
646     nandHwSpiDriverClose
648 };
649 #endif
651 nandCtbl_t *deviceGetNandCtbl (int32 interface)
653 #ifndef EXCLUDE_NAND_GPIO
655     if (interface == ibl_PMEM_IF_GPIO)
656         return (&nandGpioCtbl);
658 #endif
660 #ifndef EXCLUDE_NAND_SPI
662     if (interface == ibl_PMEM_IF_SPI)
663         return (&nandSpiCtbl);
665 #endif
667 #ifndef EXCLUDE_NAND_EMIF
669     if ((interface >= ibl_PMEM_IF_CHIPSEL_2) && (interface <= ibl_PMEM_IF_CHIPSEL_5))
670         return (&nandEmifCtbl);
672 #endif
674     return (NULL);
679 /**
680  * @brief
681  *      Get the nor call table for the specified nor interface
682  */
684 #ifndef EXCLUDE_NOR_EMIF
685 norCtbl_t norEmifCtbl = {
686     
687     norHwEmifDriverInit,
688     norHwEmifDriverReadBytes,
689     norHwEmifDriverClose
691 };
693 #endif
695 #ifndef EXCLUDE_NOR_SPI
697 norCtbl_t norSpiCtbl = {
698     
699     norHwSpiDriverInit,
700     norHwSpiDriverReadBytes,
701     norHwSpiDriverClose
703 };
705 #endif
707 norCtbl_t *deviceGetNorCtbl (int32 interface)
710 #ifndef EXCLUDE_NOR_SPI
711     
712     if (interface == ibl_PMEM_IF_SPI)
713         return (&norSpiCtbl);
715 #endif
717 #ifndef EXCLUDE_NOR_EMIF
718    
719     if ((interface >= ibl_PMEM_IF_CHIPSEL_2) && (interface <= ibl_PMEM_IF_CHIPSEL_5))
720         return (&norEmifCtbl);
722 #endif
724     return (NULL);
727     
730     
736