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: The Ethernet boot wrapper
40 *********************************************************************************
41 * FILE NAME: ethboot.c
42 *
43 * DESCRIPTION: This file provides the ethernet boot wrapper used by IBL modules
44 *
45 * @file ethboot.c
46 *
47 * @brief
48 * The ethernet boot wrapper
49 *
50 ***********************************************************************************/
51 #include "types.h"
52 #include "ibl.h"
53 #include "iblloc.h"
54 #include "ethboot.h"
55 #include "net.h"
56 #include "cpmacdrv.h"
57 #include "sgmii.h"
58 #include "device.h"
59 #include "mdioapi.h"
60 #include <string.h>
61 #include "net_osal.h"
62 #include "cpsw_api.h"
63 #include "qm_api.h"
64 #include "cpdma_api.h"
66 /**
67 * @brief Remove the possible re-definition of iblEthBoot. iblcfg.h defines this to be a void
68 * statement if there is no ethernet boot support. It must be re-enabled for the compile
69 */
70 #ifdef iblEthBoot
71 #undef iblEthBoot
72 #endif
74 /* Convert an IP address from unsigned char to IPN (uint32) */
75 #define FORM_IPN(x) ( (x[0] << 24) | \
76 (x[1] << 16) | \
77 (x[2] << 8) | \
78 (x[3] << 0) )
80 #define UNFORM_IPN(x,y) (x)[0] = (y) >> 24; \
81 (x)[1] = (y) >> 16; \
82 (x)[2] = (y) >> 8; \
83 (x)[3] = (y) >> 0
85 #define MIN(a,b) ((a) < (b)) ? (a) : (b)
87 static bool have_params;
89 /* Receive a call back when the boot file name is known */
90 void ibl_rec_params (void *params)
91 {
92 NET_DRV_DEVICE *netdev = (NET_DRV_DEVICE *)params;
94 have_params = TRUE;
96 /* Copy the information to the status fields */
97 UNFORM_IPN(iblStatus.ethParams.ipAddr, netdev->ip_address);
98 UNFORM_IPN(iblStatus.ethParams.serverIp, netdev->server_ip);
100 netMemcpy (iblStatus.ethParams.hwAddress, netdev->mac_address, sizeof(iblStatus.ethParams.hwAddress));
101 strncpy (iblStatus.ethParams.fileName, netdev->file_name, sizeof(iblStatus.ethParams.fileName));
103 }
106 void iblEthBoot (Int32 eIdx)
107 {
108 NET_DRV_DEVICE nDevice;
109 Uint32 nl;
110 Uint32 entry;
111 Int32 n;
112 Int32 dataSize;
113 Int32 format;
114 void (*exit)();
115 uint8 buf[16];
116 char *ext;
117 unsigned int i,j;
119 /* Power up the device. No action is taken if the device is already powered up */
120 if (devicePowerPeriph (TARGET_PWR_ETH(ibl.bootModes[eIdx].port)) < 0)
121 return;
123 /* Do any mdio configuration */
124 if (ibl.mdioConfig.nMdioOps > 0)
125 hwMdio (ibl.mdioConfig.nMdioOps, ibl.mdioConfig.mdio,
126 ibl.mdioConfig.mdioClkDiv, ibl.mdioConfig.interDelay);
128 for (j = 0; j < 0x100; j++)
129 for (i = 0; i < 0x1000000; i++);
131 /* SGMII configuration. If sgmii is not present this statement is defined
132 * to void in target.h */
133 for (n = 0; n < ibl_N_ETH_PORTS; n++) {
134 if (ibl.sgmiiConfig[n].configure == TRUE)
135 hwSgmiiConfig (n, &ibl.sgmiiConfig[n]);
136 }
139 #ifdef DEVICE_CPSW
140 /* On chip switch configuration */
141 hwCpswConfig (targetGetSwitchCtl(), targetGetSwitchMaxPktSize());
142 #endif
145 #ifdef DEVICE_QM
146 /* Queue manager configuration */
147 hwQmSetup ((qmConfig_t *)(targetGetQmConfig()));
148 targetInitQs ();
149 #endif
152 #ifdef DEVICE_CPDMA
153 /* Cpdma configuration. */
154 hwCpdmaRxConfig ((cpdmaRxCfg_t *)targetGetCpdmaRxConfig());
155 hwCpdmaTxConfig ((cpdmaTxCfg_t *)targetGetCpdmaTxConfig());
156 #endif
159 #ifdef DEVICE_PA
160 /* Packet accelerator configuration. If PA is not present this statement is defined
161 * to void in target.h */
162 targetPaConfig(ibl.bootModes[eIdx].u.ethBoot.ethInfo.hwAddress);
163 #endif
166 #ifdef DEVICE_SS
167 /* Streaming switch configuration. If not present this statement is defined to void
168 * in target.h. If present this is usually defined to a series of register writes */
169 hwConfigStreamingSwitch();
170 #endif
172 nDevice.port_num = ibl.bootModes[eIdx].port;
174 /* Simple transation to initialize the driver */
175 netMemcpy (nDevice.mac_address, ibl.bootModes[eIdx].u.ethBoot.ethInfo.hwAddress, sizeof(nDevice.mac_address));
177 nl = FORM_IPN(ibl.bootModes[eIdx].u.ethBoot.ethInfo.ipAddr);
178 if (ibl.bootModes[eIdx].u.ethBoot.doBootp == TRUE)
179 nDevice.ip_address = 0;
180 else
181 nDevice.ip_address = htonl(nl);
183 nl = FORM_IPN(ibl.bootModes[eIdx].u.ethBoot.ethInfo.netmask);
184 nDevice.net_mask = htonl(nl);
186 nl = FORM_IPN(ibl.bootModes[eIdx].u.ethBoot.ethInfo.serverIp);
187 nDevice.server_ip = htonl(nl);
188 nDevice.use_bootp_server_ip = ibl.bootModes[eIdx].u.ethBoot.useBootpServerIp;
190 /* Note - the file name structure in nDevice is only 64 bytes, but 128 in ethInfo */
191 netMemcpy (nDevice.file_name, ibl.bootModes[eIdx].u.ethBoot.ethInfo.fileName, sizeof(nDevice.file_name));
192 nDevice.use_bootp_file_name = ibl.bootModes[eIdx].u.ethBoot.useBootpFileName;
195 nDevice.start = cpmac_drv_start;
196 nDevice.stop = cpmac_drv_stop;
197 nDevice.send = cpmac_drv_send;
198 nDevice.receive = cpmac_drv_receive;
201 /* have_params will be set to true in the tftp call back. It must be
202 * set to false before opening the module, since the call back will
203 * be from the open call if bootp is not used */
204 have_params = FALSE;
206 /* Open the network device */
207 if ((*net_boot_module.open) ((void *)&nDevice, ibl_rec_params) != 0)
208 return;
210 /* Wait for the callback with the requested filename */
211 while (have_params == FALSE) {
213 if ((*net_boot_module.peek) ((uint8 *)&nl, sizeof(nl)) < 0) {
215 (*net_boot_module.close)();
216 return;
217 }
218 }
220 format = ibl.bootModes[eIdx].u.ethBoot.bootFormat;
222 /* If the data format was based on the name extension, determine
223 * the boot data format */
224 if (format == ibl_BOOT_FORMAT_NAME) {
226 ext = strrchr (iblStatus.ethParams.fileName, '.');
228 if (ext != NULL) {
230 if (!strcmp (ext, ".bis"))
231 format = ibl_BOOT_FORMAT_BIS;
233 else if (!strcmp (ext, ".ais"))
234 format = ibl_BOOT_FORMAT_BIS;
236 else if (!strcmp (ext, ".out"))
237 format = ibl_BOOT_FORMAT_COFF;
239 else if (!strcmp (ext, ".coff"))
240 format = ibl_BOOT_FORMAT_COFF;
242 else if (!strcmp (ext, ".btbl"))
243 format = ibl_BOOT_FORMAT_BTBL;
245 else if (!strcmp (ext, ".bin"))
246 format = ibl_BOOT_FORMAT_BBLOB;
248 else if (!strcmp (ext, ".blob"))
249 format = ibl_BOOT_FORMAT_BBLOB;
251 }
253 /* Name match failed it didn't change */
254 if (format == ibl_BOOT_FORMAT_NAME) {
256 iblStatus.nameDetectFailCnt += 1;
258 /* Close up the peripheral */
259 (*net_boot_module.close)();
261 return;
262 }
264 }
267 entry = iblBoot (&net_boot_module, format, &ibl.bootModes[eIdx].u.ethBoot.blob);
270 /* Before closing the module read any remaining data. In the coff boot mode the boot may
271 * detect an exit before the entire file has been read. Read the rest of the file
272 * to make the server happy */
274 do {
276 dataSize = (*net_boot_module.query)(); /* Will return -1 when the data is done */
278 if (dataSize > 0) {
280 while (dataSize > 0) {
282 n = MIN(dataSize, sizeof(buf));
283 (*net_boot_module.read)(buf, n);
284 dataSize = dataSize - n;
285 }
287 /* Do not peek if the data size returned in the query was > 0 */
288 } else if (dataSize == 0) {
290 (*net_boot_module.peek)(buf, 1);
291 }
293 } while (dataSize >= 0);
297 /* Close up the peripheral */
298 (*net_boot_module.close)();
301 #ifdef DEVICE_PA
302 hwPaDisable ();
303 #endif
305 #ifdef DEVICE_CPDMA
306 /* Cpdma configuration. */
307 hwCpdmaRxDisable ((cpdmaRxCfg_t *)targetGetCpdmaRxConfig());
308 hwCpdmaTxDisable ((cpdmaTxCfg_t *)targetGetCpdmaTxConfig());
309 #endif
311 #ifdef DEVICE_QM
312 targetFreeQs ();
313 /* Queue manager configuration */
314 hwQmTeardown ();
315 #endif
318 if (entry != 0) {
320 iblStatus.exitAddress = entry;
321 exit = (void (*)())entry;
322 (*exit)();
324 }
327 }