blob: 91a3842b2f359d486187bb07522a482bf5d1c207 [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 Reinauera9424d52008-06-27 16:28:34 +0000134 regval = *(volatile uint32_t *) ((uint8_t *) ich_spibar + X);
135 return regval;
136}
137
138static inline uint16_t REGREAD16(int X)
139{
140 volatile uint16_t regval;
141 regval = *(volatile uint16_t *) ((uint8_t *) ich_spibar + X);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000142 return regval;
143}
144
145#define REGWRITE32(X,Y) (*(uint32_t *)((uint8_t *)ich_spibar+X)=Y)
146#define REGWRITE16(X,Y) (*(uint16_t *)((uint8_t *)ich_spibar+X)=Y)
147#define REGWRITE8(X,Y) (*(uint8_t *)((uint8_t *)ich_spibar+X)=Y)
148
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;
178 uint16_t temp16;
179 uint32_t temp32;
180
181 /* Program Prefix Opcodes */
182 temp16 = 0;
183 /* 0:7 Prefix Opcode 1 */
184 temp16 = (op->preop[0]);
185 /* 8:16 Prefix Opcode 2 */
186 temp16 |= ((uint16_t) op->preop[1]) << 8;
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000187 if ((ich7_detected) || (viaspi_detected)) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000188 REGWRITE16(ICH7_REG_PREOP, temp16);
189 } else if (ich9_detected) {
190 REGWRITE16(ICH9_REG_PREOP, temp16);
191 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000192
Stefan Reinauera9424d52008-06-27 16:28:34 +0000193 /* Program Opcode Types 0 - 7 */
Dominik Geyerb46acba2008-05-16 12:55:55 +0000194 temp16 = 0;
195 for (a = 0; a < 8; a++) {
196 temp16 |= ((uint16_t) op->opcode[a].spi_type) << (a * 2);
197 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000198
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000199 if ((ich7_detected) || (viaspi_detected)) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000200 REGWRITE16(ICH7_REG_OPTYPE, temp16);
201 } else if (ich9_detected) {
202 REGWRITE16(ICH9_REG_OPTYPE, temp16);
203 }
204
205
206 /* Program Allowable Opcodes 0 - 3 */
Dominik Geyerb46acba2008-05-16 12:55:55 +0000207 temp32 = 0;
208 for (a = 0; a < 4; a++) {
209 temp32 |= ((uint32_t) op->opcode[a].opcode) << (a * 8);
210 }
Stefan Reinauera9424d52008-06-27 16:28:34 +0000211
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000212 if ((ich7_detected) || (viaspi_detected)) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000213 REGWRITE32(ICH7_REG_OPMENU, temp32);
214 } else if (ich9_detected) {
215 REGWRITE32(ICH9_REG_OPMENU, temp32);
216 }
217
Dominik Geyerb46acba2008-05-16 12:55:55 +0000218
219 /*Program Allowable Opcodes 4 - 7 */
220 temp32 = 0;
221 for (a = 4; a < 8; a++) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000222 temp32 |=
223 ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000224 }
Stefan Reinauera9424d52008-06-27 16:28:34 +0000225
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000226 if ((ich7_detected) || (viaspi_detected)) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000227 REGWRITE32(ICH7_REG_OPMENU + 4, temp32);
228 } else if (ich9_detected) {
229 REGWRITE32(ICH9_REG_OPMENU + 4, temp32);
230 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000231
232 return 0;
233}
234
Stefan Reinauera9424d52008-06-27 16:28:34 +0000235static int ich7_run_opcode(uint8_t nr, OPCODE op, uint32_t offset,
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000236 uint8_t datalength, uint8_t * data, int maxdata)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000237{
238 int write_cmd = 0;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000239 int timeout;
Peter Stuge7e2c0792008-06-29 01:30:41 +0000240 uint32_t temp32 = 0;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000241 uint16_t temp16;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000242 uint32_t a;
243
244 /* Is it a write command? */
245 if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
246 || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
247 write_cmd = 1;
248 }
249
250 /* Programm Offset in Flash into FADDR */
Stefan Reinauera9424d52008-06-27 16:28:34 +0000251 REGWRITE32(ICH7_REG_SPIA, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */
Dominik Geyerb46acba2008-05-16 12:55:55 +0000252
253 /* Program data into FDATA0 to N */
254 if (write_cmd && (datalength != 0)) {
255 temp32 = 0;
256 for (a = 0; a < datalength; a++) {
257 if ((a % 4) == 0) {
258 temp32 = 0;
259 }
260
261 temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
262
263 if ((a % 4) == 3) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000264 REGWRITE32(ICH7_REG_SPID0 + (a - (a % 4)),
265 temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000266 }
267 }
268 if (((a - 1) % 4) != 3) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000269 REGWRITE32(ICH7_REG_SPID0 +
270 ((a - 1) - ((a - 1) % 4)), temp32);
271 }
272
273 }
274
275 /* Assemble SPIS */
276 temp16 = 0;
277 /* clear error status registers */
278 temp16 |= (SPIS_CDS + SPIS_FCERR);
279 REGWRITE16(ICH7_REG_SPIS, temp16);
280
281 /* Assemble SPIC */
282 temp16 = 0;
283
284 if (datalength != 0) {
285 temp16 |= SPIC_DS;
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000286 temp16 |= ((uint32_t) ((datalength - 1) & (maxdata - 1))) << 8;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000287 }
288
289 /* Select opcode */
290 temp16 |= ((uint16_t) (nr & 0x07)) << 4;
291
292 /* Handle Atomic */
293 if (op.atomic != 0) {
294 /* Select atomic command */
295 temp16 |= SPIC_ACS;
296 /* Selct prefix opcode */
297 if ((op.atomic - 1) == 1) {
298 /*Select prefix opcode 2 */
299 temp16 |= SPIC_SPOP;
300 }
301 }
302
303 /* Start */
304 temp16 |= SPIC_SCGO;
305
306 /* write it */
307 REGWRITE16(ICH7_REG_SPIC, temp16);
308
309 /* wait for cycle complete */
310 timeout = 1000 * 60; // 60s is a looong timeout.
311 while (((REGREAD16(ICH7_REG_SPIS) & SPIS_CDS) == 0) && --timeout) {
312 myusec_delay(1000);
313 }
314 if (!timeout) {
315 printf_debug("timeout\n");
316 }
317
318 if ((REGREAD16(ICH7_REG_SPIS) & SPIS_FCERR) != 0) {
319 printf_debug("Transaction error!\n");
320 return 1;
321 }
322
323 if ((!write_cmd) && (datalength != 0)) {
324 for (a = 0; a < datalength; a++) {
325 if ((a % 4) == 0) {
326 temp32 = REGREAD32(ICH7_REG_SPID0 + (a));
327 }
328
329 data[a] =
330 (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
331 >> ((a % 4) * 8);
332 }
333 }
334
335 return 0;
336}
337
338
339static int ich9_run_opcode(uint8_t nr, OPCODE op, uint32_t offset,
340 uint8_t datalength, uint8_t * data)
341{
342 int write_cmd = 0;
343 uint32_t temp32;
344 uint32_t a;
345
346 /* Is it a write command? */
347 if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
348 || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
349 write_cmd = 1;
350 }
351
352 /* Programm Offset in Flash into FADDR */
353 REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */
354
355 /* Program data into FDATA0 to N */
356 if (write_cmd && (datalength != 0)) {
357 temp32 = 0;
358 for (a = 0; a < datalength; a++) {
359 if ((a % 4) == 0) {
360 temp32 = 0;
361 }
362
363 temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
364
365 if ((a % 4) == 3) {
366 REGWRITE32(ICH9_REG_FDATA0 + (a - (a % 4)),
367 temp32);
368 }
369 }
370 if (((a - 1) % 4) != 3) {
371 REGWRITE32(ICH9_REG_FDATA0 +
372 ((a - 1) - ((a - 1) % 4)), temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000373 }
374
375 }
376
377 /* Assemble SSFS + SSFC */
378 temp32 = 0;
379
380 /* clear error status registers */
381 temp32 |= (SSFS_CDS + SSFS_FCERR);
382 /* USE 20 MhZ */
383 temp32 |= SSFC_SCF_20MHZ;
384
385 if (datalength != 0) {
386 uint32_t datatemp;
387 temp32 |= SSFC_DS;
388 datatemp = ((uint32_t) ((datalength - 1) & 0x3f)) << (8 + 8);
389 temp32 |= datatemp;
390 }
391
392 /* Select opcode */
393 temp32 |= ((uint32_t) (nr & 0x07)) << (8 + 4);
394
395 /* Handle Atomic */
396 if (op.atomic != 0) {
397 /* Select atomic command */
398 temp32 |= SSFC_ACS;
399 /* Selct prefix opcode */
400 if ((op.atomic - 1) == 1) {
401 /*Select prefix opcode 2 */
402 temp32 |= SSFC_SPOP;
403 }
404 }
405
406 /* Start */
407 temp32 |= SSFC_SCGO;
408
409 /* write it */
Stefan Reinauera9424d52008-06-27 16:28:34 +0000410 REGWRITE32(ICH9_REG_SSFS, temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000411
412 /*wait for cycle complete */
Stefan Reinauera9424d52008-06-27 16:28:34 +0000413 while ((REGREAD32(ICH9_REG_SSFS) & SSFS_CDS) == 0) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000414 /*TODO; Do something that this can't lead into an endless loop. but some
415 * commands may cause this to be last more than 30 seconds */
416 }
417
Stefan Reinauera9424d52008-06-27 16:28:34 +0000418 if ((REGREAD32(ICH9_REG_SSFS) & SSFS_FCERR) != 0) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000419 printf_debug("Transaction error!\n");
420 return 1;
421 }
422
423 if ((!write_cmd) && (datalength != 0)) {
424 for (a = 0; a < datalength; a++) {
425 if ((a % 4) == 0) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000426 temp32 = REGREAD32(ICH9_REG_FDATA0 + (a));
Dominik Geyerb46acba2008-05-16 12:55:55 +0000427 }
428
429 data[a] =
Stefan Reinauera9424d52008-06-27 16:28:34 +0000430 (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
431 >> ((a % 4) * 8);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000432 }
433 }
434
435 return 0;
436}
437
Stefan Reinauera9424d52008-06-27 16:28:34 +0000438static int run_opcode(uint8_t nr, OPCODE op, uint32_t offset,
439 uint8_t datalength, uint8_t * data)
440{
441 if (ich7_detected)
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000442 return ich7_run_opcode(nr, op, offset, datalength, data, 64);
443 else if (viaspi_detected)
444 return ich7_run_opcode(nr, op, offset, datalength, data, 16);
445 else if (ich9_detected)
Stefan Reinauera9424d52008-06-27 16:28:34 +0000446 return ich9_run_opcode(nr, op, offset, datalength, data);
Stefan Reinauera9424d52008-06-27 16:28:34 +0000447
448 /* If we ever get here, something really weird happened */
449 return -1;
450}
451
Dominik Geyerb46acba2008-05-16 12:55:55 +0000452static int ich_spi_erase_block(struct flashchip *flash, int offset)
453{
Stefan Reinauera9424d52008-06-27 16:28:34 +0000454 printf_debug("ich_spi_erase_block: offset=%d, sectors=%d\n",
455 offset, 1);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000456
457 if (run_opcode(2, curopcodes->opcode[2], offset, 0, NULL) != 0) {
458 printf_debug("Error erasing sector at 0x%x", offset);
459 return -1;
460 }
461
462 printf("DONE BLOCK 0x%x\n", offset);
463
464 return 0;
465}
466
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000467static int ich_spi_read_page(struct flashchip *flash, uint8_t * buf, int offset, int maxdata)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000468{
469 int page_size = flash->page_size;
470 uint32_t remaining = flash->page_size;
471 int a;
472
Stefan Reinauera9424d52008-06-27 16:28:34 +0000473 printf_debug("ich_spi_read_page: offset=%d, number=%d, buf=%p\n",
474 offset, page_size, buf);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000475
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000476 for (a = 0; a < page_size; a += maxdata) {
477 if (remaining < maxdata) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000478
479 if (run_opcode
480 (1, curopcodes->opcode[1],
Stefan Reinauera9424d52008-06-27 16:28:34 +0000481 offset + (page_size - remaining), remaining,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000482 &buf[page_size - remaining]) != 0) {
483 printf_debug("Error reading");
484 return 1;
485 }
486 remaining = 0;
487 } else {
488 if (run_opcode
489 (1, curopcodes->opcode[1],
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000490 offset + (page_size - remaining), maxdata,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000491 &buf[page_size - remaining]) != 0) {
492 printf_debug("Error reading");
493 return 1;
494 }
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000495 remaining -= maxdata;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000496 }
497 }
498
499 return 0;
500}
501
502static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000503 int offset, int maxdata)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000504{
505 int page_size = flash->page_size;
506 uint32_t remaining = page_size;
507 int a;
508
Stefan Reinauera9424d52008-06-27 16:28:34 +0000509 printf_debug("ich_spi_write_page: offset=%d, number=%d, buf=%p\n",
510 offset, page_size, bytes);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000511
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000512 for (a = 0; a < page_size; a += maxdata) {
513 if (remaining < maxdata) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000514 if (run_opcode
515 (0, curopcodes->opcode[0],
Stefan Reinauera9424d52008-06-27 16:28:34 +0000516 offset + (page_size - remaining), remaining,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000517 &bytes[page_size - remaining]) != 0) {
518 printf_debug("Error writing");
519 return 1;
520 }
521 remaining = 0;
522 } else {
523 if (run_opcode
524 (0, curopcodes->opcode[0],
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000525 offset + (page_size - remaining), maxdata,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000526 &bytes[page_size - remaining]) != 0) {
527 printf_debug("Error writing");
528 return 1;
529 }
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000530 remaining -= maxdata;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000531 }
532 }
533
534 return 0;
535}
536
Dominik Geyerb46acba2008-05-16 12:55:55 +0000537int ich_spi_read(struct flashchip *flash, uint8_t * buf)
538{
539 int i, rc = 0;
540 int total_size = flash->total_size * 1024;
541 int page_size = flash->page_size;
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000542 int maxdata = 64;
543
544 if (viaspi_detected) {
545 maxdata = 16;
546 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000547
548 for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
549 rc = ich_spi_read_page(flash, (void *)(buf + i * page_size),
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000550 i * page_size, maxdata);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000551 }
552
553 return rc;
554}
555
Dominik Geyerb46acba2008-05-16 12:55:55 +0000556int ich_spi_write(struct flashchip *flash, uint8_t * buf)
557{
558 int i, j, rc = 0;
559 int total_size = flash->total_size * 1024;
560 int page_size = flash->page_size;
561 int erase_size = 64 * 1024;
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000562 int maxdata = 64;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000563
564 spi_disable_blockprotect();
565
566 printf("Programming page: \n");
567
568 for (i = 0; i < total_size / erase_size; i++) {
569 rc = ich_spi_erase_block(flash, i * erase_size);
570 if (rc) {
571 printf("Error erasing block at 0x%x\n", i);
572 break;
573 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000574
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000575 if (viaspi_detected) {
576 maxdata = 16;
577 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000578 for (j = 0; j < erase_size / page_size; j++) {
579 ich_spi_write_page(flash, (void *)(buf + (i * erase_size) + (j * page_size)),
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000580 (i * erase_size) + (j * page_size), maxdata);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000581 }
582 }
583
584 printf("\n");
585
586 return rc;
587}
588
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000589int ich_spi_command(unsigned int writecnt, unsigned int readcnt,
590 const unsigned char *writearr, unsigned char *readarr)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000591{
592 int a;
593 int opcode_index = -1;
594 const unsigned char cmd = *writearr;
595 OPCODE *opcode;
596 uint32_t addr = 0;
597 uint8_t *data;
598 int count;
599
600 /* program opcodes if not already done */
601 if (curopcodes == NULL) {
Carl-Daniel Hailfinger10693352008-06-29 10:57:13 +0000602 printf_debug("Programming OPCODES... ");
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000603 curopcodes = &O_ST_M25P;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000604 program_opcodes(curopcodes);
Carl-Daniel Hailfinger10693352008-06-29 10:57:13 +0000605 printf_debug("done\n");
Dominik Geyerb46acba2008-05-16 12:55:55 +0000606 }
607
608 /* find cmd in opcodes-table */
609 for (a = 0; a < 8; a++) {
610 if ((curopcodes->opcode[a]).opcode == cmd) {
611 opcode_index = a;
612 break;
613 }
614 }
615
616 /* unknown / not programmed command */
617 if (opcode_index == -1) {
618 printf_debug("Invalid OPCODE 0x%02x\n", cmd);
619 return 1;
620 }
621
622 opcode = &(curopcodes->opcode[opcode_index]);
623
624 /* if opcode-type requires an address */
625 if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS ||
626 opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000627 addr = (writearr[1] << 16) |
628 (writearr[2] << 8) | (writearr[3] << 0);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000629 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000630
Dominik Geyerb46acba2008-05-16 12:55:55 +0000631 /* translate read/write array/count */
632 if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000633 data = (uint8_t *) (writearr + 1);
634 count = writecnt - 1;
635 } else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
636 data = (uint8_t *) (writearr + 4);
637 count = writecnt - 4;
638 } else {
639 data = (uint8_t *) readarr;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000640 count = readcnt;
641 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000642
Dominik Geyerb46acba2008-05-16 12:55:55 +0000643 if (run_opcode(opcode_index, *opcode, addr, count, data) != 0) {
644 printf_debug("run OPCODE 0x%02x failed\n", opcode->opcode);
645 return 1;
646 }
647
648 return 0;
649}