Merge branch 'newI2cMap' into tmp-mike2
[keystone-rtos/ibl.git] / src / ethboot / ethboot.c
1 /*********************************************************************************
2  * FILE PURPOSE: The Ethernet boot wrapper
3  *********************************************************************************
4  * FILE NAME: ethboot.c
5  *
6  * DESCRIPTION: This file provides the ethernet boot wrapper used by IBL modules
7  *
8  * @file ethboot.c
9  *
10  * @brief
11  *   The ethernet boot wrapper
12  *
13  ***********************************************************************************/
14 #include "types.h"
15 #include "ibl.h"
16 #include "iblloc.h"
17 #include "ethboot.h"
18 #include "net.h"
19 #include "cpmacdrv.h"
20 #include "sgmii.h"
21 #include "device.h"
22 #include "mdioapi.h"
23 #include <string.h>
24 #include "net_osal.h"
26 /**
27  *  @brief Remove the possible re-definition of iblEthBoot. iblcfg.h defines this to be a void
28  *         statement if there is no ethernet boot support. It must be re-enabled for the compile
29  */
30 #ifdef iblEthBoot
31  #undef iblEthBoot
32 #endif
34 /* Convert an IP address from unsigned char to IPN (uint32) */
35 #define FORM_IPN(x)     (  (x[0] << 24) | \
36                            (x[1] << 16) | \
37                            (x[2] <<  8) | \
38                            (x[3] <<  0) )
40 #define UNFORM_IPN(x,y)  (x)[0] = (y) >> 24;  \
41                          (x)[1] = (y) >> 16;  \
42                          (x)[2] = (y) >>  8;  \
43                          (x)[3] = (y) >>  0
45 #define MIN(a,b)         ((a) < (b)) ? (a) : (b)
47 static bool have_params;
49 /* Receive a call back when the boot file name is known */
50 void ibl_rec_params (void *params)
51 {
52     NET_DRV_DEVICE *netdev = (NET_DRV_DEVICE *)params;
54     have_params = TRUE;
56     /* Copy the information to the status fields */
57     UNFORM_IPN(iblStatus.ethParams.ipAddr, netdev->ip_address);
58     UNFORM_IPN(iblStatus.ethParams.serverIp, netdev->server_ip);
60     netMemcpy (iblStatus.ethParams.hwAddress, netdev->mac_address, sizeof(iblStatus.ethParams.hwAddress));
61     strncpy (iblStatus.ethParams.fileName, netdev->file_name, sizeof(iblStatus.ethParams.fileName));
63 }
66 void iblEthBoot (Int32 eIdx)
67 {
68     NET_DRV_DEVICE nDevice;
69     Uint32  nl;
70     Uint32  entry;
71     Int32   n;
72     Int32   dataSize;
73     Int32   format;
74     void    (*exit)();
75     uint8   buf[16];
76     char    *ext;
80     /* Power up the device. No action is taken if the device is already powered up */
81     if (devicePowerPeriph (TARGET_PWR_ETH(ibl.ethConfig[eIdx].port)) < 0)
82         return;
84     /* Do any mdio configuration */
85     if (ibl.mdioConfig.nMdioOps > 0)
86         hwMdio (ibl.mdioConfig.nMdioOps, ibl.mdioConfig.mdio, 
87                 ibl.mdioConfig.mdioClkDiv, ibl.mdioConfig.interDelay);
90     /* SGMII configuration. If sgmii is not present this statement is defined
91      * to void in target.h */
92     hwSgmiiConfig (ibl.ethConfig[eIdx].port, &ibl.sgmiiConfig[eIdx]);
95     nDevice.port_num = ibl.ethConfig[eIdx].port;
97     /* Simple transation to initialize the driver */
98     netMemcpy (nDevice.mac_address, ibl.ethConfig[eIdx].ethInfo.hwAddress, sizeof(nDevice.mac_address));
100     nl = FORM_IPN(ibl.ethConfig[eIdx].ethInfo.ipAddr);
101     if (ibl.ethConfig[eIdx].doBootp == TRUE)
102         nDevice.ip_address = 0;
103     else
104         nDevice.ip_address = htonl(nl);
106     nl = FORM_IPN(ibl.ethConfig[eIdx].ethInfo.netmask);
107     nDevice.net_mask  = htonl(nl);
109     nl = FORM_IPN(ibl.ethConfig[eIdx].ethInfo.serverIp);
110     nDevice.server_ip           = htonl(nl);
111     nDevice.use_bootp_server_ip = ibl.ethConfig[eIdx].useBootpServerIp;
113     /* Note - the file name structure in nDevice is only 64 bytes, but 128 in ethInfo */
114     netMemcpy (nDevice.file_name, ibl.ethConfig[eIdx].ethInfo.fileName, sizeof(nDevice.file_name));
115     nDevice.use_bootp_file_name = ibl.ethConfig[eIdx].useBootpFileName;
118     nDevice.start    = cpmac_drv_start;
119     nDevice.stop     = cpmac_drv_stop;
120     nDevice.send     = cpmac_drv_send;
121     nDevice.receive  = cpmac_drv_receive;
124     /* have_params will be set to true in the tftp call back. It must be
125      * set to false before opening the module, since the call back will
126      * be from the open call if bootp is not used */
127     have_params = FALSE;
129     /* Open the network device */
130     if ((*net_boot_module.open) ((void *)&nDevice, ibl_rec_params) != 0)
131         return;
133     /* Wait for the callback with the requested filename */
134     while (have_params == FALSE)  {
136        if ((*net_boot_module.peek) ((uint8 *)&nl, sizeof(nl)) < 0)  {
138             (*net_boot_module.close)();
139             return;
140         }
141     }
143     format = ibl.ethConfig[eIdx].bootFormat;
145     /* If the data format was based on the name extension, determine
146      * the boot data format */
147     if (format == ibl_BOOT_FORMAT_NAME)  {
149         ext = strrchr (iblStatus.ethParams.fileName, '.');
151         if (ext != NULL)  {
153             if (!strcmp (ext, ".bis"))
154                 format = ibl_BOOT_FORMAT_BIS;
156             else if (!strcmp (ext, ".ais"))
157                 format = ibl_BOOT_FORMAT_BIS;
159             else if (!strcmp (ext, ".out"))
160                 format = ibl_BOOT_FORMAT_COFF;
162             else if (!strcmp (ext, ".coff"))
163                 format = ibl_BOOT_FORMAT_COFF;
165             else if (!strcmp (ext, ".btbl"))
166                 format = ibl_BOOT_FORMAT_BTBL;
167             
168             else if (!strcmp (ext, ".bin"))
169                 format = ibl_BOOT_FORMAT_BBLOB;
171             else if (!strcmp (ext, ".blob"))
172                 format = ibl_BOOT_FORMAT_BBLOB;
174         }
176         /* Name match failed it didn't change */
177         if (format == ibl_BOOT_FORMAT_NAME)  {
179             iblStatus.nameDetectFailCnt += 1;
181             /* Close up the peripheral */
182             (*net_boot_module.close)();
184             return;
185         }
187     }
190     entry = iblBoot (&net_boot_module, format, &ibl.ethConfig[eIdx].blob);
193     /* Before closing the module read any remaining data. In the coff boot mode the boot may
194      * detect an exit before the entire file has been read. Read the rest of the file
195      * to make the server happy */
197     do  {
199         dataSize = (*net_boot_module.query)();  /* Will return -1 when the data is done */
201         if (dataSize > 0)  {
203             while (dataSize > 0)  {
204             
205                 n = MIN(dataSize, sizeof(buf));
206                 (*net_boot_module.read)(buf, n);
207                 dataSize = dataSize - n;
208             }
210         /* Do not peek if the data size returned in the query was > 0 */
211         }  else if (dataSize == 0) {
213             (*net_boot_module.peek)(buf, 1);
214         }
216     } while (dataSize >= 0);
220     /* Close up the peripheral */
221     (*net_boot_module.close)();
223     if (entry != 0)  {
225         iblStatus.exitAddress = entry;
226         exit = (void (*)())entry;
227         (*exit)();
229     }