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: C6678 Device Specific functions
40 ************************************************************************************
41 * FILE NAME: c6678.c
42 *
43 * DESCRIPTION: Implements the device specific functions for the IBL
44 *
45 * @file c6678.c
46 *
47 * @brief
48 * This file implements the device specific functions for the IBL
49 *
50 ************************************************************************************/
51 #include <string.h>
52 #include "platform.h"
53 #include "qm_api.h"
54 #include "cpdma_api.h"
55 #include "pa_api.h"
56 #include "net.h"
57 #include "target.h"
59 extern cregister unsigned int DNUM;
61 /***********************************************************************************
62 * FUNCTION PURPOSE: Provide an approximate delay
63 ***********************************************************************************
64 * DESCRIPTION: A delay in units of CPU cycles is executed
65 ***********************************************************************************/
66 void chipDelay32 (uint32_t del)
67 {
68 volatile unsigned int i;
70 for (i = 0; i < del/8; i++);
72 }
74 void *iblMemcpy (void *s1, const void *s2, uint32_t n)
75 {
76 return (memcpy (s1, s2, n));
78 }
80 /**
81 * @brief Determine if an address is local
82 *
83 * @details
84 * Examines an input address to determine if it is a local address. Using the largest
85 * L2 size on the 6616.
86 */
87 bool address_is_local (uint32_t addr)
88 {
89 /* L2 */
90 if ((addr >= 0x00800000) && (addr < 0x00900000))
91 return (TRUE);
93 /* L1P */
94 if ((addr >= 0x00e00000) && (addr < 0x00e08000))
95 return (TRUE);
97 /* L2D */
98 if ((addr >= 0x00f00000) && (addr < 0x00f08000))
99 return (TRUE);
101 return (FALSE);
103 }
106 /**
107 * @brief Convert a local l1d, l1p or l2 address to a global address
108 *
109 * @details
110 * The global address is formed. If the address is not local then
111 * the input address is returned
112 */
113 uint32_t deviceLocalAddrToGlobal (uint32_t addr)
114 {
116 if (address_is_local (addr))
117 addr = (1 << 28) | (DNUM << 24) | addr;
119 return (addr);
121 }
125 /**
126 * @brief
127 * The e-fuse mac address is loaded
128 */
129 void deviceLoadDefaultEthAddress (uint8_t *maddr)
130 {
131 uint32_t macA, macB;
133 /* Read the e-fuse mac address */
134 macA = *((uint32_t *)0x2620110);
135 macB = *((uint32_t *)0x2620114);
137 maddr[0] = (macB >> 8) & 0xff;
138 maddr[1] = (macB >> 0) & 0xff;
139 maddr[2] = (macA >> 24) & 0xff;
140 maddr[3] = (macA >> 16) & 0xff;
141 maddr[4] = (macA >> 8) & 0xff;
142 maddr[5] = (macA >> 0) & 0xff;
143 }
146 /**
147 * @brief
148 * Compile time queue manager information
149 */
150 #define DEVICE_NUM_RX_CPPIS 1
151 #define DEVICE_NUM_TX_CPPIS 1
152 #define DEVICE_NUM_CPPIS (DEVICE_NUM_RX_CPPIS + DEVICE_NUM_TX_CPPIS)
154 /* The linking RAM */
155 #pragma DATA_SECTION(qm_linkram_buf, ".linkram")
156 #pragma DATA_ALIGN(qm_linkram_buf, 16)
157 uint8_t qm_linkram_buf[DEVICE_NUM_CPPIS * 2 * (sizeof(uint32_t)/sizeof(uint8_t))];
160 /* The CPPI RAM */
161 #pragma DATA_SECTION(qm_cppi_buf, ".cppi")
162 #pragma DATA_ALIGN(qm_cppi_buf, 16)
163 uint8_t qm_cppi_buf[QM_DESC_SIZE_BYTES * DEVICE_NUM_CPPIS];
165 /* The rx data buffers */
166 #pragma DATA_SECTION(qm_buffer, ".mac_buffer")
167 #pragma DATA_ALIGN(qm_buffer, 16)
168 uint8_t qm_buffer[MAX_SIZE_STREAM_BUFFER * DEVICE_NUM_RX_CPPIS];
170 const qmConfig_t qmConfig = {
171 (uint32_t) qm_linkram_buf,
172 sizeof (qm_cppi_buf),
173 (uint32_t) qm_cppi_buf,
175 DEVICE_NUM_CPPIS,
176 DEVICE_QM_FREE_Q
177 };
179 /**
180 * @brief
181 * Return the queue manager memory configuration information
182 */
183 void *targetGetQmConfig (void)
184 {
185 return ((void *)&qmConfig);
186 }
188 /**
189 * @brief
190 * Attach a packet buffer to each descriptor and push onto the linked buffer queue
191 */
192 void targetInitQs (void)
193 {
194 int32_t i;
195 qmHostDesc_t *hd, *hd_old;
197 for (i = 0; i < DEVICE_NUM_RX_CPPIS; i++) {
199 hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
200 hd_old = hd;
201 hd->buffLen = sizeof (qm_buffer) / DEVICE_NUM_CPPIS;
202 hd->buffPtr = (uint32_t) &(qm_buffer[MAX_SIZE_STREAM_BUFFER * i]);
203 hd->nextBDPtr = 0;
204 hd->origBufferLen = MAX_SIZE_STREAM_BUFFER;
205 hd->origBuffPtr = hd->buffPtr;
207 hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
209 }
212 for (i = 0; i < DEVICE_NUM_TX_CPPIS; i++) {
214 hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
215 if (hd == hd_old)
216 hd += 0x40;
217 hd->buffLen = 0;
218 hd->buffPtr = 0;
219 hd->nextBDPtr = 0;
220 hd->origBufferLen = 0;
221 hd->origBuffPtr = 0;
223 hwQmQueuePush (hd, DEVICE_QM_TX_Q, QM_DESC_SIZE_BYTES);
225 }
228 }
232 const cpdmaRxCfg_t cpdmaEthRxCfg = {
234 DEVICE_PA_CDMA_RX_CHAN_CFG_BASE, /* Base address of PA CPDMA rx config registers */
235 DEVICE_PA_CDMA_RX_NUM_CHANNELS, /* Number of rx channels */
237 DEVICE_PA_CDMA_RX_FLOW_CFG_BASE, /* Base address of PA CPDMA rx flow registers */
238 DEVICE_PA_CDMA_RX_NUM_FLOWS, /* Number of rx flows */
240 0, /* Queue manager for descriptor / buffer for received packets */
241 DEVICE_QM_LNK_BUF_Q, /* Queue of descriptors /buffers for received packets */
243 0, /* Queue manager for received packets */
244 DEVICE_QM_RCV_Q, /* Queue for received packets (overridden by PA) */
246 DEVICE_RX_CDMA_TIMEOUT_COUNT /* Teardown maximum loop wait */
247 };
250 /**
251 * @brief
252 * Return the cpdma configuration information
253 */
254 void *targetGetCpdmaRxConfig (void)
255 {
256 return ((void *)&cpdmaEthRxCfg);
258 }
261 const cpdmaTxCfg_t cpdmaEthTxCfg = {
263 DEVICE_PA_CDMA_GLOBAL_CFG_BASE, /* Base address of global config registers */
264 DEVICE_PA_CDMA_TX_CHAN_CFG_BASE, /* Base address of PA CPDMA tx config registers */
265 DEVICE_PA_CDMA_TX_NUM_CHANNELS /* Number of tx channels */
267 };
270 /**
271 * @brief
272 * return the tx cpdma configuration information
273 */
274 void *targetGetCpdmaTxConfig (void)
275 {
276 return ((void *)&cpdmaEthTxCfg);
278 }
280 /**
281 * @brief
282 * Configure the PA
283 */
284 void targetPaConfig (uint8_t *macAddr)
285 {
286 paConfig_t paCfg;
287 qmHostDesc_t *hd;
288 int16_t ret;
290 /* Filter everything except the desired mac address and the broadcast mac */
291 paCfg.mac0ms = ((uint32_t)macAddr[0] << 24) | ((uint32_t)macAddr[1] << 16) | ((uint32_t)macAddr[2] << 8) | (uint32_t)(macAddr[3]);
292 paCfg.mac0ls = ((uint32_t)macAddr[4] << 24) | ((uint32_t)macAddr[5] << 16);
294 paCfg.mac1ms = 0xffffffff;
295 paCfg.mac1ls = 0xffff0000;
297 paCfg.rxQnum = DEVICE_QM_RCV_Q;
299 /* Form the configuration command in a buffer linked to a descriptor */
300 hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
301 paCfg.cmdBuf = (uint8_t *)hd->origBuffPtr;
303 ret = hwPaEnable (&paCfg);
304 if (ret != 0) {
305 return;
306 }
309 /* Send the command to the PA through the QM */
310 hd->softwareInfo0 = PA_MAGIC_ID;
311 hd->buffLen = 16;
312 QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, 16);
314 /* Set the return Queue */
315 QM_DESC_PINFO_SET_QM (hd->packetInfo, 0);
316 QM_DESC_PINFO_SET_QUEUE (hd->packetInfo, DEVICE_QM_LNK_BUF_Q);
318 hwQmQueuePush (hd, DEVICE_QM_PA_CFG_Q, QM_DESC_SIZE_BYTES);
321 }
323 int32_t targetMacSend (void *vptr_device, uint8_t* buffer, int32_t num_bytes)
324 {
325 qmHostDesc_t *hd;
326 int32_t i;
329 /* Must always setup the descriptor to have the minimum packet length */
330 if (num_bytes < 64)
331 num_bytes = 64;
334 for (i = 0, hd = NULL; hd == NULL; i++, chipDelay32 (1000))
335 hd = hwQmQueuePop (DEVICE_QM_TX_Q);
337 if (hd == NULL)
338 return (-1);
340 QM_DESC_DESCINFO_SET_PKT_LEN(hd->descInfo, num_bytes);
342 hd->buffLen = num_bytes;
343 hd->origBufferLen = num_bytes;
345 hd->buffPtr = deviceLocalAddrToGlobal((uint32_t)buffer);
346 hd->origBuffPtr = deviceLocalAddrToGlobal((uint32_t)buffer);
349 /* Return the descriptor back to the transmit queue */
350 QM_DESC_PINFO_SET_QM(hd->packetInfo, 0);
351 QM_DESC_PINFO_SET_QUEUE(hd->packetInfo, DEVICE_QM_TX_Q);
352 /* Force the packet to EMAC port 0 if loopback is enabled */
353 hd->packetInfo |= (1<<16);
355 hwQmQueuePush (hd, DEVICE_QM_ETH_TX_Q, QM_DESC_SIZE_BYTES);
357 return (0);
359 }
362 int32_t targetMacRcv (void *vptr_device, uint8_t *buffer)
363 {
364 int32_t pktSizeBytes;
365 qmHostDesc_t *hd;
367 hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
368 if (hd == NULL)
369 return (0);
371 pktSizeBytes = QM_DESC_DESCINFO_GET_PKT_LEN(hd->descInfo);
372 iblMemcpy ((void *)buffer, (void *)hd->buffPtr, pktSizeBytes);
374 hd->buffLen = hd->origBufferLen;
375 hd->buffPtr = hd->origBuffPtr;
377 hwQmQueuePush (hd, DEVICE_QM_LNK_BUF_Q, QM_DESC_SIZE_BYTES);
379 return (pktSizeBytes);
381 }
383 void targetFreeQs (void)
384 {
385 qmHostDesc_t *hd;
387 do {
389 hd = hwQmQueuePop (DEVICE_QM_FREE_Q);
391 } while (hd != NULL);
393 do {
395 hd = hwQmQueuePop (DEVICE_QM_LNK_BUF_Q);
397 } while (hd != NULL);
399 do {
401 hd = hwQmQueuePop (DEVICE_QM_RCV_Q);
403 } while (hd != NULL);
405 do {
407 hd = hwQmQueuePop (DEVICE_QM_TX_Q);
409 } while (hd != NULL);
411 }