Modified IBL to re-init PLL in DDR controller, added UART
[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 extern cregister unsigned int DNUM;
73 #define DDR3_TEST_ENABLE
75 #ifdef DDR3_TEST_ENABLE
76 /**
77  *  @brief Simple DDR3 test
78  *
79  *  @details
80  *      This function performs a simple DDR3 test for a memory range
81  *      specified below and returns -1 for failure and 0 for success.
82  */
84 #define DDR3_TEST_START_ADDRESS 0x80000000
86 #define DDR3_TEST_END_ADDRESS   (DDR3_TEST_START_ADDRESS + (128 *1024))
88 static int32_t ddr3_memory_test (void)
89 {
90         uint32_t index, value;
92         /* Write a pattern */
93         for (index = DDR3_TEST_START_ADDRESS; index < DDR3_TEST_END_ADDRESS; index += 4) {
94                 *(volatile uint32_t *) index = (uint32_t)index;
95         }
97         /* Read and check the pattern */
98         for (index = DDR3_TEST_START_ADDRESS; index < DDR3_TEST_END_ADDRESS; index += 4) {
100                 value = *(uint32_t *) index;
102                 if (value  != index) {
103                         return -1;
104                 }
105         }
107         /* Write a pattern for complementary values */
108         for (index = DDR3_TEST_START_ADDRESS; index < DDR3_TEST_END_ADDRESS; index += 4) {
109                 *(volatile uint32_t *) index = (uint32_t)~index;
110         }
112         /* Read and check the pattern */
113         for (index = DDR3_TEST_START_ADDRESS; index < DDR3_TEST_END_ADDRESS; index += 4) {
115                 value = *(uint32_t *) index;
117                 if (value  != ~index) {
118                         return -1;
119                 }
120         }
122         return 0;
125 #endif
127 /**
128  *  @brief Determine if an address is local
129  *
130  *  @details
131  *    Examines an input address to determine if it is a local address. Using the largest
132  *    L2 size on the C6670.
133  */
134 bool address_is_local (Uint32 addr)
136     /* L2 */
137     if ((addr >= 0x00800000) && (addr < 0x00900000))
138         return (TRUE);
140     /* L1P */
141     if ((addr >= 0x00e00000) && (addr < 0x00e08000))
142         return (TRUE);
144     /* L2D */
145     if ((addr >= 0x00f00000) && (addr < 0x00f08000))
146         return (TRUE);
148     return (FALSE);
153 /**
154  * @brief  Convert a local l1d, l1p or l2 address to a global address
155  *
156  * @details
157  *  The global address is formed. If the address is not local then
158  *  the input address is returned
159  */
160 Uint32 deviceLocalAddrToGlobal (Uint32 addr)
163     if (address_is_local (addr))
164         addr = (1 << 28) | (DNUM << 24) | addr;
166     return (addr);
169         
170         
171 /**
172  * @brief
173  *   Enable the DDR
174  *
175  * @details
176  *   The DDR controller on the c66x is an emif 4.0. The controller is
177  *   initialized directly with the supplied values
178  */
179 void deviceDdrConfig (void)
181     uint32 loopcount=0;
182     uint32 uartcount=10;
183     int8  ddr_pass_str[20] = "IBL: DDR TEST PASS\n";
184     int8  ddr_fail_str[20] = "IBL: DDR TEST FAIL\n";
185     int8  ibl_msg_str1[20] = "IBL: PLL SEQ DONE \n";
186         
187                 
188     /* The emif registers must be made visible. MPAX mapping 2 is used */
189     DEVICE_REG_XMPAX_L(2) =  0x10000000 | 0xff;     /* replacement addr + perm*/
190     DEVICE_REG_XMPAX_H(2) =  0x2100000B;         /* base addr + seg size (64KB)*/       
191     
192     for (loopcount = 0; loopcount < PLL_DDR_INIT_LOOPMAX ; loopcount++)
193     {
194         if(loopcount !=0) /*Do not call PLL sequence for the first time */
195         {
196         /* Calling MAIN, PA, DDR PLL init  */
197             if (ibl.pllConfig[ibl_MAIN_PLL].doEnable == TRUE)
198                 hwPllSetPll (MAIN_PLL, 
199                              ibl.pllConfig[ibl_MAIN_PLL].prediv,
200                                  ibl.pllConfig[ibl_MAIN_PLL].mult,
201                                  ibl.pllConfig[ibl_MAIN_PLL].postdiv);
202     
203             if (ibl.pllConfig[ibl_NET_PLL].doEnable == TRUE)
204                 hwPllSetCfgPll (DEVICE_PLL_BASE(NET_PLL),
205                                 ibl.pllConfig[ibl_NET_PLL].prediv,
206                                 ibl.pllConfig[ibl_NET_PLL].mult,
207                                 ibl.pllConfig[ibl_NET_PLL].postdiv,
208                                 ibl.pllConfig[ibl_MAIN_PLL].pllOutFreqMhz,
209                                 ibl.pllConfig[ibl_NET_PLL].pllOutFreqMhz);
210     
211             if (ibl.pllConfig[ibl_DDR_PLL].doEnable == TRUE)
212                 hwPllSetCfg2Pll (DEVICE_PLL_BASE(DDR_PLL),
213                                  ibl.pllConfig[ibl_DDR_PLL].prediv,
214                                  ibl.pllConfig[ibl_DDR_PLL].mult,
215                                  ibl.pllConfig[ibl_DDR_PLL].postdiv,
216                                  ibl.pllConfig[ibl_MAIN_PLL].pllOutFreqMhz,
217                                  ibl.pllConfig[ibl_DDR_PLL].pllOutFreqMhz);
218           }
219           
220         if (ibl.ddrConfig.configDdr != 0)
221             hwEmif4p0Enable (&ibl.ddrConfig.uEmif.emif4p0);
222         /* Init UART */
223          uart_init();
224         /* Write something to UART */
225            uart_write_string(ibl_msg_str1,19);
226 #ifdef DDR3_TEST_ENABLE
227         if (ddr3_memory_test() == 0) 
228         {
229             uart_write_string(ddr_pass_str,19);
230             break;
231         }
232 #endif
233       uart_write_string(ddr_fail_str,19);
235     }
238         
241 /**
242  *  @brief  Enable EMIF25 or SPI interface to the NAND
243  *
244  */
245 int32 deviceConfigureForNand(void)
248     return (0);
252 /**
253  *  @brief
254  *      Return the base memory address for emif25 in a given chip select space
255  */
256 uint32 deviceEmif25MemBase (int32 cs)
258     switch (cs)  {
260         case 2:  return (TARGET_MEM_NAND_CS_2);
262         case 3:  return (TARGET_MEM_NAND_CS_3);
264         case 4:  return (TARGET_MEM_NAND_CS_4);
266         case 5:  return (TARGET_MEM_NAND_CS_5);
268     }
270     return (0xffffffff);
275 /**
276  *  @brief
277  *      Return the PSC number for NAND/NOR through emif. Only 6678 has the emif
278  */
279 Int32 deviceEmifPscNum (void)
281     Uint32 v;
283     v = *((Uint32 *)DEVICE_JTAG_ID_REG);
284     v &= DEVICE_JTAG_ID_MASK;
285     if (v == DEVICE_C6678_JTAG_ID_VAL)
286         return (TARGET_PWR_EMIF_C6678);
288     /* Return a negative number to indicate no PSC module is associated with NAND */
289     return (-1);
295 /**
296  *  @brief
297  *    The e-fuse mac address is loaded
298  */
299 void deviceLoadDefaultEthAddress (uint8 *maddr)
301     uint32 macA, macB;
303     /* Read the e-fuse mac address */
304     macA = *((uint32 *)0x2620110);
305     macB = *((uint32 *)0x2620114);
307     maddr[0] = (macB >>  8) & 0xff;
308     maddr[1] = (macB >>  0) & 0xff;
309     maddr[2] = (macA >> 24) & 0xff;
310     maddr[3] = (macA >> 16) & 0xff;
311     maddr[4] = (macA >>  8) & 0xff;
312     maddr[5] = (macA >>  0) & 0xff;
316 /**
317  *  @brief
318  *    Compile time queue manager information
319  */
320 #define DEVICE_NUM_RX_CPPIS     1
321 #define DEVICE_NUM_TX_CPPIS     1
322 #define DEVICE_NUM_CPPIS        (DEVICE_NUM_RX_CPPIS + DEVICE_NUM_TX_CPPIS)
324 /* The linking RAM */
325 #pragma DATA_SECTION(qm_linkram_buf, ".linkram")
326 #pragma DATA_ALIGN(qm_linkram_buf, 16)
327 uint8 qm_linkram_buf[DEVICE_NUM_CPPIS * 2 * (sizeof(uint32)/sizeof(uint8))];
330 /* The CPPI RAM */
331 #pragma DATA_SECTION(qm_cppi_buf, ".cppi")
332 #pragma DATA_ALIGN(qm_cppi_buf, 16)
333 uint8 qm_cppi_buf[QM_DESC_SIZE_BYTES * DEVICE_NUM_CPPIS];
336 /* The rx data buffers */
337 #pragma DATA_SECTION(qm_buffer, ".mac_buffer")
338 #pragma DATA_ALIGN(qm_buffer, 16)
339 uint8 qm_buffer[MAX_SIZE_STREAM_BUFFER * DEVICE_NUM_RX_CPPIS];
341 const qmConfig_t qmConfig =  {
342     (UINT32) qm_linkram_buf,
343     sizeof  (qm_cppi_buf),
344     (UINT32) qm_cppi_buf,
346     DEVICE_NUM_CPPIS,
347     DEVICE_QM_FREE_Q
348 };
350 /**
351  *  @brief
352  *      Return the queue manager memory configuration information
353  */
354 void *targetGetQmConfig (void)
356     return ((void *)&qmConfig);
359 /**
360  *  @brief
361  *      Attach a packet buffer to each descriptor and push onto the linked buffer queue
362  */
363 void targetInitQs (void)
365     int32 i;
366     qmHostDesc_t *hd;
368     for (i = 0; i < DEVICE_NUM_RX_CPPIS; i++)  {
370         hd                = hwQmQueuePop (DEVICE_QM_FREE_Q);
371         hd->buffLen       = sizeof (qm_buffer) / DEVICE_NUM_CPPIS;
372         hd->buffPtr       = (UINT32) &(qm_buffer[MAX_SIZE_STREAM_BUFFER * i]);
373         hd->nextBDPtr     = 0;
374         hd->origBufferLen = MAX_SIZE_STREAM_BUFFER;
375         hd->origBuffPtr   = hd->buffPtr;
377         hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
379     }
382     for (i = 0; i < DEVICE_NUM_TX_CPPIS; i++)  {
384         hd                = hwQmQueuePop (DEVICE_QM_FREE_Q);
385         hd->buffLen       = 0;
386         hd->buffPtr       = 0;
387         hd->nextBDPtr     = 0;
388         hd->origBufferLen = 0;
389         hd->origBuffPtr   = 0;
391         hwQmQueuePush (hd, DEVICE_QM_TX_Q, QM_DESC_SIZE_BYTES);
393     }
400 const cpdmaRxCfg_t cpdmaEthRxCfg =  {
402     DEVICE_PA_CDMA_RX_CHAN_CFG_BASE,    /* Base address of PA CPDMA rx config registers */
403     DEVICE_PA_CDMA_RX_NUM_CHANNELS,     /* Number of rx channels */
405     DEVICE_PA_CDMA_RX_FLOW_CFG_BASE,    /* Base address of PA CPDMA rx flow registers */
406     DEVICE_PA_CDMA_RX_NUM_FLOWS,        /* Number of rx flows */
408     0,                                  /* Queue manager for descriptor / buffer for received packets */
409     DEVICE_QM_LNK_BUF_Q,                /* Queue of descriptors /buffers for received packets */
411     0,                                  /* Queue manager for received packets */
412     DEVICE_QM_RCV_Q,                    /* Queue for received packets (overridden by PA)  */
414     DEVICE_RX_CDMA_TIMEOUT_COUNT        /* Teardown maximum loop wait */
415 };
418 /**
419  *  @brief
420  *      Return the cpdma configuration information
421  */
422 void *targetGetCpdmaRxConfig (void)
424     return ((void *)&cpdmaEthRxCfg);
429 const cpdmaTxCfg_t cpdmaEthTxCfg = {
431     DEVICE_PA_CDMA_GLOBAL_CFG_BASE,     /* Base address of global config registers      */
432     DEVICE_PA_CDMA_TX_CHAN_CFG_BASE,    /* Base address of PA CPDMA tx config registers */
433     DEVICE_PA_CDMA_TX_NUM_CHANNELS      /* Number of tx channels */
435 };
438 /**
439  *  @brief
440  *      return the tx cpdma configuration information
441  */
442 void *targetGetCpdmaTxConfig (void)
444     return ((void *)&cpdmaEthTxCfg);
448 /**
449  *  @brief
450  *     Configure the PA
451  */
452 void targetPaConfig (uint8 *macAddr)
454     paConfig_t     paCfg;
455     qmHostDesc_t  *hd;
456     SINT16         ret;
458     /* Filter everything except the desired mac address and the broadcast mac */
459     paCfg.mac0ms = ((uint32)macAddr[0] << 24) | ((uint32)macAddr[1] << 16) | ((uint32)macAddr[2] << 8) | (uint32)(macAddr[3]);
460     paCfg.mac0ls = ((uint32)macAddr[4] << 24) | ((uint32)macAddr[5] << 16);
462     paCfg.mac1ms = 0xffffffff;
463     paCfg.mac1ls = 0xffff0000;
465     paCfg.rxQnum = DEVICE_QM_RCV_Q;
467     /* Form the configuration command in a buffer linked to a descriptor */
468     hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
469     paCfg.cmdBuf = (uint8 *)hd->origBuffPtr;
471     ret = hwPaEnable (&paCfg);
472     if (ret != 0)  {
473         iblStatus.iblFail = ibl_FAIL_CODE_PA;
474         return;
475     }
478     /* Send the command to the PA through the QM */
479     hd->softwareInfo0 = PA_MAGIC_ID;
480     hd->buffLen = 16;
481     QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, 16);
483     /* Set the return Queue */
484     QM_DESC_PINFO_SET_QM    (hd->packetInfo, 0);
485     QM_DESC_PINFO_SET_QUEUE (hd->packetInfo, DEVICE_QM_LNK_BUF_Q);
487     hwQmQueuePush (hd, DEVICE_QM_PA_CFG_Q, QM_DESC_SIZE_BYTES);
492 /**
493  *  @brief
494  *      Chip level SGMII serdes configuration
495  *
496  *  @details
497  *      Both lanes are always setup, regardless of the port value
498  */
499 void targetSgmiiSerdesConfig (int32 port, void *viblSgmii)
501   serdesConfig_t scfg;
502   iblSgmii_t     *sgmii = (iblSgmii_t *)viblSgmii;
504   scfg.cfg      = sgmii->auxConfig;
505   scfg.nLanes   = 2;
506   scfg.rxCfg[0] = scfg.rxCfg[1] = sgmii->rxConfig;
507   scfg.txCfg[0] = scfg.txCfg[1] = sgmii->txConfig;
509   hwSerdesConfig (TARGET_SGMII_SERDES_BASE, &scfg);
511   hwSerdesWaitLock (TARGET_SGMII_SERDES_STATUS_BASE);
516 Int32 targetMacSend (void *vptr_device, Uint8* buffer, int num_bytes) 
518     qmHostDesc_t   *hd;
519     NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
520     int             i;
523     /* Must always setup the descriptor to have the minimum packet length */
524     if (num_bytes < 64)
525         num_bytes = 64;
528     for (i = 0, hd = NULL; hd == NULL; i++, chipDelay32 (1000)) 
529         hd = hwQmQueuePop (DEVICE_QM_TX_Q);
530     
531     if (hd == NULL)
532         return (-1);
534     QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, num_bytes);
536     hd->buffLen       = num_bytes;
537     hd->origBufferLen = num_bytes;
539     hd->buffPtr     = deviceLocalAddrToGlobal((UINT32)buffer);
540     hd->origBuffPtr = deviceLocalAddrToGlobal((UINT32)buffer);
542     
543     /* Return the descriptor back to the transmit queue */
544     QM_DESC_PINFO_SET_QM(hd->packetInfo, 0);
545     QM_DESC_PINFO_SET_QUEUE(hd->packetInfo, DEVICE_QM_TX_Q);
547     hwQmQueuePush (hd, DEVICE_QM_ETH_TX_Q, QM_DESC_SIZE_BYTES);
549     return (0);
554 Int32 targetMacRcv (void *vptr_device, UINT8 *buffer)
556     Int32           pktSizeBytes; 
557     qmHostDesc_t   *hd;
558     NET_DRV_DEVICE *ptr_device = (NET_DRV_DEVICE *)vptr_device;
560     hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
561     if (hd == NULL)
562         return (0);
564     pktSizeBytes = QM_DESC_DESCINFO_GET_PKT_LEN(hd->descInfo);
565     iblMemcpy ((void *)buffer, (void *)hd->buffPtr, pktSizeBytes);
567     hd->buffLen = hd->origBufferLen;
568     hd->buffPtr = hd->origBuffPtr;
570     hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
572     return (pktSizeBytes);
576 void targetFreeQs (void)
578     qmHostDesc_t   *hd;
580     do  {
582         hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
584     } while (hd != NULL);
586     do  {
588         hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
590     } while (hd != NULL);
591     
592     do  {
594         hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
596     } while (hd != NULL);
597     
598     do  {
600         hd = hwQmQueuePop (DEVICE_QM_TX_Q);
602     } while (hd != NULL);
603     
604 }    
606 extern nandCtbl_t nandEmifCtbl;
607 /**
608  *  @brief Return the NAND interface (GPIO, EMIF25 or SPI) used based on the value
609  *         of interface
610  */
611 #ifndef EXCLUDE_NAND_GPIO
612 nandCtbl_t nandGpioCtbl =  {
614     nandHwGpioDriverInit,
615     nandHwGpioDriverReadBytes,
616     nandHwGpioDriverReadPage,
617     nandHwGpioDriverClose
619 };
620 #endif
622 #ifndef EXCLUDE_NAND_EMIF
623 extern Int32 nandHwEmifDriverInit (int32 cs, void *vdevInfo);
624 extern Int32 nandHwEmifDriverReadBytes (Uint32 block, Uint32 page, Uint32 byte, Uint32 nbytes, Uint8 *data);
625 extern Int32 nandHwEmifDriverReadPage (Uint32 block, Uint32 page, Uint8 *data);
626 extern Int32 nandHwEmifDriverClose (void);
628 nandCtbl_t nandEmifCtbl =  {
630     nandHwEmifDriverInit,
631     nandHwEmifDriverReadBytes,
632     nandHwEmifDriverReadPage,
633     nandHwEmifDriverClose
635 };
636 #endif
638 #ifndef EXCLUDE_NAND_SPI
639 nandCtbl_t nandSpiCtbl =  {
642     nandHwSpiDriverInit,
643     nandHwSpiDriverReadBytes,
644     nandHwSpiDriverReadPage,
645     nandHwSpiDriverClose
647 };
648 #endif
650 nandCtbl_t *deviceGetNandCtbl (int32 interface)
652 #ifndef EXCLUDE_NAND_GPIO
654     if (interface == ibl_PMEM_IF_GPIO)
655         return (&nandGpioCtbl);
657 #endif
659 #ifndef EXCLUDE_NAND_SPI
661     if (interface == ibl_PMEM_IF_SPI)
662         return (&nandSpiCtbl);
664 #endif
666 #ifndef EXCLUDE_NAND_EMIF
668     if ((interface >= ibl_PMEM_IF_CHIPSEL_2) && (interface <= ibl_PMEM_IF_CHIPSEL_5))
669         return (&nandEmifCtbl);
671 #endif
673     return (NULL);
678 /**
679  * @brief
680  *      Get the nor call table for the specified nor interface
681  */
683 #ifndef EXCLUDE_NOR_EMIF
684 norCtbl_t norEmifCtbl = {
685     
686     norHwEmifDriverInit,
687     norHwEmifDriverReadBytes,
688     norHwEmifDriverClose
690 };
692 #endif
694 #ifndef EXCLUDE_NOR_SPI
696 norCtbl_t norSpiCtbl = {
697     
698     norHwSpiDriverInit,
699     norHwSpiDriverReadBytes,
700     norHwSpiDriverClose
702 };
704 #endif
706 norCtbl_t *deviceGetNorCtbl (int32 interface)
709 #ifndef EXCLUDE_NOR_SPI
710     
711     if (interface == ibl_PMEM_IF_SPI)
712         return (&norSpiCtbl);
714 #endif
716 #ifndef EXCLUDE_NOR_EMIF
717    
718     if ((interface >= ibl_PMEM_IF_CHIPSEL_2) && (interface <= ibl_PMEM_IF_CHIPSEL_5))
719         return (&norEmifCtbl);
721 #endif
723     return (NULL);
726     
729     
735