]> git.sur5r.net Git - openocd/blob - src/flash/nor/lpcspifi.c
63901493c0593386540d368fa82993cda1ef3544
[openocd] / src / flash / nor / lpcspifi.c
1 /***************************************************************************
2  *   Copyright (C) 2012 by George Harris                                   *
3  *   george@luminairecoffee.com                                            *
4  *                                                                                                                                                 *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
19  ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "imp.h"
26 #include "spi.h"
27 #include <jtag/jtag.h>
28 #include <helper/time_support.h>
29 #include <target/algorithm.h>
30 #include <target/armv7m.h>
31
32 /* Offsets from ssp_base into config & data registers */
33 #define SSP_CR0         (0x00)  /* Control register 0 */
34 #define SSP_CR1         (0x04)  /* Control register 1 */
35 #define SSP_DATA        (0x08)  /* Data register (TX and RX) */
36 #define SSP_SR          (0x0C)  /* Status register */
37 #define SSP_CPSR        (0x10)  /* Clock prescale register */
38
39 /* Status register fields */
40 #define SSP_BSY         (0x00000010)
41
42 /* Timeout in ms */
43 #define SSP_CMD_TIMEOUT   (100)
44 #define SSP_PROBE_TIMEOUT (100)
45 #define SSP_MAX_TIMEOUT  (3000)
46
47 /* Size of the stack to alloc in the working area for the execution of
48  * the ROM spifi_init() function */
49 #define SPIFI_INIT_STACK_SIZE  512
50
51 struct lpcspifi_flash_bank {
52         int probed;
53         uint32_t ssp_base;
54         uint32_t io_base;
55         uint32_t ioconfig_base;
56         uint32_t bank_num;
57         uint32_t max_spi_clock_mhz;
58         const struct flash_device *dev;
59 };
60
61 struct lpcspifi_target {
62         char *name;
63         uint32_t tap_idcode;
64         uint32_t spifi_base;
65         uint32_t ssp_base;
66         uint32_t io_base;
67         uint32_t ioconfig_base; /* base address for the port word pin registers */
68 };
69
70 static const struct lpcspifi_target target_devices[] = {
71         /* name,          tap_idcode, spifi_base, ssp_base,   io_base,    ioconfig_base */
72         { "LPC43xx/18xx", 0x4ba00477, 0x14000000, 0x40083000, 0x400F4000, 0x40086000 },
73         { NULL,           0,          0,          0,          0,          0 }
74 };
75
76 /* flash_bank lpcspifi <base> <size> <chip_width> <bus_width> <target>
77  */
78 FLASH_BANK_COMMAND_HANDLER(lpcspifi_flash_bank_command)
79 {
80         struct lpcspifi_flash_bank *lpcspifi_info;
81
82         if (CMD_ARGC < 6)
83                 return ERROR_COMMAND_SYNTAX_ERROR;
84
85         lpcspifi_info = malloc(sizeof(struct lpcspifi_flash_bank));
86         if (lpcspifi_info == NULL) {
87                 LOG_ERROR("not enough memory");
88                 return ERROR_FAIL;
89         }
90
91         bank->driver_priv = lpcspifi_info;
92         lpcspifi_info->probed = 0;
93
94         return ERROR_OK;
95 }
96
97 static inline int ioconfig_write_reg(struct target *target, uint32_t ioconfig_base, uint32_t offset, uint32_t value)
98 {
99         return target_write_u32(target, ioconfig_base + offset, value);
100 }
101
102 static inline int ssp_write_reg(struct target *target, uint32_t ssp_base, uint32_t offset, uint32_t value)
103 {
104         return target_write_u32(target, ssp_base + offset, value);
105 }
106
107 static inline int io_write_reg(struct target *target, uint32_t io_base, uint32_t offset, uint32_t value)
108 {
109         return target_write_u32(target, io_base + offset, value);
110 }
111
112 static inline int ssp_read_reg(struct target *target, uint32_t ssp_base, uint32_t offset, uint32_t *value)
113 {
114         return target_read_u32(target, ssp_base + offset, value);
115 }
116
117 static int ssp_setcs(struct target *target, uint32_t io_base, unsigned int value)
118 {
119         return io_write_reg(target, io_base, 0x12ac, value ? 0xffffffff : 0x00000000);
120 }
121
122 /* Poll the SSP busy flag. When this comes back as 0, the transfer is complete
123  * and the controller is idle. */
124 static int poll_ssp_busy(struct target *target, uint32_t ssp_base, int timeout)
125 {
126         long long endtime;
127         uint32_t value;
128         int retval;
129
130         retval = ssp_read_reg(target, ssp_base, SSP_SR, &value);
131         if ((retval == ERROR_OK) && (value & SSP_BSY) == 0)
132                 return ERROR_OK;
133         else if (retval != ERROR_OK)
134                 return retval;
135
136         endtime = timeval_ms() + timeout;
137         do {
138                 alive_sleep(1);
139                 retval = ssp_read_reg(target, ssp_base, SSP_SR, &value);
140                 if ((retval == ERROR_OK) && (value & SSP_BSY) == 0)
141                         return ERROR_OK;
142                 else if (retval != ERROR_OK)
143                         return retval;
144         } while (timeval_ms() < endtime);
145
146         LOG_ERROR("Timeout while polling BSY");
147         return ERROR_FLASH_OPERATION_FAILED;
148 }
149
150 /* Un-initialize the ssp module and initialize the SPIFI module */
151 static int lpcspifi_set_hw_mode(struct flash_bank *bank)
152 {
153         struct target *target = bank->target;
154         struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
155         uint32_t ssp_base = lpcspifi_info->ssp_base;
156         struct armv7m_algorithm armv7m_info;
157         struct working_area *spifi_init_algorithm;
158         struct reg_param reg_params[2];
159         int retval = ERROR_OK;
160
161         LOG_DEBUG("Uninitializing LPC43xx SSP");
162         /* Turn off the SSP module */
163         retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000000);
164         if (retval != ERROR_OK)
165                 return retval;
166
167         /* see contrib/loaders/flash/lpcspifi_init.S for src */
168         static const uint8_t spifi_init_code[] = {
169                 0x4f, 0xea, 0x00, 0x08, 0xa1, 0xb0, 0x00, 0xaf,
170                 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03,
171                 0x4f, 0xf0, 0xf3, 0x02, 0xc3, 0xf8, 0x8c, 0x21,
172                 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03,
173                 0x4f, 0xf4, 0xc0, 0x42, 0xc4, 0xf2, 0x08, 0x02,
174                 0x4f, 0xf4, 0xc0, 0x41, 0xc4, 0xf2, 0x08, 0x01,
175                 0x4f, 0xf4, 0xc0, 0x40, 0xc4, 0xf2, 0x08, 0x00,
176                 0x4f, 0xf0, 0xd3, 0x04, 0xc0, 0xf8, 0x9c, 0x41,
177                 0x20, 0x46, 0xc1, 0xf8, 0x98, 0x01, 0x01, 0x46,
178                 0xc2, 0xf8, 0x94, 0x11, 0xc3, 0xf8, 0x90, 0x11,
179                 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03,
180                 0x4f, 0xf0, 0x13, 0x02, 0xc3, 0xf8, 0xa0, 0x21,
181                 0x40, 0xf2, 0x18, 0x13, 0xc1, 0xf2, 0x40, 0x03,
182                 0x1b, 0x68, 0x1c, 0x68, 0x40, 0xf2, 0xb4, 0x30,
183                 0xc1, 0xf2, 0x00, 0x00, 0x4f, 0xf0, 0x03, 0x01,
184                 0x4f, 0xf0, 0xc0, 0x02, 0x4f, 0xea, 0x08, 0x03,
185                 0xa0, 0x47, 0x00, 0xf0, 0x00, 0xb8, 0x00, 0xbe
186         };
187
188         armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
189         armv7m_info.core_mode = ARM_MODE_THREAD;
190
191
192         LOG_DEBUG("Allocating working area for SPIFI init algorithm");
193         /* Get memory for spifi initialization algorithm */
194         retval = target_alloc_working_area(target, sizeof(spifi_init_code)
195                 + SPIFI_INIT_STACK_SIZE, &spifi_init_algorithm);
196         if (retval != ERROR_OK) {
197                 LOG_ERROR("Insufficient working area to initialize SPIFI "\
198                         "module. You must allocate at least %zdB of working "\
199                         "area in order to use this driver.",
200                         sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE
201                 );
202
203                 return retval;
204         }
205
206         LOG_DEBUG("Writing algorithm to working area at 0x%08" PRIx32,
207                 spifi_init_algorithm->address);
208         /* Write algorithm to working area */
209         retval = target_write_buffer(target,
210                 spifi_init_algorithm->address,
211                 sizeof(spifi_init_code),
212                 spifi_init_code
213         );
214
215         if (retval != ERROR_OK) {
216                 target_free_working_area(target, spifi_init_algorithm);
217                 return retval;
218         }
219
220         init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);            /* spifi clk speed */
221         /* the spifi_init() rom API makes use of the stack */
222         init_reg_param(&reg_params[1], "sp", 32, PARAM_OUT);
223
224         /* For now, the algorithm will set up the SPIFI module
225          * @ the IRC clock speed. In the future, it could be made
226          * a bit smarter to use other clock sources if the user has
227          * already configured them in order to speed up memory-
228          * mapped reads. */
229         buf_set_u32(reg_params[0].value, 0, 32, 12);
230         /* valid stack pointer */
231         buf_set_u32(reg_params[1].value, 0, 32, (spifi_init_algorithm->address +
232                 sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE) & ~7UL);
233
234         /* Run the algorithm */
235         LOG_DEBUG("Running SPIFI init algorithm");
236         retval = target_run_algorithm(target, 0 , NULL, 2, reg_params,
237                 spifi_init_algorithm->address,
238                 spifi_init_algorithm->address + sizeof(spifi_init_code) - 2,
239                 1000, &armv7m_info);
240
241         if (retval != ERROR_OK)
242                 LOG_ERROR("Error executing SPIFI init algorithm");
243
244         target_free_working_area(target, spifi_init_algorithm);
245
246         destroy_reg_param(&reg_params[0]);
247         destroy_reg_param(&reg_params[1]);
248
249         return retval;
250 }
251
252 /* Initialize the ssp module */
253 static int lpcspifi_set_sw_mode(struct flash_bank *bank)
254 {
255         struct target *target = bank->target;
256         struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
257         uint32_t ssp_base = lpcspifi_info->ssp_base;
258         uint32_t io_base = lpcspifi_info->io_base;
259         uint32_t ioconfig_base = lpcspifi_info->ioconfig_base;
260         int retval = ERROR_OK;
261
262         /* Re-initialize SPIFI. There are a couple of errata on this, so this makes
263         sure that nothing's in an unhappy state. */
264         retval = lpcspifi_set_hw_mode(bank);
265
266         /* If we couldn't initialize hardware mode, don't even bother continuing */
267         if (retval != ERROR_OK)
268                 return retval;
269
270         /* Initialize the pins */
271         retval = ioconfig_write_reg(target, ioconfig_base, 0x194, 0x00000040);
272         if (retval == ERROR_OK)
273                 retval = ioconfig_write_reg(target, ioconfig_base, 0x1a0, 0x00000044);
274         if (retval == ERROR_OK)
275                 retval = ioconfig_write_reg(target, ioconfig_base, 0x190, 0x00000040);
276         if (retval == ERROR_OK)
277                 retval = ioconfig_write_reg(target, ioconfig_base, 0x19c, 0x000000ed);
278         if (retval == ERROR_OK)
279                 retval = ioconfig_write_reg(target, ioconfig_base, 0x198, 0x000000ed);
280         if (retval == ERROR_OK)
281                 retval = ioconfig_write_reg(target, ioconfig_base, 0x18c, 0x000000ea);
282
283         /* Set CS high & as an output */
284         if (retval == ERROR_OK)
285                 retval = io_write_reg(target, io_base, 0x12ac, 0xffffffff);
286         if (retval == ERROR_OK)
287                 retval = io_write_reg(target, io_base, 0x2014, 0x00000800);
288
289         /* Initialize the module */
290         if (retval == ERROR_OK)
291                 retval = ssp_write_reg(target, ssp_base, SSP_CR0, 0x00000007);
292         if (retval == ERROR_OK)
293                 retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000000);
294         if (retval == ERROR_OK)
295                 retval = ssp_write_reg(target, ssp_base, SSP_CPSR, 0x00000008);
296         if (retval == ERROR_OK)
297                 retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000002);
298
299         /* If something didn't work out, attempt to return SPIFI to HW mode */
300         if (retval != ERROR_OK)
301                 lpcspifi_set_hw_mode(bank);
302
303         return retval;
304 }
305
306 /* Read the status register of the external SPI flash chip. */
307 static int read_status_reg(struct flash_bank *bank, uint32_t *status)
308 {
309         struct target *target = bank->target;
310         struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
311         uint32_t ssp_base = lpcspifi_info->ssp_base;
312         uint32_t io_base = lpcspifi_info->io_base;
313         uint32_t value;
314         int retval = ERROR_OK;
315
316         retval = ssp_setcs(target, io_base, 0);
317         if (retval == ERROR_OK)
318                 retval = ssp_write_reg(target, ssp_base, SSP_DATA, SPIFLASH_READ_STATUS);
319         if (retval == ERROR_OK)
320                 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
321         if (retval == ERROR_OK)
322                 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
323         /* Dummy write to clock in the register */
324         if (retval == ERROR_OK)
325                 retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00);
326         if (retval == ERROR_OK)
327                 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
328         if (retval == ERROR_OK)
329                 retval = ssp_setcs(target, io_base, 1);
330
331         if (retval == ERROR_OK)
332                 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
333         if (retval == ERROR_OK)
334                 *status = value;
335
336         return retval;
337 }
338
339 /* check for BSY bit in flash status register */
340 /* timeout in ms */
341 static int wait_till_ready(struct flash_bank *bank, int timeout)
342 {
343         uint32_t status;
344         int retval;
345         long long endtime;
346
347         endtime = timeval_ms() + timeout;
348         do {
349                 /* read flash status register */
350                 retval = read_status_reg(bank, &status);
351                 if (retval != ERROR_OK)
352                         return retval;
353
354                 if ((status & SPIFLASH_BSY_BIT) == 0)
355                         return ERROR_OK;
356                 alive_sleep(1);
357         } while (timeval_ms() < endtime);
358
359         LOG_ERROR("timeout waiting for flash to finish write/erase operation");
360         return ERROR_FAIL;
361 }
362
363 /* Send "write enable" command to SPI flash chip. */
364 static int lpcspifi_write_enable(struct flash_bank *bank)
365 {
366         struct target *target = bank->target;
367         struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
368         uint32_t ssp_base = lpcspifi_info->ssp_base;
369         uint32_t io_base = lpcspifi_info->io_base;
370         uint32_t status, value;
371         int retval = ERROR_OK;
372
373         retval = ssp_setcs(target, io_base, 0);
374         if (retval == ERROR_OK)
375                 retval = ssp_write_reg(target, ssp_base, SSP_DATA, SPIFLASH_WRITE_ENABLE);
376         if (retval == ERROR_OK)
377                 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
378         if (retval == ERROR_OK)
379                 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
380         if (retval == ERROR_OK)
381                 retval = ssp_setcs(target, io_base, 1);
382
383         /* read flash status register */
384         if (retval == ERROR_OK)
385                 retval = read_status_reg(bank, &status);
386         if (retval != ERROR_OK)
387                 return retval;
388
389         /* Check write enabled */
390         if ((status & SPIFLASH_WE_BIT) == 0) {
391                 LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status);
392                 return ERROR_FAIL;
393         }
394
395         return retval;
396 }
397
398 static int lpcspifi_bulk_erase(struct flash_bank *bank)
399 {
400         struct target *target = bank->target;
401         struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
402         uint32_t ssp_base = lpcspifi_info->ssp_base;
403         uint32_t io_base = lpcspifi_info->io_base;
404         uint32_t value;
405         int retval = ERROR_OK;
406
407         retval = lpcspifi_set_sw_mode(bank);
408
409         if (retval == ERROR_OK)
410                 retval = lpcspifi_write_enable(bank);
411
412         /* send SPI command "bulk erase" */
413         if (retval == ERROR_OK)
414                 ssp_setcs(target, io_base, 0);
415         if (retval == ERROR_OK)
416                 retval = ssp_write_reg(target, ssp_base, SSP_DATA, lpcspifi_info->dev->chip_erase_cmd);
417         if (retval == ERROR_OK)
418                 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
419         if (retval == ERROR_OK)
420                 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
421         if (retval == ERROR_OK)
422                 retval = ssp_setcs(target, io_base, 1);
423
424         /* poll flash BSY for self-timed bulk erase */
425         if (retval == ERROR_OK)
426                 retval = wait_till_ready(bank, bank->num_sectors*SSP_MAX_TIMEOUT);
427
428         return retval;
429 }
430
431 static int lpcspifi_erase(struct flash_bank *bank, int first, int last)
432 {
433         struct target *target = bank->target;
434         struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
435         struct reg_param reg_params[4];
436         struct armv7m_algorithm armv7m_info;
437         struct working_area *erase_algorithm;
438         int retval = ERROR_OK;
439         int sector;
440
441         LOG_DEBUG("erase from sector %d to sector %d", first, last);
442
443         if (target->state != TARGET_HALTED) {
444                 LOG_ERROR("Target not halted");
445                 return ERROR_TARGET_NOT_HALTED;
446         }
447
448         if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
449                 LOG_ERROR("Flash sector invalid");
450                 return ERROR_FLASH_SECTOR_INVALID;
451         }
452
453         if (!(lpcspifi_info->probed)) {
454                 LOG_ERROR("Flash bank not probed");
455                 return ERROR_FLASH_BANK_NOT_PROBED;
456         }
457
458         for (sector = first; sector <= last; sector++) {
459                 if (bank->sectors[sector].is_protected) {
460                         LOG_ERROR("Flash sector %d protected", sector);
461                         return ERROR_FAIL;
462                 }
463         }
464
465         /* If we're erasing the entire chip and the flash supports
466          * it, use a bulk erase instead of going sector-by-sector. */
467         if (first == 0 && last == (bank->num_sectors - 1)
468                 && lpcspifi_info->dev->chip_erase_cmd != lpcspifi_info->dev->erase_cmd) {
469                 LOG_DEBUG("Chip supports the bulk erase command."\
470                 " Will use bulk erase instead of sector-by-sector erase.");
471                 retval = lpcspifi_bulk_erase(bank);
472
473                 if (retval == ERROR_OK) {
474                         retval = lpcspifi_set_hw_mode(bank);
475                         return retval;
476                 } else
477                         LOG_WARNING("Bulk flash erase failed. Falling back to sector-by-sector erase.");
478         }
479
480         retval = lpcspifi_set_hw_mode(bank);
481         if (retval != ERROR_OK)
482                 return retval;
483
484         /* see contrib/loaders/flash/lpcspifi_erase.S for src */
485         static const uint8_t lpcspifi_flash_erase_code[] = {
486                 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x08, 0x0a,
487                 0x4f, 0xf0, 0xea, 0x08, 0xca, 0xf8, 0x8c, 0x81,
488                 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x90, 0x81,
489                 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x94, 0x81,
490                 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x98, 0x81,
491                 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x9c, 0x81,
492                 0x4f, 0xf0, 0x44, 0x08, 0xca, 0xf8, 0xa0, 0x81,
493                 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
494                 0x4f, 0xf4, 0x00, 0x68, 0xca, 0xf8, 0x14, 0x80,
495                 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
496                 0x4f, 0xf0, 0xff, 0x08, 0xca, 0xf8, 0xab, 0x80,
497                 0x4f, 0xf0, 0x00, 0x0a, 0xc4, 0xf2, 0x05, 0x0a,
498                 0x4f, 0xf0, 0x00, 0x08, 0xc0, 0xf2, 0x00, 0x18,
499                 0xca, 0xf8, 0x94, 0x80, 0x4f, 0xf4, 0x00, 0x5a,
500                 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x01, 0x08,
501                 0xca, 0xf8, 0x00, 0x87, 0x4f, 0xf4, 0x40, 0x5a,
502                 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0x07, 0x08,
503                 0xca, 0xf8, 0x00, 0x80, 0x4f, 0xf0, 0x02, 0x08,
504                 0xca, 0xf8, 0x10, 0x80, 0xca, 0xf8, 0x04, 0x80,
505                 0x00, 0xf0, 0x52, 0xf8, 0x4f, 0xf0, 0x06, 0x09,
506                 0x00, 0xf0, 0x3b, 0xf8, 0x00, 0xf0, 0x48, 0xf8,
507                 0x00, 0xf0, 0x4a, 0xf8, 0x4f, 0xf0, 0x05, 0x09,
508                 0x00, 0xf0, 0x33, 0xf8, 0x4f, 0xf0, 0x00, 0x09,
509                 0x00, 0xf0, 0x2f, 0xf8, 0x00, 0xf0, 0x3c, 0xf8,
510                 0x19, 0xf0, 0x02, 0x0f, 0x00, 0xf0, 0x45, 0x80,
511                 0x00, 0xf0, 0x3a, 0xf8, 0x4f, 0xea, 0x02, 0x09,
512                 0x00, 0xf0, 0x23, 0xf8, 0x4f, 0xea, 0x10, 0x49,
513                 0x00, 0xf0, 0x1f, 0xf8, 0x4f, 0xea, 0x10, 0x29,
514                 0x00, 0xf0, 0x1b, 0xf8, 0x4f, 0xea, 0x00, 0x09,
515                 0x00, 0xf0, 0x17, 0xf8, 0x00, 0xf0, 0x24, 0xf8,
516                 0x00, 0xf0, 0x26, 0xf8, 0x4f, 0xf0, 0x05, 0x09,
517                 0x00, 0xf0, 0x0f, 0xf8, 0x4f, 0xf0, 0x00, 0x09,
518                 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0xf0, 0x18, 0xf8,
519                 0x19, 0xf0, 0x01, 0x0f, 0x7f, 0xf4, 0xf0, 0xaf,
520                 0x01, 0x39, 0xf9, 0xb1, 0x18, 0x44, 0xff, 0xf7,
521                 0xbf, 0xbf, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2,
522                 0x08, 0x0a, 0xca, 0xf8, 0x08, 0x90, 0xda, 0xf8,
523                 0x0c, 0x90, 0x19, 0xf0, 0x10, 0x0f, 0x7f, 0xf4,
524                 0xfa, 0xaf, 0xda, 0xf8, 0x08, 0x90, 0x70, 0x47,
525                 0x4f, 0xf0, 0xff, 0x08, 0x00, 0xf0, 0x02, 0xb8,
526                 0x4f, 0xf0, 0x00, 0x08, 0x4f, 0xf4, 0x80, 0x4a,
527                 0xc4, 0xf2, 0x0f, 0x0a, 0xca, 0xf8, 0xab, 0x80,
528                 0x70, 0x47, 0x00, 0x20, 0x00, 0xbe, 0xff, 0xff
529         };
530
531         armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
532         armv7m_info.core_mode = ARM_MODE_THREAD;
533
534
535         /* Get memory for spifi initialization algorithm */
536         retval = target_alloc_working_area(target, sizeof(lpcspifi_flash_erase_code),
537                 &erase_algorithm);
538         if (retval != ERROR_OK) {
539                 LOG_ERROR("Insufficient working area. You must configure a working"\
540                         " area of at least %zdB in order to erase SPIFI flash.",
541                         sizeof(lpcspifi_flash_erase_code));
542                 return retval;
543         }
544
545         /* Write algorithm to working area */
546         retval = target_write_buffer(target, erase_algorithm->address,
547                 sizeof(lpcspifi_flash_erase_code), lpcspifi_flash_erase_code);
548         if (retval != ERROR_OK) {
549                 target_free_working_area(target, erase_algorithm);
550                 return retval;
551         }
552
553         init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* Start address */
554         init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);    /* Sector count */
555         init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);    /* Erase command */
556         init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);    /* Sector size */
557
558         buf_set_u32(reg_params[0].value, 0, 32, bank->sectors[first].offset);
559         buf_set_u32(reg_params[1].value, 0, 32, last - first + 1);
560         buf_set_u32(reg_params[2].value, 0, 32, lpcspifi_info->dev->erase_cmd);
561         buf_set_u32(reg_params[3].value, 0, 32, bank->sectors[first].size);
562
563         /* Run the algorithm */
564         retval = target_run_algorithm(target, 0 , NULL, 4, reg_params,
565                 erase_algorithm->address,
566                 erase_algorithm->address + sizeof(lpcspifi_flash_erase_code) - 4,
567                 3000*(last - first + 1), &armv7m_info);
568
569         if (retval != ERROR_OK)
570                 LOG_ERROR("Error executing flash erase algorithm");
571
572         target_free_working_area(target, erase_algorithm);
573
574         destroy_reg_param(&reg_params[0]);
575         destroy_reg_param(&reg_params[1]);
576         destroy_reg_param(&reg_params[2]);
577         destroy_reg_param(&reg_params[3]);
578
579         retval = lpcspifi_set_hw_mode(bank);
580
581         return retval;
582 }
583
584 static int lpcspifi_protect(struct flash_bank *bank, int set,
585         int first, int last)
586 {
587         int sector;
588
589         for (sector = first; sector <= last; sector++)
590                 bank->sectors[sector].is_protected = set;
591         return ERROR_OK;
592 }
593
594 static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
595         uint32_t offset, uint32_t count)
596 {
597         struct target *target = bank->target;
598         struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
599         uint32_t page_size, fifo_size;
600         struct working_area *fifo;
601         struct reg_param reg_params[5];
602         struct armv7m_algorithm armv7m_info;
603         struct working_area *write_algorithm;
604         int sector;
605         int retval = ERROR_OK;
606
607         LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32,
608                 offset, count);
609
610         if (target->state != TARGET_HALTED) {
611                 LOG_ERROR("Target not halted");
612                 return ERROR_TARGET_NOT_HALTED;
613         }
614
615         if (offset + count > lpcspifi_info->dev->size_in_bytes) {
616                 LOG_WARNING("Writes past end of flash. Extra data discarded.");
617                 count = lpcspifi_info->dev->size_in_bytes - offset;
618         }
619
620         /* Check sector protection */
621         for (sector = 0; sector < bank->num_sectors; sector++) {
622                 /* Start offset in or before this sector? */
623                 /* End offset in or behind this sector? */
624                 if ((offset <
625                                 (bank->sectors[sector].offset + bank->sectors[sector].size))
626                         && ((offset + count - 1) >= bank->sectors[sector].offset)
627                         && bank->sectors[sector].is_protected) {
628                         LOG_ERROR("Flash sector %d protected", sector);
629                         return ERROR_FAIL;
630                 }
631         }
632
633         page_size = lpcspifi_info->dev->pagesize;
634
635         retval = lpcspifi_set_hw_mode(bank);
636         if (retval != ERROR_OK)
637                 return retval;
638
639         /* see contrib/loaders/flash/lpcspifi_write.S for src */
640         static const uint8_t lpcspifi_flash_write_code[] = {
641                 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x08, 0x0a,
642                 0x4f, 0xf0, 0xea, 0x08, 0xca, 0xf8, 0x8c, 0x81,
643                 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x90, 0x81,
644                 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x94, 0x81,
645                 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x98, 0x81,
646                 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x9c, 0x81,
647                 0x4f, 0xf0, 0x44, 0x08, 0xca, 0xf8, 0xa0, 0x81,
648                 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
649                 0x4f, 0xf4, 0x00, 0x68, 0xca, 0xf8, 0x14, 0x80,
650                 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
651                 0x4f, 0xf0, 0xff, 0x08, 0xca, 0xf8, 0xab, 0x80,
652                 0x4f, 0xf0, 0x00, 0x0a, 0xc4, 0xf2, 0x05, 0x0a,
653                 0x4f, 0xf0, 0x00, 0x08, 0xc0, 0xf2, 0x00, 0x18,
654                 0xca, 0xf8, 0x94, 0x80, 0x4f, 0xf4, 0x00, 0x5a,
655                 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x01, 0x08,
656                 0xca, 0xf8, 0x00, 0x87, 0x4f, 0xf4, 0x40, 0x5a,
657                 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0x07, 0x08,
658                 0xca, 0xf8, 0x00, 0x80, 0x4f, 0xf0, 0x02, 0x08,
659                 0xca, 0xf8, 0x10, 0x80, 0xca, 0xf8, 0x04, 0x80,
660                 0x4f, 0xf0, 0x00, 0x0b, 0xa3, 0x44, 0x93, 0x45,
661                 0x7f, 0xf6, 0xfc, 0xaf, 0x00, 0xf0, 0x6a, 0xf8,
662                 0x4f, 0xf0, 0x06, 0x09, 0x00, 0xf0, 0x53, 0xf8,
663                 0x00, 0xf0, 0x60, 0xf8, 0x00, 0xf0, 0x62, 0xf8,
664                 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x4b, 0xf8,
665                 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x47, 0xf8,
666                 0x00, 0xf0, 0x54, 0xf8, 0x19, 0xf0, 0x02, 0x0f,
667                 0x00, 0xf0, 0x5d, 0x80, 0x00, 0xf0, 0x52, 0xf8,
668                 0x4f, 0xf0, 0x02, 0x09, 0x00, 0xf0, 0x3b, 0xf8,
669                 0x4f, 0xea, 0x12, 0x49, 0x00, 0xf0, 0x37, 0xf8,
670                 0x4f, 0xea, 0x12, 0x29, 0x00, 0xf0, 0x33, 0xf8,
671                 0x4f, 0xea, 0x02, 0x09, 0x00, 0xf0, 0x2f, 0xf8,
672                 0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1, 0x00, 0x0f,
673                 0x00, 0xf0, 0x47, 0x80, 0x47, 0x68, 0x47, 0x45,
674                 0x3f, 0xf4, 0xf6, 0xaf, 0x17, 0xf8, 0x01, 0x9b,
675                 0x00, 0xf0, 0x21, 0xf8, 0x8f, 0x42, 0x28, 0xbf,
676                 0x00, 0xf1, 0x08, 0x07, 0x47, 0x60, 0x01, 0x3b,
677                 0xbb, 0xb3, 0x02, 0xf1, 0x01, 0x02, 0x93, 0x45,
678                 0x7f, 0xf4, 0xe6, 0xaf, 0x00, 0xf0, 0x22, 0xf8,
679                 0xa3, 0x44, 0x00, 0xf0, 0x23, 0xf8, 0x4f, 0xf0,
680                 0x05, 0x09, 0x00, 0xf0, 0x0c, 0xf8, 0x4f, 0xf0,
681                 0x00, 0x09, 0x00, 0xf0, 0x08, 0xf8, 0x00, 0xf0,
682                 0x15, 0xf8, 0x19, 0xf0, 0x01, 0x0f, 0x7f, 0xf4,
683                 0xf0, 0xaf, 0xff, 0xf7, 0xa7, 0xbf, 0x4f, 0xf4,
684                 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0xca, 0xf8,
685                 0x08, 0x90, 0xda, 0xf8, 0x0c, 0x90, 0x19, 0xf0,
686                 0x10, 0x0f, 0x7f, 0xf4, 0xfa, 0xaf, 0xda, 0xf8,
687                 0x08, 0x90, 0x70, 0x47, 0x4f, 0xf0, 0xff, 0x08,
688                 0x00, 0xf0, 0x02, 0xb8, 0x4f, 0xf0, 0x00, 0x08,
689                 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
690                 0xca, 0xf8, 0xab, 0x80, 0x70, 0x47, 0x00, 0x20,
691                 0x50, 0x60, 0xff, 0xf7, 0xef, 0xff, 0x30, 0x46,
692                 0x00, 0xbe, 0xff, 0xff
693         };
694
695         if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code),
696                         &write_algorithm) != ERROR_OK) {
697                 LOG_ERROR("Insufficient working area. You must configure"\
698                         " a working area > %zdB in order to write to SPIFI flash.",
699                         sizeof(lpcspifi_flash_write_code));
700                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
701         }
702
703         retval = target_write_buffer(target, write_algorithm->address,
704                         sizeof(lpcspifi_flash_write_code),
705                         lpcspifi_flash_write_code);
706         if (retval != ERROR_OK) {
707                 target_free_working_area(target, write_algorithm);
708                 return retval;
709         }
710
711         /* FIFO allocation */
712         fifo_size = target_get_working_area_avail(target);
713
714         if (fifo_size == 0) {
715                 /* if we already allocated the writing code but failed to get fifo
716                  * space, free the algorithm */
717                 target_free_working_area(target, write_algorithm);
718
719                 LOG_ERROR("Insufficient working area. Please allocate at least"\
720                         " %zdB of working area to enable flash writes.",
721                         sizeof(lpcspifi_flash_write_code) + 1
722                 );
723
724                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
725         } else if (fifo_size < page_size)
726                 LOG_WARNING("Working area size is limited; flash writes may be"\
727                         " slow. Increase working area size to at least %zdB"\
728                         " to reduce write times.",
729                         (size_t)(sizeof(lpcspifi_flash_write_code) + page_size)
730                 );
731         else if (fifo_size > 0x2000) /* Beyond this point, we start to get diminishing returns */
732                 fifo_size = 0x2000;
733
734         if (target_alloc_working_area(target, fifo_size, &fifo) != ERROR_OK) {
735                 target_free_working_area(target, write_algorithm);
736                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
737         }
738
739         armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
740         armv7m_info.core_mode = ARM_MODE_THREAD;
741
742         init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);         /* buffer start, status (out) */
743         init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);            /* buffer end */
744         init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);            /* target address */
745         init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);            /* count (halfword-16bit) */
746         init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);            /* page size */
747
748         buf_set_u32(reg_params[0].value, 0, 32, fifo->address);
749         buf_set_u32(reg_params[1].value, 0, 32, fifo->address + fifo->size);
750         buf_set_u32(reg_params[2].value, 0, 32, offset);
751         buf_set_u32(reg_params[3].value, 0, 32, count);
752         buf_set_u32(reg_params[4].value, 0, 32, page_size);
753
754         retval = target_run_flash_async_algorithm(target, buffer, count, 1,
755                         0, NULL,
756                         5, reg_params,
757                         fifo->address, fifo->size,
758                         write_algorithm->address, 0,
759                         &armv7m_info
760         );
761
762         if (retval != ERROR_OK)
763                 LOG_ERROR("Error executing flash write algorithm");
764
765         target_free_working_area(target, fifo);
766         target_free_working_area(target, write_algorithm);
767
768         destroy_reg_param(&reg_params[0]);
769         destroy_reg_param(&reg_params[1]);
770         destroy_reg_param(&reg_params[2]);
771         destroy_reg_param(&reg_params[3]);
772         destroy_reg_param(&reg_params[4]);
773
774         /* Switch to HW mode before return to prompt */
775         retval = lpcspifi_set_hw_mode(bank);
776         return retval;
777 }
778
779 /* Return ID of flash device */
780 /* On exit, SW mode is kept */
781 static int lpcspifi_read_flash_id(struct flash_bank *bank, uint32_t *id)
782 {
783         struct target *target = bank->target;
784         struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
785         uint32_t ssp_base = lpcspifi_info->ssp_base;
786         uint32_t io_base = lpcspifi_info->io_base;
787         uint32_t value;
788         uint8_t id_buf[3] = {0, 0, 0};
789         int retval;
790
791         if (target->state != TARGET_HALTED) {
792                 LOG_ERROR("Target not halted");
793                 return ERROR_TARGET_NOT_HALTED;
794         }
795
796         LOG_DEBUG("Getting ID");
797         retval = lpcspifi_set_sw_mode(bank);
798         if (retval != ERROR_OK)
799                 return retval;
800
801         /* poll WIP */
802         if (retval == ERROR_OK)
803                 retval = wait_till_ready(bank, SSP_PROBE_TIMEOUT);
804
805         /* Send SPI command "read ID" */
806         if (retval == ERROR_OK)
807                 retval = ssp_setcs(target, io_base, 0);
808         if (retval == ERROR_OK)
809                 retval = ssp_write_reg(target, ssp_base, SSP_DATA, SPIFLASH_READ_ID);
810         if (retval == ERROR_OK)
811                 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
812         if (retval == ERROR_OK)
813                 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
814
815         /* Dummy write to clock in data */
816         if (retval == ERROR_OK)
817                 retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00);
818         if (retval == ERROR_OK)
819                 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
820         if (retval == ERROR_OK)
821                 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
822         if (retval == ERROR_OK)
823                 id_buf[0] = value;
824
825         /* Dummy write to clock in data */
826         if (retval == ERROR_OK)
827                 retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00);
828         if (retval == ERROR_OK)
829                 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
830         if (retval == ERROR_OK)
831                 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
832         if (retval == ERROR_OK)
833                 id_buf[1] = value;
834
835         /* Dummy write to clock in data */
836         if (retval == ERROR_OK)
837                 retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00);
838         if (retval == ERROR_OK)
839                 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
840         if (retval == ERROR_OK)
841                 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
842         if (retval == ERROR_OK)
843                 id_buf[2] = value;
844
845         if (retval == ERROR_OK)
846                 retval = ssp_setcs(target, io_base, 1);
847         if (retval == ERROR_OK)
848                 *id = id_buf[2] << 16 | id_buf[1] << 8 | id_buf[0];
849
850         return retval;
851 }
852
853 static int lpcspifi_probe(struct flash_bank *bank)
854 {
855         struct target *target = bank->target;
856         struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
857         uint32_t ssp_base;
858         uint32_t io_base;
859         uint32_t ioconfig_base;
860         struct flash_sector *sectors;
861         uint32_t id = 0; /* silence uninitialized warning */
862         const struct lpcspifi_target *target_device;
863         int retval;
864
865         /* If we've already probed, we should be fine to skip this time. */
866         if (lpcspifi_info->probed)
867                 return ERROR_OK;
868         lpcspifi_info->probed = 0;
869
870         for (target_device = target_devices ; target_device->name ; ++target_device)
871                 if (target_device->tap_idcode == target->tap->idcode)
872                         break;
873         if (!target_device->name) {
874                 LOG_ERROR("Device ID 0x%" PRIx32 " is not known as SPIFI capable",
875                                 target->tap->idcode);
876                 return ERROR_FAIL;
877         }
878
879         ssp_base = target_device->ssp_base;
880         io_base = target_device->io_base;
881         ioconfig_base = target_device->ioconfig_base;
882         lpcspifi_info->ssp_base = ssp_base;
883         lpcspifi_info->io_base = io_base;
884         lpcspifi_info->ioconfig_base = ioconfig_base;
885         lpcspifi_info->bank_num = bank->bank_number;
886
887         LOG_DEBUG("Valid SPIFI on device %s at address 0x%" PRIx32,
888                 target_device->name, bank->base);
889
890         /* read and decode flash ID; returns in SW mode */
891         retval = lpcspifi_read_flash_id(bank, &id);
892         if (retval != ERROR_OK)
893                 return retval;
894
895         retval = lpcspifi_set_hw_mode(bank);
896         if (retval != ERROR_OK)
897                 return retval;
898
899         lpcspifi_info->dev = NULL;
900         for (const struct flash_device *p = flash_devices; p->name ; p++)
901                 if (p->device_id == id) {
902                         lpcspifi_info->dev = p;
903                         break;
904                 }
905
906         if (!lpcspifi_info->dev) {
907                 LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id);
908                 return ERROR_FAIL;
909         }
910
911         LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
912                 lpcspifi_info->dev->name, lpcspifi_info->dev->device_id);
913
914         /* Set correct size value */
915         bank->size = lpcspifi_info->dev->size_in_bytes;
916
917         /* create and fill sectors array */
918         bank->num_sectors =
919                 lpcspifi_info->dev->size_in_bytes / lpcspifi_info->dev->sectorsize;
920         sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
921         if (sectors == NULL) {
922                 LOG_ERROR("not enough memory");
923                 return ERROR_FAIL;
924         }
925
926         for (int sector = 0; sector < bank->num_sectors; sector++) {
927                 sectors[sector].offset = sector * lpcspifi_info->dev->sectorsize;
928                 sectors[sector].size = lpcspifi_info->dev->sectorsize;
929                 sectors[sector].is_erased = -1;
930                 sectors[sector].is_protected = 0;
931         }
932
933         bank->sectors = sectors;
934
935         lpcspifi_info->probed = 1;
936         return ERROR_OK;
937 }
938
939 static int lpcspifi_auto_probe(struct flash_bank *bank)
940 {
941         struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
942         if (lpcspifi_info->probed)
943                 return ERROR_OK;
944         return lpcspifi_probe(bank);
945 }
946
947 static int lpcspifi_protect_check(struct flash_bank *bank)
948 {
949         /* Nothing to do. Protection is only handled in SW. */
950         return ERROR_OK;
951 }
952
953 static int get_lpcspifi_info(struct flash_bank *bank, char *buf, int buf_size)
954 {
955         struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
956
957         if (!(lpcspifi_info->probed)) {
958                 snprintf(buf, buf_size,
959                         "\nSPIFI flash bank not probed yet\n");
960                 return ERROR_OK;
961         }
962
963         snprintf(buf, buf_size, "\nSPIFI flash information:\n"
964                 "  Device \'%s\' (ID 0x%08" PRIx32 ")\n",
965                 lpcspifi_info->dev->name, lpcspifi_info->dev->device_id);
966
967         return ERROR_OK;
968 }
969
970 struct flash_driver lpcspifi_flash = {
971         .name = "lpcspifi",
972         .flash_bank_command = lpcspifi_flash_bank_command,
973         .erase = lpcspifi_erase,
974         .protect = lpcspifi_protect,
975         .write = lpcspifi_write,
976         .read = default_flash_read,
977         .probe = lpcspifi_probe,
978         .auto_probe = lpcspifi_auto_probe,
979         .erase_check = default_flash_blank_check,
980         .protect_check = lpcspifi_protect_check,
981         .info = get_lpcspifi_info,
982 };