blob: 1c615ce0de7c06cb71b0c740d96dd40045122282 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/******************************************************************************
2
3 Copyright (c) 2014-2015 Lantiq Deutschland GmbH
4 Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
5 Copyright 2016, Intel Corporation.
6
7 For licensing information, see the file 'LICENSE' in the root folder of
8 this software module.
9
10******************************************************************************/
11
12/**
13 \file dxs_dwld.c
14 Implementation of download functions.
15*/
16
17/* ========================================================================== */
18/* Includes */
19/* ========================================================================== */
20#include <stdio.h>
21#include <string.h>
22#include <time.h>
23
24#include "dxs_lib.h"
25#include "dxs_errno.h"
26#include "dxs_error.h"
27#include "dxs_access.h"
28#include "dxs_init.h"
29#include "dxs_mbx.h"
30#include "dxs_pollint.h"
31
32/* ========================================================================== */
33/* Macro definitions */
34/* ========================================================================== */
35#define DXS_PRAM_MAGIC_DXS1 0x44585331
36#define DXS_PRAM_MAGIC_DXS2 0x44585332
37
38#define DXS_ROM_MASK_1_0 1
39#define DXS_ROM_MASK_2_0 2
40
41#define DXS_CRC32_POLY 0xEDB88320
42#define DXS_SWAP32(a) ((((a) >> 24) & 0xFF) | (((a) >> 8) & 0xFF00) | \
43 (((a) & 0xFF00) << 8) | (((a) & 0xFF) << 24))
44
45/* FW download container header struct values */
46#define DXS_FW_TYPE_GLOBAL_V1 0xD0000001 /* type 0xD000, version 0x0001 */
47#define DXS_FW_GLOBAL_MAGIC 0x44585346 /* 'DXSF' character sequence */
48
49/* ========================================================================== */
50/* Type definitions */
51/* ========================================================================== */
52struct pram_footer
53{
54 /* version information */
55 uint32_t fw_vers;
56 /* unix compilation timestamp */
57 uint32_t timestamp;
58 /* 'DXS1' or 'DXS2' */
59 uint32_t magic;
60 /* image size */
61 uint32_t mem;
62 /* CRC32 */
63 uint32_t crc;
64};
65
66/* FW download container header (big endian) */
67struct fw_container_header
68{
69 /* Type and Version identifier */
70 uint32_t nType;
71 /* Length of the payload following this header */
72 uint32_t nLength;
73 /* MAGIC value for endianess checking */
74 uint32_t nMagic;
75 /* Version, each of the 4 bytes represents a digit */
76 uint32_t nVersion;
77 /* Epoch timestamp */
78 uint32_t nTimestamp;
79 /* Offset of the DXS V11 FW within the payload section */
80 uint32_t nDxsV11FwOffset;
81 /* Length of the DXS V11 FW within the payload section */
82 uint32_t nDxsV11FwLength;
83 /* Offset of the DXS1 V12 FW within the payload section */
84 uint32_t nDxs1V12FwOffset;
85 /* Length of the DXS1 V12 FW within the payload section */
86 uint32_t nDxs1V12FwLength;
87 /* Offset of the DXS2 V12 FW within the payload section */
88 uint32_t nDxs2V12FwOffset;
89 /* Length of the DXS2 V12 FW within the payload section */
90 uint32_t nDxs2V12FwLength;
91};
92
93/* ========================================================================== */
94/* Global variables */
95/* ========================================================================== */
96
97/* ========================================================================== */
98/* Function prototypes */
99/* ========================================================================== */
100
101/* ========================================================================== */
102/* Function implementation */
103/* ========================================================================== */
104
105/**
106 Update CRC32 checksum
107
108 \param pData - data buffer
109 \param len - data buffer size in bytes
110 \param prev - previous CRC32 checksum (initial should be 0)
111
112 \return
113 Newly calculated CRC32 value
114*/
115static uint32_t dxs_crc32_le(const void *pData, size_t len, uint32_t prev)
116{
117 uint32_t crc = ~prev;
118 uint8_t *pByte = (uint8_t *)pData;
119 uint32_t j;
120
121 while (len--)
122 {
123 crc ^= (uint32_t) *pByte++;
124 for (j = 0; j < 8; j++)
125 {
126 if (crc & 1)
127 crc = (crc >> 1) ^ DXS_CRC32_POLY;
128 else
129 crc = crc >> 1;
130 }
131 }
132 return ~crc;
133}
134
135/**
136 Verify PRAM image CRC checksum
137
138 \param pData - pointer to image data
139 \param size - size of the image in bytes
140 \param cksum - CRC checksum from image footer
141
142 \return
143 0 - verification failed
144 1 - verification passed
145*/
146static int32_t pram_cksum_verify(uint8_t *pData, uint32_t size, uint32_t ftr_cksum)
147{
148 uint32_t calc_cksum = 0, words32 = size/sizeof(uint32_t);
149
150 while (words32--)
151 {
152 int32_t i = 1;
153 /* make 32-bit word of 4 bytes */
154 uint32_t word = (*pData << 24)|(*(pData+1) << 16)|(*(pData+2) << 8)|(*(pData+3));
155
156 if (!(*((int8_t *)&i)))
157 {
158 /* to use LE CRC32 calculation on BE system -
159 swap bytes in a word */
160 word = DXS_SWAP32(word);
161 }
162
163 calc_cksum = dxs_crc32_le((void *)&word, sizeof(word), calc_cksum);
164 pData += sizeof(word);
165 }
166
167 if (calc_cksum == ftr_cksum)
168 return 1;
169
170 return 0;
171}
172
173/**
174 Read the footer from PRAM patch file
175
176 \param pData - pointer to PRAM image
177 \param size - size of the PRAM image
178 \param f - pointer to footer structure
179
180 \return
181 - none
182*/
183static void pram_footer_read(uint8_t *pData, uint32_t size,
184 struct pram_footer *f)
185{
186 uint32_t offset = size - sizeof(*f), word, i;
187
188 for (i=0; i<(sizeof(*f)/sizeof(uint32_t)); i++)
189 {
190 word = 0;
191
192 word |= (uint32_t) (pData[offset++]) << 24;
193 word |= (uint32_t) (pData[offset++]) << 16;
194 word |= (uint32_t) (pData[offset++]) << 8;
195 word |= (uint32_t) (pData[offset++]);
196
197 *((uint32_t *)f + i) = word;
198 }
199}
200
201/**
202 Function dxs_fw_download
203
204 \param pDev - pointer to DXS device structure
205 \param pPatch - pointer to data buffer
206 \param nBytes - size of the buffer
207
208 \return
209 - DXS_status_t
210*/
211static int32_t dxs_fw_download(DXS_DEVICE_t *pDev,
212 uint8_t *pPatch, uint32_t nBytes)
213{
214 int32_t ret = DXS_statusOk;
215 uint16_t nDxsRegBootCfg = 0,
216 nDxsRegBootInfo = 0,
217 nDxsRegCfg = 0;
218 struct pram_footer ft;
219
220 /* read PRAM patch footer */
221 pram_footer_read(pPatch, nBytes, &ft);
222
223 /* if the image has a footer, verify the checksum */
224 if (ft.magic == DXS_PRAM_MAGIC_DXS1 || ft.magic == DXS_PRAM_MAGIC_DXS2)
225 {
226 /* do not pass the footer for checksum verification */
227 nBytes -= sizeof(struct pram_footer);
228
229 if (!pram_cksum_verify(pPatch, nBytes, ft.crc))
230 {
231 DXS_RETURN(DXS_statusPramPatchCksumError);
232 }
233
234 /* prepare image size for download -
235 minus one word of block delimiter */
236 nBytes -= sizeof(uint32_t);
237 }
238
239 /* stop polling timer */
240 if (pDev->irqNumber == -1)
241 {
242 dxs_polling_timer_stop();
243 }
244
245 /* Set the controller startup configuration in the Boot Configuration
246 Register to boot from HOST_DATA inbox. */
247 nDxsRegBootCfg = DXS_REG_BCFG_ASC_SPI;
248 ret = DXS_RegWrite(pDev, DXS_REG_BCFG, nDxsRegBootCfg);
249 if (ret != DXS_statusOk)
250 {
251 /* errmsg: Setting of boot configuration register failed. */
252 ret = DXS_statusSetBootCfgErr;
253 }
254
255 /* Reset controller to start the boot process from HOST_DATA inbox. */
256 if (ret == DXS_statusOk)
257 {
258 nDxsRegCfg = DXS_REG_CFG_RST_RSTCORE|DXS_REG_CFG_8BIT_EN;
259 ret = DXS_RegWrite(pDev, DXS_REG_CFG, nDxsRegCfg);
260 if (ret != DXS_statusOk)
261 {
262 /* errmsg: Controller reset failed. */
263 ret = DXS_statusCtrlResErr;
264 }
265 }
266
267 /* setup waiting flag */
268 pDev->bWaitingInPatchDwld = 1;
269
270 /* Download firmware patch. */
271 if (ret == DXS_statusOk)
272 {
273 ret = DXS_DwldPatch (pDev, pPatch, nBytes);
274 if (ret != DXS_statusOk)
275 {
276 /* errmsg: Download of the firmware binary failed. */
277 ret = DXS_statusDwldBinErr;
278 }
279 }
280
281 /* Check success of the download by reading the boot info register. */
282 if (ret == DXS_statusOk)
283 {
284 uint8_t loop = 10;
285
286 while (loop > 0)
287 {
288 struct timespec ts = {0, 2000000}; /* 2 ms */
289
290 nanosleep(&ts, NULL);
291
292 /* read the boot state indication */
293 ret = DXS_RegRead(pDev, DXS_REG_BINF, &nDxsRegBootInfo);
294
295 if ((ret == DXS_statusOk) &&
296 ((nDxsRegBootInfo & DXS_REG_BINF_BOOTSTATE_MASK) >= 0x10))
297 {
298 break;
299 }
300
301 loop--;
302 }
303
304 if (loop == 0)
305 {
306 /* errmsg: Firmware download timeout. */
307 ret = DXS_statusFwDwldTimeout;
308 }
309 }
310
311 /* Set bootmode back to ROM in case a recovery is needed. */
312 if (ret == DXS_statusOk)
313 {
314 nDxsRegBootCfg = DXS_REG_BCFG_ASC_ROM;
315 ret = DXS_RegWrite(pDev, DXS_REG_BCFG, nDxsRegBootCfg);
316
317 if (ret != DXS_statusOk)
318 {
319 /* errmsg: Setting of boot configuration register failed. */
320 ret = DXS_statusSetBootCfgErr;
321 }
322 }
323
324 /* restart polling timer */
325 if (pDev->irqNumber == -1)
326 {
327 dxs_polling_timer_start();
328 }
329
330 /* handle special test mode */
331 if (pDev->irqNumber == 255)
332 {
333 sem_post(&pDev->obxSemaphore);
334 }
335
336 /* wait for boot finished event */
337 ret = sem_wait(&pDev->mtxPatchDwld);
338 if (ret)
339 DXS_RETURN(ret);
340
341 /* enable interrupt self-clearing */
342 if (ret == DXS_statusOk)
343 {
344 ret = DXS_RegRead(pDev, DXS_REG_CFG, &nDxsRegCfg);
345 if (ret == DXS_statusOk)
346 {
347 nDxsRegCfg |= DXS_REG_CFG_SC_MD;
348 ret = DXS_RegWrite(pDev, DXS_REG_CFG, nDxsRegCfg);
349 if (ret != DXS_statusOk)
350 {
351 ret = DXS_statusRegWriteError;
352 }
353 }
354 else
355 {
356 ret = DXS_statusRegReadError;
357 }
358 }
359
360 /* read caps and version from the device, mark caps and
361 version structures updated */
362 if (ret == DXS_statusOk)
363 {
364 ret = dxs_caps_vers_update(pDev);
365 }
366
367 /* set default clock failure handling */
368 if (ret == DXS_statusOk)
369 {
370 ret = DXS_CfEsdSwitch(pDev, 1);
371 }
372
373 if (ret == DXS_statusOk)
374 {
375 pDev->flags |= DXS_DEV_PRAM_PATCH_DOWNLOADED;
376 }
377
378 DXS_RETURN(ret);
379}
380
381/**
382 Function DXS_FW_Select
383
384 \param pDev - pointer to DXS device structure
385 \param pPatch - pointer to data buffer (container)
386 \param nBytes - size of the buffer
387
388 \return
389 - DXS_status_t
390*/
391int32_t DXS_FW_Select(DXS_DEVICE_t *pDev, uint8_t *pPatch, uint32_t nBytes)
392{
393 struct fw_container_header header;
394 struct fw_container_header *pHeaderNew = (struct fw_container_header*) pPatch;
395 uint32_t header_length = sizeof(header);
396 int32_t ret;
397#if __BYTE_ORDER == __LITTLE_ENDIAN
398 int32_t i = 0;
399#endif
400
401 if ((pPatch == NULL) || (nBytes == 0) || (nBytes % 4) ||
402 (nBytes < header_length))
403 {
404 DXS_RETURN(DXS_statusInvalidParam);
405 }
406
407 header = *pHeaderNew;
408
409 /* on LE systems - swap bytes in every 32-bit word
410 of the header */
411#if __BYTE_ORDER == __LITTLE_ENDIAN
412 while (i < header_length/sizeof(uint32_t))
413 {
414 uint32_t *pWord = (uint32_t *)&header + i;
415
416 *pWord = DXS_SWAP32(*pWord);
417 i++;
418 }
419#endif
420
421 /* Process the container after verifying the header. */
422 if (header.nType == DXS_FW_TYPE_GLOBAL_V1 &&
423 header.nLength + header_length == nBytes &&
424 header.nMagic == DXS_FW_GLOBAL_MAGIC &&
425 header.nVersion != 0 &&
426 header.nTimestamp != 0 &&
427 header.nLength == header.nDxsV11FwLength +
428 header.nDxs1V12FwLength +
429 header.nDxs2V12FwLength)
430 {
431 uint8_t rom = 0, channels = 0;
432
433 DXS_DevInfoGet(pDev, &rom, &channels);
434
435 switch (rom)
436 {
437
438 case 1:
439 /* ROM 1.x.x */
440 if (header.nDxsV11FwLength > 0)
441 {
442 /* ROM 1.x.x devices are not allowed
443 for some types of DCDC */
444 if (pDev->dcdcType == DXS_DCDC_IFB12CH8)
445 {
446 DXS_RETURN(DXS_statusPramPatchDwldFail);
447 }
448
449 ret = dxs_fw_download(pDev,
450 pPatch + header_length + header.nDxsV11FwOffset,
451 header.nDxsV11FwLength);
452 if (ret != DXS_statusOk)
453 {
454 DXS_RETURN(ret);
455 }
456 }
457 break;
458
459 case 2:
460 /* ROM 2.x.x */
461 switch (channels)
462 {
463 case 1:
464 /* DXS 1-channel device */
465 if (header.nDxs1V12FwLength > 0)
466 {
467 ret = dxs_fw_download(pDev,
468 pPatch + header_length + header.nDxs1V12FwOffset,
469 header.nDxs1V12FwLength);
470 if (ret != DXS_statusOk)
471 {
472 DXS_RETURN(ret);
473 }
474 }
475 break;
476 case 2:
477 /* DXS 2-channel device */
478 if (header.nDxs2V12FwLength > 0)
479 {
480 ret = dxs_fw_download(pDev,
481 pPatch + header_length + header.nDxs2V12FwOffset,
482 header.nDxs2V12FwLength);
483 if (ret != DXS_statusOk)
484 {
485 DXS_RETURN(ret);
486 }
487 }
488 break;
489 default:
490 DXS_RETURN(DXS_statusPramPatchDwldFail);
491 break;
492 }
493 break;
494
495 default:
496 {
497 DXS_RETURN(DXS_statusPramPatchDwldFail);
498 }
499 }
500 }
501 else
502 {
503 /* provided buffer has no header */
504 DXS_RETURN(DXS_statusPramPatchInvalid);
505 }
506
507 return DXS_statusOk;
508}