blob: 93887b3c332c0073eaef71a8856d28e52fdd6299 [file] [log] [blame]
Dominik Geyerb46acba2008-05-16 12:55:55 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2008 Stefan Wildemann <stefan.wildemann@kontron.com>
5 * Copyright (C) 2008 Claus Gindhart <claus.gindhart@kontron.com>
6 * Copyright (C) 2008 Dominik Geyer <dominik.geyer@kontron.com>
Stefan Reinauera9424d52008-06-27 16:28:34 +00007 * Copyright (C) 2008 coresystems GmbH <info@coresystems.de>
Dominik Geyerb46acba2008-05-16 12:55:55 +00008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 */
24
25/*
26 * This module is designed for supporting the devices
27 * ST M25P40
28 * ST M25P80
29 * ST M25P16
30 * ST M25P32 already tested
31 * ST M25P64
32 * AT 25DF321 already tested
33 *
34 */
35
36#include <stdio.h>
37#include <string.h>
38#include <stdint.h>
39#include <sys/mman.h>
40#include <pci/pci.h>
41#include "flash.h"
42#include "spi.h"
43
Stefan Reinauera9424d52008-06-27 16:28:34 +000044/* ICH9 controller register definition */
45#define ICH9_REG_FADDR 0x08 /* 32 Bits */
46#define ICH9_REG_FDATA0 0x10 /* 64 Bytes */
47
48#define ICH9_REG_SSFS 0x90 /* 08 Bits */
Dominik Geyerb46acba2008-05-16 12:55:55 +000049#define SSFS_SCIP 0x00000001
50#define SSFS_CDS 0x00000004
51#define SSFS_FCERR 0x00000008
52#define SSFS_AEL 0x00000010
Stefan Reinauera9424d52008-06-27 16:28:34 +000053
54#define ICH9_REG_SSFC 0x91 /* 24 Bits */
Dominik Geyerb46acba2008-05-16 12:55:55 +000055#define SSFC_SCGO 0x00000200
56#define SSFC_ACS 0x00000400
57#define SSFC_SPOP 0x00000800
58#define SSFC_COP 0x00001000
59#define SSFC_DBC 0x00010000
60#define SSFC_DS 0x00400000
61#define SSFC_SME 0x00800000
62#define SSFC_SCF 0x01000000
63#define SSFC_SCF_20MHZ 0x00000000
64#define SSFC_SCF_33MHZ 0x01000000
Stefan Reinauera9424d52008-06-27 16:28:34 +000065
66#define ICH9_REG_PREOP 0x94 /* 16 Bits */
67#define ICH9_REG_OPTYPE 0x96 /* 16 Bits */
68#define ICH9_REG_OPMENU 0x98 /* 64 Bits */
Dominik Geyerb46acba2008-05-16 12:55:55 +000069
70// ICH9R SPI commands
71#define SPI_OPCODE_TYPE_READ_NO_ADDRESS 0
72#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS 1
73#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS 2
74#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS 3
75
Stefan Reinauera9424d52008-06-27 16:28:34 +000076// ICH7 registers
77#define ICH7_REG_SPIS 0x00 /* 16 Bits */
78#define SPIS_SCIP 0x00000001
79#define SPIS_CDS 0x00000004
80#define SPIS_FCERR 0x00000008
81
Rudolf Marek3fdbccf2008-06-30 21:38:30 +000082/* VIA SPI is compatible with ICH7, but maxdata
83 to transfer is 16 bytes.
84
85 DATA byte count on ICH7 is 8:13, on VIA 8:11
86
87 bit 12 is port select CS0 CS1
88 bit 13 is FAST READ enable
89 bit 7 is used with fast read and one shot controls CS de-assert?
90*/
91
Stefan Reinauera9424d52008-06-27 16:28:34 +000092#define ICH7_REG_SPIC 0x02 /* 16 Bits */
93#define SPIC_SCGO 0x0002
94#define SPIC_ACS 0x0004
95#define SPIC_SPOP 0x0008
Rudolf Marek3fdbccf2008-06-30 21:38:30 +000096#define SPIC_DS 0x4000
Stefan Reinauera9424d52008-06-27 16:28:34 +000097
98#define ICH7_REG_SPIA 0x04 /* 32 Bits */
99#define ICH7_REG_SPID0 0x08 /* 64 Bytes */
100#define ICH7_REG_PREOP 0x54 /* 16 Bits */
101#define ICH7_REG_OPTYPE 0x56 /* 16 Bits */
102#define ICH7_REG_OPMENU 0x58 /* 64 Bits */
103
Dominik Geyerb46acba2008-05-16 12:55:55 +0000104typedef struct _OPCODE {
105 uint8_t opcode; //This commands spi opcode
106 uint8_t spi_type; //This commands spi type
107 uint8_t atomic; //Use preop: (0: none, 1: preop0, 2: preop1
108} OPCODE;
109
110/* Opcode definition:
111 * Preop 1: Write Enable
112 * Preop 2: Write Status register enable
113 *
114 * OP 0: Write address
115 * OP 1: Read Address
116 * OP 2: ERASE block
117 * OP 3: Read Status register
118 * OP 4: Read ID
119 * OP 5: Write Status register
120 * OP 6: chip private (read JDEC id)
121 * OP 7: Chip erase
122 */
123typedef struct _OPCODES {
124 uint8_t preop[2];
125 OPCODE opcode[8];
126} OPCODES;
127
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000128static OPCODES *curopcodes = NULL;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000129
130/* HW access functions */
131static inline uint32_t REGREAD32(int X)
132{
133 volatile uint32_t regval;
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000134 regval = *(volatile uint32_t *) ((uint8_t *) spibar + X);
Stefan Reinauera9424d52008-06-27 16:28:34 +0000135 return regval;
136}
137
138static inline uint16_t REGREAD16(int X)
139{
140 volatile uint16_t regval;
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000141 regval = *(volatile uint16_t *) ((uint8_t *) spibar + X);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000142 return regval;
143}
144
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000145#define REGWRITE32(X,Y) (*(uint32_t *)((uint8_t *)spibar+X)=Y)
146#define REGWRITE16(X,Y) (*(uint16_t *)((uint8_t *)spibar+X)=Y)
147#define REGWRITE8(X,Y) (*(uint8_t *)((uint8_t *)spibar+X)=Y)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000148
Dominik Geyerb46acba2008-05-16 12:55:55 +0000149/* Common SPI functions */
150static int program_opcodes(OPCODES * op);
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000151static int run_opcode(uint8_t nr, OPCODE op, uint32_t offset,
152 uint8_t datalength, uint8_t * data);
153static int ich_spi_read_page(struct flashchip *flash, uint8_t * buf,
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000154 int offset, int maxdata);
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000155static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000156 int offset, int maxdata);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000157static int ich_spi_erase_block(struct flashchip *flash, int offset);
158
Dominik Geyerb46acba2008-05-16 12:55:55 +0000159OPCODES O_ST_M25P = {
160 {
161 JEDEC_WREN,
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000162 0},
Dominik Geyerb46acba2008-05-16 12:55:55 +0000163 {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000164 {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Write Byte
165 {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data
166 {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Erase Sector
167 {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg
168 {JEDEC_RES, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Resume Deep Power-Down
169 {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Write Status Register
170 {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID
171 {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Bulk erase
172 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000173};
174
Dominik Geyerb46acba2008-05-16 12:55:55 +0000175int program_opcodes(OPCODES * op)
176{
177 uint8_t a;
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000178 uint16_t preop, optype;
179 uint32_t opmenu[2];
Dominik Geyerb46acba2008-05-16 12:55:55 +0000180
181 /* Program Prefix Opcodes */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000182 preop = 0;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000183 /* 0:7 Prefix Opcode 1 */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000184 preop = (op->preop[0]);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000185 /* 8:16 Prefix Opcode 2 */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000186 preop |= ((uint16_t) op->preop[1]) << 8;
187
Stefan Reinauera9424d52008-06-27 16:28:34 +0000188 /* Program Opcode Types 0 - 7 */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000189 optype = 0;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000190 for (a = 0; a < 8; a++) {
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000191 optype |= ((uint16_t) op->opcode[a].spi_type) << (a * 2);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000192 }
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000193
Stefan Reinauera9424d52008-06-27 16:28:34 +0000194 /* Program Allowable Opcodes 0 - 3 */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000195 opmenu[0] = 0;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000196 for (a = 0; a < 4; a++) {
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000197 opmenu[0] |= ((uint32_t) op->opcode[a].opcode) << (a * 8);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000198 }
Stefan Reinauera9424d52008-06-27 16:28:34 +0000199
Dominik Geyerb46acba2008-05-16 12:55:55 +0000200 /*Program Allowable Opcodes 4 - 7 */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000201 opmenu[1] = 0;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000202 for (a = 4; a < 8; a++) {
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000203 opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000204 }
Stefan Reinauera9424d52008-06-27 16:28:34 +0000205
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000206 switch (flashbus) {
207 case BUS_TYPE_ICH7_SPI:
208 case BUS_TYPE_VIA_SPI:
209 REGWRITE16(ICH7_REG_PREOP, preop);
210 REGWRITE16(ICH7_REG_OPTYPE, optype);
211 REGWRITE32(ICH7_REG_OPMENU, opmenu[0]);
212 REGWRITE32(ICH7_REG_OPMENU + 4, opmenu[1]);
213 break;
214 case BUS_TYPE_ICH9_SPI:
215 REGWRITE16(ICH9_REG_PREOP, preop);
216 REGWRITE16(ICH9_REG_OPTYPE, optype);
217 REGWRITE32(ICH9_REG_OPMENU, opmenu[0]);
218 REGWRITE32(ICH9_REG_OPMENU + 4, opmenu[1]);
219 break;
220 default:
221 printf_debug("%s: unsupported chipset\n", __FUNCTION__);
222 return -1;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000223 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000224
225 return 0;
226}
227
Stefan Reinauera9424d52008-06-27 16:28:34 +0000228static int ich7_run_opcode(uint8_t nr, OPCODE op, uint32_t offset,
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000229 uint8_t datalength, uint8_t * data, int maxdata)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000230{
231 int write_cmd = 0;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000232 int timeout;
Peter Stuge7e2c0792008-06-29 01:30:41 +0000233 uint32_t temp32 = 0;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000234 uint16_t temp16;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000235 uint32_t a;
236
237 /* Is it a write command? */
238 if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
239 || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
240 write_cmd = 1;
241 }
242
243 /* Programm Offset in Flash into FADDR */
Stefan Reinauera9424d52008-06-27 16:28:34 +0000244 REGWRITE32(ICH7_REG_SPIA, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */
Dominik Geyerb46acba2008-05-16 12:55:55 +0000245
246 /* Program data into FDATA0 to N */
247 if (write_cmd && (datalength != 0)) {
248 temp32 = 0;
249 for (a = 0; a < datalength; a++) {
250 if ((a % 4) == 0) {
251 temp32 = 0;
252 }
253
254 temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
255
256 if ((a % 4) == 3) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000257 REGWRITE32(ICH7_REG_SPID0 + (a - (a % 4)),
258 temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000259 }
260 }
261 if (((a - 1) % 4) != 3) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000262 REGWRITE32(ICH7_REG_SPID0 +
263 ((a - 1) - ((a - 1) % 4)), temp32);
264 }
265
266 }
267
268 /* Assemble SPIS */
269 temp16 = 0;
270 /* clear error status registers */
271 temp16 |= (SPIS_CDS + SPIS_FCERR);
272 REGWRITE16(ICH7_REG_SPIS, temp16);
273
274 /* Assemble SPIC */
275 temp16 = 0;
276
277 if (datalength != 0) {
278 temp16 |= SPIC_DS;
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000279 temp16 |= ((uint32_t) ((datalength - 1) & (maxdata - 1))) << 8;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000280 }
281
282 /* Select opcode */
283 temp16 |= ((uint16_t) (nr & 0x07)) << 4;
284
285 /* Handle Atomic */
286 if (op.atomic != 0) {
287 /* Select atomic command */
288 temp16 |= SPIC_ACS;
289 /* Selct prefix opcode */
290 if ((op.atomic - 1) == 1) {
291 /*Select prefix opcode 2 */
292 temp16 |= SPIC_SPOP;
293 }
294 }
295
296 /* Start */
297 temp16 |= SPIC_SCGO;
298
299 /* write it */
300 REGWRITE16(ICH7_REG_SPIC, temp16);
301
302 /* wait for cycle complete */
303 timeout = 1000 * 60; // 60s is a looong timeout.
304 while (((REGREAD16(ICH7_REG_SPIS) & SPIS_CDS) == 0) && --timeout) {
305 myusec_delay(1000);
306 }
307 if (!timeout) {
308 printf_debug("timeout\n");
309 }
310
311 if ((REGREAD16(ICH7_REG_SPIS) & SPIS_FCERR) != 0) {
312 printf_debug("Transaction error!\n");
313 return 1;
314 }
315
316 if ((!write_cmd) && (datalength != 0)) {
317 for (a = 0; a < datalength; a++) {
318 if ((a % 4) == 0) {
319 temp32 = REGREAD32(ICH7_REG_SPID0 + (a));
320 }
321
322 data[a] =
323 (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
324 >> ((a % 4) * 8);
325 }
326 }
327
328 return 0;
329}
330
331
332static int ich9_run_opcode(uint8_t nr, OPCODE op, uint32_t offset,
333 uint8_t datalength, uint8_t * data)
334{
335 int write_cmd = 0;
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000336 int timeout;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000337 uint32_t temp32;
338 uint32_t a;
339
340 /* Is it a write command? */
341 if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
342 || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
343 write_cmd = 1;
344 }
345
346 /* Programm Offset in Flash into FADDR */
347 REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */
348
349 /* Program data into FDATA0 to N */
350 if (write_cmd && (datalength != 0)) {
351 temp32 = 0;
352 for (a = 0; a < datalength; a++) {
353 if ((a % 4) == 0) {
354 temp32 = 0;
355 }
356
357 temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
358
359 if ((a % 4) == 3) {
360 REGWRITE32(ICH9_REG_FDATA0 + (a - (a % 4)),
361 temp32);
362 }
363 }
364 if (((a - 1) % 4) != 3) {
365 REGWRITE32(ICH9_REG_FDATA0 +
366 ((a - 1) - ((a - 1) % 4)), temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000367 }
368
369 }
370
371 /* Assemble SSFS + SSFC */
372 temp32 = 0;
373
374 /* clear error status registers */
375 temp32 |= (SSFS_CDS + SSFS_FCERR);
376 /* USE 20 MhZ */
377 temp32 |= SSFC_SCF_20MHZ;
378
379 if (datalength != 0) {
380 uint32_t datatemp;
381 temp32 |= SSFC_DS;
382 datatemp = ((uint32_t) ((datalength - 1) & 0x3f)) << (8 + 8);
383 temp32 |= datatemp;
384 }
385
386 /* Select opcode */
387 temp32 |= ((uint32_t) (nr & 0x07)) << (8 + 4);
388
389 /* Handle Atomic */
390 if (op.atomic != 0) {
391 /* Select atomic command */
392 temp32 |= SSFC_ACS;
393 /* Selct prefix opcode */
394 if ((op.atomic - 1) == 1) {
395 /*Select prefix opcode 2 */
396 temp32 |= SSFC_SPOP;
397 }
398 }
399
400 /* Start */
401 temp32 |= SSFC_SCGO;
402
403 /* write it */
Stefan Reinauera9424d52008-06-27 16:28:34 +0000404 REGWRITE32(ICH9_REG_SSFS, temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000405
406 /*wait for cycle complete */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000407 timeout = 1000 * 60; // 60s is a looong timeout.
408 while (((REGREAD32(ICH9_REG_SSFS) & SSFS_CDS) == 0) && --timeout) {
409 myusec_delay(1000);
410 }
411 if (!timeout) {
412 printf_debug("timeout\n");
Dominik Geyerb46acba2008-05-16 12:55:55 +0000413 }
414
Stefan Reinauera9424d52008-06-27 16:28:34 +0000415 if ((REGREAD32(ICH9_REG_SSFS) & SSFS_FCERR) != 0) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000416 printf_debug("Transaction error!\n");
417 return 1;
418 }
419
420 if ((!write_cmd) && (datalength != 0)) {
421 for (a = 0; a < datalength; a++) {
422 if ((a % 4) == 0) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000423 temp32 = REGREAD32(ICH9_REG_FDATA0 + (a));
Dominik Geyerb46acba2008-05-16 12:55:55 +0000424 }
425
426 data[a] =
Stefan Reinauera9424d52008-06-27 16:28:34 +0000427 (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
428 >> ((a % 4) * 8);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000429 }
430 }
431
432 return 0;
433}
434
Stefan Reinauera9424d52008-06-27 16:28:34 +0000435static int run_opcode(uint8_t nr, OPCODE op, uint32_t offset,
436 uint8_t datalength, uint8_t * data)
437{
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000438 switch (flashbus) {
439 case BUS_TYPE_VIA_SPI:
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000440 return ich7_run_opcode(nr, op, offset, datalength, data, 16);
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000441 case BUS_TYPE_ICH7_SPI:
442 return ich7_run_opcode(nr, op, offset, datalength, data, 64);
443 case BUS_TYPE_ICH9_SPI:
Stefan Reinauera9424d52008-06-27 16:28:34 +0000444 return ich9_run_opcode(nr, op, offset, datalength, data);
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000445 default:
446 printf_debug("%s: unsupported chipset\n", __FUNCTION__);
447 }
Stefan Reinauera9424d52008-06-27 16:28:34 +0000448
449 /* If we ever get here, something really weird happened */
450 return -1;
451}
452
Dominik Geyerb46acba2008-05-16 12:55:55 +0000453static int ich_spi_erase_block(struct flashchip *flash, int offset)
454{
Stefan Reinauera9424d52008-06-27 16:28:34 +0000455 printf_debug("ich_spi_erase_block: offset=%d, sectors=%d\n",
456 offset, 1);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000457
458 if (run_opcode(2, curopcodes->opcode[2], offset, 0, NULL) != 0) {
459 printf_debug("Error erasing sector at 0x%x", offset);
460 return -1;
461 }
462
463 printf("DONE BLOCK 0x%x\n", offset);
464
465 return 0;
466}
467
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000468static int ich_spi_read_page(struct flashchip *flash, uint8_t * buf, int offset, int maxdata)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000469{
470 int page_size = flash->page_size;
471 uint32_t remaining = flash->page_size;
472 int a;
473
Stefan Reinauera9424d52008-06-27 16:28:34 +0000474 printf_debug("ich_spi_read_page: offset=%d, number=%d, buf=%p\n",
475 offset, page_size, buf);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000476
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000477 for (a = 0; a < page_size; a += maxdata) {
478 if (remaining < maxdata) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000479
480 if (run_opcode
481 (1, curopcodes->opcode[1],
Stefan Reinauera9424d52008-06-27 16:28:34 +0000482 offset + (page_size - remaining), remaining,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000483 &buf[page_size - remaining]) != 0) {
484 printf_debug("Error reading");
485 return 1;
486 }
487 remaining = 0;
488 } else {
489 if (run_opcode
490 (1, curopcodes->opcode[1],
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000491 offset + (page_size - remaining), maxdata,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000492 &buf[page_size - remaining]) != 0) {
493 printf_debug("Error reading");
494 return 1;
495 }
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000496 remaining -= maxdata;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000497 }
498 }
499
500 return 0;
501}
502
503static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000504 int offset, int maxdata)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000505{
506 int page_size = flash->page_size;
507 uint32_t remaining = page_size;
508 int a;
509
Stefan Reinauera9424d52008-06-27 16:28:34 +0000510 printf_debug("ich_spi_write_page: offset=%d, number=%d, buf=%p\n",
511 offset, page_size, bytes);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000512
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000513 for (a = 0; a < page_size; a += maxdata) {
514 if (remaining < maxdata) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000515 if (run_opcode
516 (0, curopcodes->opcode[0],
Stefan Reinauera9424d52008-06-27 16:28:34 +0000517 offset + (page_size - remaining), remaining,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000518 &bytes[page_size - remaining]) != 0) {
519 printf_debug("Error writing");
520 return 1;
521 }
522 remaining = 0;
523 } else {
524 if (run_opcode
525 (0, curopcodes->opcode[0],
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000526 offset + (page_size - remaining), maxdata,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000527 &bytes[page_size - remaining]) != 0) {
528 printf_debug("Error writing");
529 return 1;
530 }
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000531 remaining -= maxdata;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000532 }
533 }
534
535 return 0;
536}
537
Dominik Geyerb46acba2008-05-16 12:55:55 +0000538int ich_spi_read(struct flashchip *flash, uint8_t * buf)
539{
540 int i, rc = 0;
541 int total_size = flash->total_size * 1024;
542 int page_size = flash->page_size;
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000543 int maxdata = 64;
544
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000545 if (flashbus == BUS_TYPE_VIA_SPI) {
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000546 maxdata = 16;
547 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000548
549 for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
550 rc = ich_spi_read_page(flash, (void *)(buf + i * page_size),
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000551 i * page_size, maxdata);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000552 }
553
554 return rc;
555}
556
Dominik Geyerb46acba2008-05-16 12:55:55 +0000557int ich_spi_write(struct flashchip *flash, uint8_t * buf)
558{
559 int i, j, rc = 0;
560 int total_size = flash->total_size * 1024;
561 int page_size = flash->page_size;
562 int erase_size = 64 * 1024;
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000563 int maxdata = 64;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000564
565 spi_disable_blockprotect();
566
567 printf("Programming page: \n");
568
569 for (i = 0; i < total_size / erase_size; i++) {
570 rc = ich_spi_erase_block(flash, i * erase_size);
571 if (rc) {
572 printf("Error erasing block at 0x%x\n", i);
573 break;
574 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000575
Peter Stuge6a214162008-07-07 05:14:06 +0000576 if (flashbus == BUS_TYPE_VIA_SPI)
577 maxdata = 16;
578
Dominik Geyerb46acba2008-05-16 12:55:55 +0000579 for (j = 0; j < erase_size / page_size; j++) {
580 ich_spi_write_page(flash, (void *)(buf + (i * erase_size) + (j * page_size)),
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000581 (i * erase_size) + (j * page_size), maxdata);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000582 }
583 }
584
585 printf("\n");
586
587 return rc;
588}
589
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000590int ich_spi_command(unsigned int writecnt, unsigned int readcnt,
591 const unsigned char *writearr, unsigned char *readarr)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000592{
593 int a;
594 int opcode_index = -1;
595 const unsigned char cmd = *writearr;
596 OPCODE *opcode;
597 uint32_t addr = 0;
598 uint8_t *data;
599 int count;
600
601 /* program opcodes if not already done */
602 if (curopcodes == NULL) {
Carl-Daniel Hailfinger10693352008-06-29 10:57:13 +0000603 printf_debug("Programming OPCODES... ");
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000604 curopcodes = &O_ST_M25P;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000605 program_opcodes(curopcodes);
Carl-Daniel Hailfinger10693352008-06-29 10:57:13 +0000606 printf_debug("done\n");
Dominik Geyerb46acba2008-05-16 12:55:55 +0000607 }
608
609 /* find cmd in opcodes-table */
610 for (a = 0; a < 8; a++) {
611 if ((curopcodes->opcode[a]).opcode == cmd) {
612 opcode_index = a;
613 break;
614 }
615 }
616
617 /* unknown / not programmed command */
618 if (opcode_index == -1) {
619 printf_debug("Invalid OPCODE 0x%02x\n", cmd);
620 return 1;
621 }
622
623 opcode = &(curopcodes->opcode[opcode_index]);
624
625 /* if opcode-type requires an address */
626 if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS ||
627 opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000628 addr = (writearr[1] << 16) |
629 (writearr[2] << 8) | (writearr[3] << 0);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000630 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000631
Dominik Geyerb46acba2008-05-16 12:55:55 +0000632 /* translate read/write array/count */
633 if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000634 data = (uint8_t *) (writearr + 1);
635 count = writecnt - 1;
636 } else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
637 data = (uint8_t *) (writearr + 4);
638 count = writecnt - 4;
639 } else {
640 data = (uint8_t *) readarr;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000641 count = readcnt;
642 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000643
Dominik Geyerb46acba2008-05-16 12:55:55 +0000644 if (run_opcode(opcode_index, *opcode, addr, count, data) != 0) {
645 printf_debug("run OPCODE 0x%02x failed\n", opcode->opcode);
646 return 1;
647 }
648
649 return 0;
650}