blob: d6c0157e138cb2da89b8654a8dad5eb625dcc4a0 [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
44#define MAXDATABYTES 0x40
45
Stefan Reinauera9424d52008-06-27 16:28:34 +000046/* ICH9 controller register definition */
47#define ICH9_REG_FADDR 0x08 /* 32 Bits */
48#define ICH9_REG_FDATA0 0x10 /* 64 Bytes */
49
50#define ICH9_REG_SSFS 0x90 /* 08 Bits */
Dominik Geyerb46acba2008-05-16 12:55:55 +000051#define SSFS_SCIP 0x00000001
52#define SSFS_CDS 0x00000004
53#define SSFS_FCERR 0x00000008
54#define SSFS_AEL 0x00000010
Stefan Reinauera9424d52008-06-27 16:28:34 +000055
56#define ICH9_REG_SSFC 0x91 /* 24 Bits */
Dominik Geyerb46acba2008-05-16 12:55:55 +000057#define SSFC_SCGO 0x00000200
58#define SSFC_ACS 0x00000400
59#define SSFC_SPOP 0x00000800
60#define SSFC_COP 0x00001000
61#define SSFC_DBC 0x00010000
62#define SSFC_DS 0x00400000
63#define SSFC_SME 0x00800000
64#define SSFC_SCF 0x01000000
65#define SSFC_SCF_20MHZ 0x00000000
66#define SSFC_SCF_33MHZ 0x01000000
Stefan Reinauera9424d52008-06-27 16:28:34 +000067
68#define ICH9_REG_PREOP 0x94 /* 16 Bits */
69#define ICH9_REG_OPTYPE 0x96 /* 16 Bits */
70#define ICH9_REG_OPMENU 0x98 /* 64 Bits */
Dominik Geyerb46acba2008-05-16 12:55:55 +000071
72// ICH9R SPI commands
73#define SPI_OPCODE_TYPE_READ_NO_ADDRESS 0
74#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS 1
75#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS 2
76#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS 3
77
Stefan Reinauera9424d52008-06-27 16:28:34 +000078// ICH7 registers
79#define ICH7_REG_SPIS 0x00 /* 16 Bits */
80#define SPIS_SCIP 0x00000001
81#define SPIS_CDS 0x00000004
82#define SPIS_FCERR 0x00000008
83
84#define ICH7_REG_SPIC 0x02 /* 16 Bits */
85#define SPIC_SCGO 0x0002
86#define SPIC_ACS 0x0004
87#define SPIC_SPOP 0x0008
88#define SPIC_DS 0x4000
89
90#define ICH7_REG_SPIA 0x04 /* 32 Bits */
91#define ICH7_REG_SPID0 0x08 /* 64 Bytes */
92#define ICH7_REG_PREOP 0x54 /* 16 Bits */
93#define ICH7_REG_OPTYPE 0x56 /* 16 Bits */
94#define ICH7_REG_OPMENU 0x58 /* 64 Bits */
95
Dominik Geyerb46acba2008-05-16 12:55:55 +000096typedef struct _OPCODE {
97 uint8_t opcode; //This commands spi opcode
98 uint8_t spi_type; //This commands spi type
99 uint8_t atomic; //Use preop: (0: none, 1: preop0, 2: preop1
100} OPCODE;
101
102/* Opcode definition:
103 * Preop 1: Write Enable
104 * Preop 2: Write Status register enable
105 *
106 * OP 0: Write address
107 * OP 1: Read Address
108 * OP 2: ERASE block
109 * OP 3: Read Status register
110 * OP 4: Read ID
111 * OP 5: Write Status register
112 * OP 6: chip private (read JDEC id)
113 * OP 7: Chip erase
114 */
115typedef struct _OPCODES {
116 uint8_t preop[2];
117 OPCODE opcode[8];
118} OPCODES;
119
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000120static OPCODES *curopcodes = NULL;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000121
122/* HW access functions */
123static inline uint32_t REGREAD32(int X)
124{
125 volatile uint32_t regval;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000126 regval = *(volatile uint32_t *) ((uint8_t *) ich_spibar + X);
127 return regval;
128}
129
130static inline uint16_t REGREAD16(int X)
131{
132 volatile uint16_t regval;
133 regval = *(volatile uint16_t *) ((uint8_t *) ich_spibar + X);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000134 return regval;
135}
136
137#define REGWRITE32(X,Y) (*(uint32_t *)((uint8_t *)ich_spibar+X)=Y)
138#define REGWRITE16(X,Y) (*(uint16_t *)((uint8_t *)ich_spibar+X)=Y)
139#define REGWRITE8(X,Y) (*(uint8_t *)((uint8_t *)ich_spibar+X)=Y)
140
Dominik Geyerb46acba2008-05-16 12:55:55 +0000141/* Common SPI functions */
142static int program_opcodes(OPCODES * op);
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000143static int run_opcode(uint8_t nr, OPCODE op, uint32_t offset,
144 uint8_t datalength, uint8_t * data);
145static int ich_spi_read_page(struct flashchip *flash, uint8_t * buf,
Stefan Reinauera9424d52008-06-27 16:28:34 +0000146 int offset);
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000147static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
Stefan Reinauera9424d52008-06-27 16:28:34 +0000148 int offset);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000149static int ich_spi_erase_block(struct flashchip *flash, int offset);
150
Dominik Geyerb46acba2008-05-16 12:55:55 +0000151OPCODES O_ST_M25P = {
152 {
153 JEDEC_WREN,
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000154 0},
Dominik Geyerb46acba2008-05-16 12:55:55 +0000155 {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000156 {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Write Byte
157 {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data
158 {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Erase Sector
159 {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg
160 {JEDEC_RES, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Resume Deep Power-Down
161 {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Write Status Register
162 {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID
163 {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Bulk erase
164 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000165};
166
Dominik Geyerb46acba2008-05-16 12:55:55 +0000167int program_opcodes(OPCODES * op)
168{
169 uint8_t a;
170 uint16_t temp16;
171 uint32_t temp32;
172
173 /* Program Prefix Opcodes */
174 temp16 = 0;
175 /* 0:7 Prefix Opcode 1 */
176 temp16 = (op->preop[0]);
177 /* 8:16 Prefix Opcode 2 */
178 temp16 |= ((uint16_t) op->preop[1]) << 8;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000179 if (ich7_detected) {
180 REGWRITE16(ICH7_REG_PREOP, temp16);
181 } else if (ich9_detected) {
182 REGWRITE16(ICH9_REG_PREOP, temp16);
183 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000184
Stefan Reinauera9424d52008-06-27 16:28:34 +0000185 /* Program Opcode Types 0 - 7 */
Dominik Geyerb46acba2008-05-16 12:55:55 +0000186 temp16 = 0;
187 for (a = 0; a < 8; a++) {
188 temp16 |= ((uint16_t) op->opcode[a].spi_type) << (a * 2);
189 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000190
Stefan Reinauera9424d52008-06-27 16:28:34 +0000191 if (ich7_detected) {
192 REGWRITE16(ICH7_REG_OPTYPE, temp16);
193 } else if (ich9_detected) {
194 REGWRITE16(ICH9_REG_OPTYPE, temp16);
195 }
196
197
198 /* Program Allowable Opcodes 0 - 3 */
Dominik Geyerb46acba2008-05-16 12:55:55 +0000199 temp32 = 0;
200 for (a = 0; a < 4; a++) {
201 temp32 |= ((uint32_t) op->opcode[a].opcode) << (a * 8);
202 }
Stefan Reinauera9424d52008-06-27 16:28:34 +0000203
204 if (ich7_detected) {
205 REGWRITE32(ICH7_REG_OPMENU, temp32);
206 } else if (ich9_detected) {
207 REGWRITE32(ICH9_REG_OPMENU, temp32);
208 }
209
Dominik Geyerb46acba2008-05-16 12:55:55 +0000210
211 /*Program Allowable Opcodes 4 - 7 */
212 temp32 = 0;
213 for (a = 4; a < 8; a++) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000214 temp32 |=
215 ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000216 }
Stefan Reinauera9424d52008-06-27 16:28:34 +0000217
218 if (ich7_detected) {
219 REGWRITE32(ICH7_REG_OPMENU + 4, temp32);
220 } else if (ich9_detected) {
221 REGWRITE32(ICH9_REG_OPMENU + 4, temp32);
222 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000223
224 return 0;
225}
226
Stefan Reinauera9424d52008-06-27 16:28:34 +0000227static int ich7_run_opcode(uint8_t nr, OPCODE op, uint32_t offset,
228 uint8_t datalength, uint8_t * data)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000229{
230 int write_cmd = 0;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000231 int timeout;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000232 uint32_t temp32;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000233 uint16_t temp16;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000234 uint32_t a;
235
236 /* Is it a write command? */
237 if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
238 || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
239 write_cmd = 1;
240 }
241
242 /* Programm Offset in Flash into FADDR */
Stefan Reinauera9424d52008-06-27 16:28:34 +0000243 REGWRITE32(ICH7_REG_SPIA, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */
Dominik Geyerb46acba2008-05-16 12:55:55 +0000244
245 /* Program data into FDATA0 to N */
246 if (write_cmd && (datalength != 0)) {
247 temp32 = 0;
248 for (a = 0; a < datalength; a++) {
249 if ((a % 4) == 0) {
250 temp32 = 0;
251 }
252
253 temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
254
255 if ((a % 4) == 3) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000256 REGWRITE32(ICH7_REG_SPID0 + (a - (a % 4)),
257 temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000258 }
259 }
260 if (((a - 1) % 4) != 3) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000261 REGWRITE32(ICH7_REG_SPID0 +
262 ((a - 1) - ((a - 1) % 4)), temp32);
263 }
264
265 }
266
267 /* Assemble SPIS */
268 temp16 = 0;
269 /* clear error status registers */
270 temp16 |= (SPIS_CDS + SPIS_FCERR);
271 REGWRITE16(ICH7_REG_SPIS, temp16);
272
273 /* Assemble SPIC */
274 temp16 = 0;
275
276 if (datalength != 0) {
277 temp16 |= SPIC_DS;
278 temp16 |= ((uint16_t) ((datalength - 1) & 0x3f)) << 8;
279 }
280
281 /* Select opcode */
282 temp16 |= ((uint16_t) (nr & 0x07)) << 4;
283
284 /* Handle Atomic */
285 if (op.atomic != 0) {
286 /* Select atomic command */
287 temp16 |= SPIC_ACS;
288 /* Selct prefix opcode */
289 if ((op.atomic - 1) == 1) {
290 /*Select prefix opcode 2 */
291 temp16 |= SPIC_SPOP;
292 }
293 }
294
295 /* Start */
296 temp16 |= SPIC_SCGO;
297
298 /* write it */
299 REGWRITE16(ICH7_REG_SPIC, temp16);
300
301 /* wait for cycle complete */
302 timeout = 1000 * 60; // 60s is a looong timeout.
303 while (((REGREAD16(ICH7_REG_SPIS) & SPIS_CDS) == 0) && --timeout) {
304 myusec_delay(1000);
305 }
306 if (!timeout) {
307 printf_debug("timeout\n");
308 }
309
310 if ((REGREAD16(ICH7_REG_SPIS) & SPIS_FCERR) != 0) {
311 printf_debug("Transaction error!\n");
312 return 1;
313 }
314
315 if ((!write_cmd) && (datalength != 0)) {
316 for (a = 0; a < datalength; a++) {
317 if ((a % 4) == 0) {
318 temp32 = REGREAD32(ICH7_REG_SPID0 + (a));
319 }
320
321 data[a] =
322 (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
323 >> ((a % 4) * 8);
324 }
325 }
326
327 return 0;
328}
329
330
331static int ich9_run_opcode(uint8_t nr, OPCODE op, uint32_t offset,
332 uint8_t datalength, uint8_t * data)
333{
334 int write_cmd = 0;
335 uint32_t temp32;
336 uint32_t a;
337
338 /* Is it a write command? */
339 if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
340 || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
341 write_cmd = 1;
342 }
343
344 /* Programm Offset in Flash into FADDR */
345 REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */
346
347 /* Program data into FDATA0 to N */
348 if (write_cmd && (datalength != 0)) {
349 temp32 = 0;
350 for (a = 0; a < datalength; a++) {
351 if ((a % 4) == 0) {
352 temp32 = 0;
353 }
354
355 temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
356
357 if ((a % 4) == 3) {
358 REGWRITE32(ICH9_REG_FDATA0 + (a - (a % 4)),
359 temp32);
360 }
361 }
362 if (((a - 1) % 4) != 3) {
363 REGWRITE32(ICH9_REG_FDATA0 +
364 ((a - 1) - ((a - 1) % 4)), temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000365 }
366
367 }
368
369 /* Assemble SSFS + SSFC */
370 temp32 = 0;
371
372 /* clear error status registers */
373 temp32 |= (SSFS_CDS + SSFS_FCERR);
374 /* USE 20 MhZ */
375 temp32 |= SSFC_SCF_20MHZ;
376
377 if (datalength != 0) {
378 uint32_t datatemp;
379 temp32 |= SSFC_DS;
380 datatemp = ((uint32_t) ((datalength - 1) & 0x3f)) << (8 + 8);
381 temp32 |= datatemp;
382 }
383
384 /* Select opcode */
385 temp32 |= ((uint32_t) (nr & 0x07)) << (8 + 4);
386
387 /* Handle Atomic */
388 if (op.atomic != 0) {
389 /* Select atomic command */
390 temp32 |= SSFC_ACS;
391 /* Selct prefix opcode */
392 if ((op.atomic - 1) == 1) {
393 /*Select prefix opcode 2 */
394 temp32 |= SSFC_SPOP;
395 }
396 }
397
398 /* Start */
399 temp32 |= SSFC_SCGO;
400
401 /* write it */
Stefan Reinauera9424d52008-06-27 16:28:34 +0000402 REGWRITE32(ICH9_REG_SSFS, temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000403
404 /*wait for cycle complete */
Stefan Reinauera9424d52008-06-27 16:28:34 +0000405 while ((REGREAD32(ICH9_REG_SSFS) & SSFS_CDS) == 0) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000406 /*TODO; Do something that this can't lead into an endless loop. but some
407 * commands may cause this to be last more than 30 seconds */
408 }
409
Stefan Reinauera9424d52008-06-27 16:28:34 +0000410 if ((REGREAD32(ICH9_REG_SSFS) & SSFS_FCERR) != 0) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000411 printf_debug("Transaction error!\n");
412 return 1;
413 }
414
415 if ((!write_cmd) && (datalength != 0)) {
416 for (a = 0; a < datalength; a++) {
417 if ((a % 4) == 0) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000418 temp32 = REGREAD32(ICH9_REG_FDATA0 + (a));
Dominik Geyerb46acba2008-05-16 12:55:55 +0000419 }
420
421 data[a] =
Stefan Reinauera9424d52008-06-27 16:28:34 +0000422 (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
423 >> ((a % 4) * 8);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000424 }
425 }
426
427 return 0;
428}
429
Stefan Reinauera9424d52008-06-27 16:28:34 +0000430static int run_opcode(uint8_t nr, OPCODE op, uint32_t offset,
431 uint8_t datalength, uint8_t * data)
432{
433 if (ich7_detected)
434 return ich7_run_opcode(nr, op, offset, datalength, data);
435 else if (ich9_detected) {
436 return ich9_run_opcode(nr, op, offset, datalength, data);
437 }
438
439 /* If we ever get here, something really weird happened */
440 return -1;
441}
442
Dominik Geyerb46acba2008-05-16 12:55:55 +0000443static int ich_spi_erase_block(struct flashchip *flash, int offset)
444{
Stefan Reinauera9424d52008-06-27 16:28:34 +0000445 printf_debug("ich_spi_erase_block: offset=%d, sectors=%d\n",
446 offset, 1);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000447
448 if (run_opcode(2, curopcodes->opcode[2], offset, 0, NULL) != 0) {
449 printf_debug("Error erasing sector at 0x%x", offset);
450 return -1;
451 }
452
453 printf("DONE BLOCK 0x%x\n", offset);
454
455 return 0;
456}
457
Stefan Reinauera9424d52008-06-27 16:28:34 +0000458static int ich_spi_read_page(struct flashchip *flash, uint8_t * buf, int offset)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000459{
460 int page_size = flash->page_size;
461 uint32_t remaining = flash->page_size;
462 int a;
463
Stefan Reinauera9424d52008-06-27 16:28:34 +0000464 printf_debug("ich_spi_read_page: offset=%d, number=%d, buf=%p\n",
465 offset, page_size, buf);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000466
467 for (a = 0; a < page_size; a += MAXDATABYTES) {
468 if (remaining < MAXDATABYTES) {
469
470 if (run_opcode
471 (1, curopcodes->opcode[1],
Stefan Reinauera9424d52008-06-27 16:28:34 +0000472 offset + (page_size - remaining), remaining,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000473 &buf[page_size - remaining]) != 0) {
474 printf_debug("Error reading");
475 return 1;
476 }
477 remaining = 0;
478 } else {
479 if (run_opcode
480 (1, curopcodes->opcode[1],
Stefan Reinauera9424d52008-06-27 16:28:34 +0000481 offset + (page_size - remaining), MAXDATABYTES,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000482 &buf[page_size - remaining]) != 0) {
483 printf_debug("Error reading");
484 return 1;
485 }
486 remaining -= MAXDATABYTES;
487 }
488 }
489
490 return 0;
491}
492
493static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
Stefan Reinauera9424d52008-06-27 16:28:34 +0000494 int offset)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000495{
496 int page_size = flash->page_size;
497 uint32_t remaining = page_size;
498 int a;
499
Stefan Reinauera9424d52008-06-27 16:28:34 +0000500 printf_debug("ich_spi_write_page: offset=%d, number=%d, buf=%p\n",
501 offset, page_size, bytes);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000502
503 for (a = 0; a < page_size; a += MAXDATABYTES) {
504 if (remaining < MAXDATABYTES) {
505 if (run_opcode
506 (0, curopcodes->opcode[0],
Stefan Reinauera9424d52008-06-27 16:28:34 +0000507 offset + (page_size - remaining), remaining,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000508 &bytes[page_size - remaining]) != 0) {
509 printf_debug("Error writing");
510 return 1;
511 }
512 remaining = 0;
513 } else {
514 if (run_opcode
515 (0, curopcodes->opcode[0],
Stefan Reinauera9424d52008-06-27 16:28:34 +0000516 offset + (page_size - remaining), MAXDATABYTES,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000517 &bytes[page_size - remaining]) != 0) {
518 printf_debug("Error writing");
519 return 1;
520 }
521 remaining -= MAXDATABYTES;
522 }
523 }
524
525 return 0;
526}
527
Dominik Geyerb46acba2008-05-16 12:55:55 +0000528int ich_spi_read(struct flashchip *flash, uint8_t * buf)
529{
530 int i, rc = 0;
531 int total_size = flash->total_size * 1024;
532 int page_size = flash->page_size;
533
534 for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
535 rc = ich_spi_read_page(flash, (void *)(buf + i * page_size),
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000536 i * page_size);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000537 }
538
539 return rc;
540}
541
Dominik Geyerb46acba2008-05-16 12:55:55 +0000542int ich_spi_write(struct flashchip *flash, uint8_t * buf)
543{
544 int i, j, rc = 0;
545 int total_size = flash->total_size * 1024;
546 int page_size = flash->page_size;
547 int erase_size = 64 * 1024;
548
549 spi_disable_blockprotect();
550
551 printf("Programming page: \n");
552
553 for (i = 0; i < total_size / erase_size; i++) {
554 rc = ich_spi_erase_block(flash, i * erase_size);
555 if (rc) {
556 printf("Error erasing block at 0x%x\n", i);
557 break;
558 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000559
Dominik Geyerb46acba2008-05-16 12:55:55 +0000560 for (j = 0; j < erase_size / page_size; j++) {
561 ich_spi_write_page(flash, (void *)(buf + (i * erase_size) + (j * page_size)),
562 (i * erase_size) + (j * page_size));
563 }
564 }
565
566 printf("\n");
567
568 return rc;
569}
570
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000571int ich_spi_command(unsigned int writecnt, unsigned int readcnt,
572 const unsigned char *writearr, unsigned char *readarr)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000573{
574 int a;
575 int opcode_index = -1;
576 const unsigned char cmd = *writearr;
577 OPCODE *opcode;
578 uint32_t addr = 0;
579 uint8_t *data;
580 int count;
581
582 /* program opcodes if not already done */
583 if (curopcodes == NULL) {
584 printf_debug("Programming OPCODES\n");
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000585 curopcodes = &O_ST_M25P;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000586 program_opcodes(curopcodes);
587 }
588
589 /* find cmd in opcodes-table */
590 for (a = 0; a < 8; a++) {
591 if ((curopcodes->opcode[a]).opcode == cmd) {
592 opcode_index = a;
593 break;
594 }
595 }
596
597 /* unknown / not programmed command */
598 if (opcode_index == -1) {
599 printf_debug("Invalid OPCODE 0x%02x\n", cmd);
600 return 1;
601 }
602
603 opcode = &(curopcodes->opcode[opcode_index]);
604
605 /* if opcode-type requires an address */
606 if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS ||
607 opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000608 addr = (writearr[1] << 16) |
609 (writearr[2] << 8) | (writearr[3] << 0);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000610 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000611
Dominik Geyerb46acba2008-05-16 12:55:55 +0000612 /* translate read/write array/count */
613 if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000614 data = (uint8_t *) (writearr + 1);
615 count = writecnt - 1;
616 } else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
617 data = (uint8_t *) (writearr + 4);
618 count = writecnt - 4;
619 } else {
620 data = (uint8_t *) readarr;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000621 count = readcnt;
622 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000623
Dominik Geyerb46acba2008-05-16 12:55:55 +0000624 if (run_opcode(opcode_index, *opcode, addr, count, data) != 0) {
625 printf_debug("run OPCODE 0x%02x failed\n", opcode->opcode);
626 return 1;
627 }
628
629 return 0;
630}