blob: 28ee578ee3292335c76d4bccb7f9df4dcd0f88fb [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;
Uwe Hermann394131e2008-10-18 21:14:13 +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;
Uwe Hermann394131e2008-10-18 21:14:13 +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 Reinauer43119562008-11-02 19:51:50 +0000151static int run_opcode(OPCODE op, uint32_t offset,
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000152 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 +0000157
Dominik Geyerb46acba2008-05-16 12:55:55 +0000158OPCODES O_ST_M25P = {
159 {
160 JEDEC_WREN,
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000161 0},
Dominik Geyerb46acba2008-05-16 12:55:55 +0000162 {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000163 {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Write Byte
164 {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data
165 {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Erase Sector
166 {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg
167 {JEDEC_RES, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Resume Deep Power-Down
168 {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Write Status Register
169 {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID
170 {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Bulk erase
171 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000172};
173
Dominik Geyerb46acba2008-05-16 12:55:55 +0000174int program_opcodes(OPCODES * op)
175{
176 uint8_t a;
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000177 uint16_t preop, optype;
178 uint32_t opmenu[2];
Dominik Geyerb46acba2008-05-16 12:55:55 +0000179
180 /* Program Prefix Opcodes */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000181 preop = 0;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000182 /* 0:7 Prefix Opcode 1 */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000183 preop = (op->preop[0]);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000184 /* 8:16 Prefix Opcode 2 */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000185 preop |= ((uint16_t) op->preop[1]) << 8;
Uwe Hermann394131e2008-10-18 21:14:13 +0000186
Stefan Reinauera9424d52008-06-27 16:28:34 +0000187 /* Program Opcode Types 0 - 7 */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000188 optype = 0;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000189 for (a = 0; a < 8; a++) {
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000190 optype |= ((uint16_t) op->opcode[a].spi_type) << (a * 2);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000191 }
Uwe Hermann394131e2008-10-18 21:14:13 +0000192
Stefan Reinauera9424d52008-06-27 16:28:34 +0000193 /* Program Allowable Opcodes 0 - 3 */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000194 opmenu[0] = 0;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000195 for (a = 0; a < 4; a++) {
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000196 opmenu[0] |= ((uint32_t) op->opcode[a].opcode) << (a * 8);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000197 }
Stefan Reinauera9424d52008-06-27 16:28:34 +0000198
Dominik Geyerb46acba2008-05-16 12:55:55 +0000199 /*Program Allowable Opcodes 4 - 7 */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000200 opmenu[1] = 0;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000201 for (a = 4; a < 8; a++) {
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000202 opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000203 }
Stefan Reinauera9424d52008-06-27 16:28:34 +0000204
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000205 switch (flashbus) {
Uwe Hermann394131e2008-10-18 21:14:13 +0000206 case BUS_TYPE_ICH7_SPI:
207 case BUS_TYPE_VIA_SPI:
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000208 REGWRITE16(ICH7_REG_PREOP, preop);
209 REGWRITE16(ICH7_REG_OPTYPE, optype);
210 REGWRITE32(ICH7_REG_OPMENU, opmenu[0]);
211 REGWRITE32(ICH7_REG_OPMENU + 4, opmenu[1]);
212 break;
213 case BUS_TYPE_ICH9_SPI:
214 REGWRITE16(ICH9_REG_PREOP, preop);
215 REGWRITE16(ICH9_REG_OPTYPE, optype);
216 REGWRITE32(ICH9_REG_OPMENU, opmenu[0]);
217 REGWRITE32(ICH9_REG_OPMENU + 4, opmenu[1]);
218 break;
219 default:
220 printf_debug("%s: unsupported chipset\n", __FUNCTION__);
221 return -1;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000222 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000223
224 return 0;
225}
226
Stefan Reinauer43119562008-11-02 19:51:50 +0000227static int ich7_run_opcode(OPCODE op, uint32_t offset,
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000228 uint8_t datalength, uint8_t * data, int maxdata)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000229{
230 int write_cmd = 0;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000231 int timeout;
Peter Stuge7e2c0792008-06-29 01:30:41 +0000232 uint32_t temp32 = 0;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000233 uint16_t temp16;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000234 uint32_t a;
Stefan Reinauer43119562008-11-02 19:51:50 +0000235 uint64_t opmenu;
236 int opcode_index;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000237
238 /* Is it a write command? */
239 if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
240 || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
241 write_cmd = 1;
242 }
243
244 /* Programm Offset in Flash into FADDR */
Stefan Reinauera9424d52008-06-27 16:28:34 +0000245 REGWRITE32(ICH7_REG_SPIA, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */
Dominik Geyerb46acba2008-05-16 12:55:55 +0000246
247 /* Program data into FDATA0 to N */
248 if (write_cmd && (datalength != 0)) {
249 temp32 = 0;
250 for (a = 0; a < datalength; a++) {
251 if ((a % 4) == 0) {
252 temp32 = 0;
253 }
254
255 temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
256
257 if ((a % 4) == 3) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000258 REGWRITE32(ICH7_REG_SPID0 + (a - (a % 4)),
259 temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000260 }
261 }
262 if (((a - 1) % 4) != 3) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000263 REGWRITE32(ICH7_REG_SPID0 +
264 ((a - 1) - ((a - 1) % 4)), temp32);
265 }
266
267 }
268
269 /* Assemble SPIS */
270 temp16 = 0;
271 /* clear error status registers */
272 temp16 |= (SPIS_CDS + SPIS_FCERR);
273 REGWRITE16(ICH7_REG_SPIS, temp16);
274
275 /* Assemble SPIC */
276 temp16 = 0;
277
278 if (datalength != 0) {
279 temp16 |= SPIC_DS;
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000280 temp16 |= ((uint32_t) ((datalength - 1) & (maxdata - 1))) << 8;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000281 }
282
283 /* Select opcode */
Stefan Reinauer43119562008-11-02 19:51:50 +0000284 opmenu = REGREAD32(ICH7_REG_OPMENU);
285 opmenu |= ((uint64_t)REGREAD32(ICH7_REG_OPMENU + 4)) << 32;
286
287 for (opcode_index=0; opcode_index<8; opcode_index++) {
288 if((opmenu & 0xff) == op.opcode) {
289 break;
290 }
291 opmenu >>= 8;
292 }
293 if (opcode_index == 8) {
294 printf_debug("Opcode %x not found.\n", op.opcode);
295 return 1;
296 }
297 temp16 |= ((uint16_t) (opcode_index & 0x07)) << 4;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000298
299 /* Handle Atomic */
300 if (op.atomic != 0) {
301 /* Select atomic command */
302 temp16 |= SPIC_ACS;
303 /* Selct prefix opcode */
304 if ((op.atomic - 1) == 1) {
305 /*Select prefix opcode 2 */
306 temp16 |= SPIC_SPOP;
307 }
308 }
309
310 /* Start */
311 temp16 |= SPIC_SCGO;
312
313 /* write it */
314 REGWRITE16(ICH7_REG_SPIC, temp16);
315
316 /* wait for cycle complete */
317 timeout = 1000 * 60; // 60s is a looong timeout.
318 while (((REGREAD16(ICH7_REG_SPIS) & SPIS_CDS) == 0) && --timeout) {
319 myusec_delay(1000);
320 }
321 if (!timeout) {
322 printf_debug("timeout\n");
323 }
324
325 if ((REGREAD16(ICH7_REG_SPIS) & SPIS_FCERR) != 0) {
326 printf_debug("Transaction error!\n");
327 return 1;
328 }
329
330 if ((!write_cmd) && (datalength != 0)) {
331 for (a = 0; a < datalength; a++) {
332 if ((a % 4) == 0) {
333 temp32 = REGREAD32(ICH7_REG_SPID0 + (a));
334 }
335
336 data[a] =
337 (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
338 >> ((a % 4) * 8);
339 }
340 }
341
342 return 0;
343}
344
Stefan Reinauer43119562008-11-02 19:51:50 +0000345static int ich9_run_opcode(OPCODE op, uint32_t offset,
Stefan Reinauera9424d52008-06-27 16:28:34 +0000346 uint8_t datalength, uint8_t * data)
347{
348 int write_cmd = 0;
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000349 int timeout;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000350 uint32_t temp32;
351 uint32_t a;
Stefan Reinauer43119562008-11-02 19:51:50 +0000352 uint64_t opmenu;
353 int opcode_index;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000354
355 /* Is it a write command? */
356 if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
357 || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
358 write_cmd = 1;
359 }
360
361 /* Programm Offset in Flash into FADDR */
362 REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */
363
364 /* Program data into FDATA0 to N */
365 if (write_cmd && (datalength != 0)) {
366 temp32 = 0;
367 for (a = 0; a < datalength; a++) {
368 if ((a % 4) == 0) {
369 temp32 = 0;
370 }
371
372 temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
373
374 if ((a % 4) == 3) {
375 REGWRITE32(ICH9_REG_FDATA0 + (a - (a % 4)),
376 temp32);
377 }
378 }
379 if (((a - 1) % 4) != 3) {
380 REGWRITE32(ICH9_REG_FDATA0 +
381 ((a - 1) - ((a - 1) % 4)), temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000382 }
383
384 }
385
386 /* Assemble SSFS + SSFC */
387 temp32 = 0;
388
389 /* clear error status registers */
390 temp32 |= (SSFS_CDS + SSFS_FCERR);
391 /* USE 20 MhZ */
392 temp32 |= SSFC_SCF_20MHZ;
393
394 if (datalength != 0) {
395 uint32_t datatemp;
396 temp32 |= SSFC_DS;
397 datatemp = ((uint32_t) ((datalength - 1) & 0x3f)) << (8 + 8);
398 temp32 |= datatemp;
399 }
400
401 /* Select opcode */
Stefan Reinauer43119562008-11-02 19:51:50 +0000402 opmenu = REGREAD32(ICH9_REG_OPMENU);
403 opmenu |= ((uint64_t)REGREAD32(ICH9_REG_OPMENU + 4)) << 32;
404
405 for (opcode_index=0; opcode_index<8; opcode_index++) {
406 if((opmenu & 0xff) == op.opcode) {
407 break;
408 }
409 opmenu >>= 8;
410 }
411 if (opcode_index == 8) {
412 printf_debug("Opcode %x not found.\n", op.opcode);
413 return 1;
414 }
415 temp32 |= ((uint32_t) (opcode_index & 0x07)) << (8 + 4);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000416
417 /* Handle Atomic */
418 if (op.atomic != 0) {
419 /* Select atomic command */
420 temp32 |= SSFC_ACS;
421 /* Selct prefix opcode */
422 if ((op.atomic - 1) == 1) {
423 /*Select prefix opcode 2 */
424 temp32 |= SSFC_SPOP;
425 }
426 }
427
428 /* Start */
429 temp32 |= SSFC_SCGO;
430
431 /* write it */
Stefan Reinauera9424d52008-06-27 16:28:34 +0000432 REGWRITE32(ICH9_REG_SSFS, temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000433
434 /*wait for cycle complete */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000435 timeout = 1000 * 60; // 60s is a looong timeout.
436 while (((REGREAD32(ICH9_REG_SSFS) & SSFS_CDS) == 0) && --timeout) {
437 myusec_delay(1000);
438 }
439 if (!timeout) {
440 printf_debug("timeout\n");
Dominik Geyerb46acba2008-05-16 12:55:55 +0000441 }
442
Stefan Reinauera9424d52008-06-27 16:28:34 +0000443 if ((REGREAD32(ICH9_REG_SSFS) & SSFS_FCERR) != 0) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000444 printf_debug("Transaction error!\n");
445 return 1;
446 }
447
448 if ((!write_cmd) && (datalength != 0)) {
449 for (a = 0; a < datalength; a++) {
450 if ((a % 4) == 0) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000451 temp32 = REGREAD32(ICH9_REG_FDATA0 + (a));
Dominik Geyerb46acba2008-05-16 12:55:55 +0000452 }
453
454 data[a] =
Stefan Reinauera9424d52008-06-27 16:28:34 +0000455 (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
456 >> ((a % 4) * 8);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000457 }
458 }
459
460 return 0;
461}
462
Stefan Reinauer43119562008-11-02 19:51:50 +0000463static int run_opcode(OPCODE op, uint32_t offset,
Stefan Reinauera9424d52008-06-27 16:28:34 +0000464 uint8_t datalength, uint8_t * data)
465{
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000466 switch (flashbus) {
467 case BUS_TYPE_VIA_SPI:
Stefan Reinauer43119562008-11-02 19:51:50 +0000468 return ich7_run_opcode(op, offset, datalength, data, 16);
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000469 case BUS_TYPE_ICH7_SPI:
Stefan Reinauer43119562008-11-02 19:51:50 +0000470 return ich7_run_opcode(op, offset, datalength, data, 64);
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000471 case BUS_TYPE_ICH9_SPI:
Stefan Reinauer43119562008-11-02 19:51:50 +0000472 return ich9_run_opcode(op, offset, datalength, data);
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000473 default:
474 printf_debug("%s: unsupported chipset\n", __FUNCTION__);
475 }
Stefan Reinauera9424d52008-06-27 16:28:34 +0000476
477 /* If we ever get here, something really weird happened */
478 return -1;
479}
480
Uwe Hermann394131e2008-10-18 21:14:13 +0000481static int ich_spi_read_page(struct flashchip *flash, uint8_t * buf, int offset,
482 int maxdata)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000483{
484 int page_size = flash->page_size;
485 uint32_t remaining = flash->page_size;
486 int a;
487
Stefan Reinauera9424d52008-06-27 16:28:34 +0000488 printf_debug("ich_spi_read_page: offset=%d, number=%d, buf=%p\n",
489 offset, page_size, buf);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000490
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000491 for (a = 0; a < page_size; a += maxdata) {
492 if (remaining < maxdata) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000493
494 if (run_opcode
Stefan Reinauer43119562008-11-02 19:51:50 +0000495 (curopcodes->opcode[1],
Stefan Reinauera9424d52008-06-27 16:28:34 +0000496 offset + (page_size - remaining), remaining,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000497 &buf[page_size - remaining]) != 0) {
498 printf_debug("Error reading");
499 return 1;
500 }
501 remaining = 0;
502 } else {
503 if (run_opcode
Stefan Reinauer43119562008-11-02 19:51:50 +0000504 (curopcodes->opcode[1],
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000505 offset + (page_size - remaining), maxdata,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000506 &buf[page_size - remaining]) != 0) {
507 printf_debug("Error reading");
508 return 1;
509 }
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000510 remaining -= maxdata;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000511 }
512 }
513
514 return 0;
515}
516
517static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000518 int offset, int maxdata)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000519{
520 int page_size = flash->page_size;
521 uint32_t remaining = page_size;
522 int a;
523
Stefan Reinauera9424d52008-06-27 16:28:34 +0000524 printf_debug("ich_spi_write_page: offset=%d, number=%d, buf=%p\n",
525 offset, page_size, bytes);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000526
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000527 for (a = 0; a < page_size; a += maxdata) {
528 if (remaining < maxdata) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000529 if (run_opcode
Stefan Reinauer43119562008-11-02 19:51:50 +0000530 (curopcodes->opcode[0],
Stefan Reinauera9424d52008-06-27 16:28:34 +0000531 offset + (page_size - remaining), remaining,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000532 &bytes[page_size - remaining]) != 0) {
533 printf_debug("Error writing");
534 return 1;
535 }
536 remaining = 0;
537 } else {
538 if (run_opcode
Stefan Reinauer43119562008-11-02 19:51:50 +0000539 (curopcodes->opcode[0],
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000540 offset + (page_size - remaining), maxdata,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000541 &bytes[page_size - remaining]) != 0) {
542 printf_debug("Error writing");
543 return 1;
544 }
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000545 remaining -= maxdata;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000546 }
547 }
548
549 return 0;
550}
551
Dominik Geyerb46acba2008-05-16 12:55:55 +0000552int ich_spi_read(struct flashchip *flash, uint8_t * buf)
553{
554 int i, rc = 0;
555 int total_size = flash->total_size * 1024;
556 int page_size = flash->page_size;
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000557 int maxdata = 64;
558
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000559 if (flashbus == BUS_TYPE_VIA_SPI) {
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000560 maxdata = 16;
561 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000562
563 for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
564 rc = ich_spi_read_page(flash, (void *)(buf + i * page_size),
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000565 i * page_size, maxdata);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000566 }
567
568 return rc;
569}
570
Dominik Geyerb46acba2008-05-16 12:55:55 +0000571int ich_spi_write(struct flashchip *flash, uint8_t * buf)
572{
573 int i, j, rc = 0;
574 int total_size = flash->total_size * 1024;
575 int page_size = flash->page_size;
576 int erase_size = 64 * 1024;
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000577 int maxdata = 64;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000578
579 spi_disable_blockprotect();
580
581 printf("Programming page: \n");
582
583 for (i = 0; i < total_size / erase_size; i++) {
Carl-Daniel Hailfinger6afb6132008-11-03 00:02:11 +0000584 /* FIMXE: call the chip-specific spi_block_erase_XX instead.
585 * For this, we need to add a block erase function to
586 * struct flashchip.
587 */
588 rc = spi_block_erase_d8(flash, i * erase_size);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000589 if (rc) {
590 printf("Error erasing block at 0x%x\n", i);
591 break;
592 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000593
Peter Stuge6a214162008-07-07 05:14:06 +0000594 if (flashbus == BUS_TYPE_VIA_SPI)
595 maxdata = 16;
596
Dominik Geyerb46acba2008-05-16 12:55:55 +0000597 for (j = 0; j < erase_size / page_size; j++) {
Uwe Hermann394131e2008-10-18 21:14:13 +0000598 ich_spi_write_page(flash,
599 (void *)(buf + (i * erase_size) + (j * page_size)),
600 (i * erase_size) + (j * page_size), maxdata);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000601 }
602 }
603
604 printf("\n");
605
606 return rc;
607}
608
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000609int ich_spi_command(unsigned int writecnt, unsigned int readcnt,
610 const unsigned char *writearr, unsigned char *readarr)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000611{
612 int a;
613 int opcode_index = -1;
614 const unsigned char cmd = *writearr;
615 OPCODE *opcode;
616 uint32_t addr = 0;
617 uint8_t *data;
618 int count;
619
620 /* program opcodes if not already done */
621 if (curopcodes == NULL) {
Carl-Daniel Hailfinger10693352008-06-29 10:57:13 +0000622 printf_debug("Programming OPCODES... ");
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000623 curopcodes = &O_ST_M25P;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000624 program_opcodes(curopcodes);
Carl-Daniel Hailfinger10693352008-06-29 10:57:13 +0000625 printf_debug("done\n");
Dominik Geyerb46acba2008-05-16 12:55:55 +0000626 }
627
628 /* find cmd in opcodes-table */
629 for (a = 0; a < 8; a++) {
630 if ((curopcodes->opcode[a]).opcode == cmd) {
631 opcode_index = a;
632 break;
633 }
634 }
635
636 /* unknown / not programmed command */
637 if (opcode_index == -1) {
638 printf_debug("Invalid OPCODE 0x%02x\n", cmd);
639 return 1;
640 }
641
642 opcode = &(curopcodes->opcode[opcode_index]);
643
644 /* if opcode-type requires an address */
645 if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS ||
646 opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000647 addr = (writearr[1] << 16) |
648 (writearr[2] << 8) | (writearr[3] << 0);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000649 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000650
Dominik Geyerb46acba2008-05-16 12:55:55 +0000651 /* translate read/write array/count */
652 if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000653 data = (uint8_t *) (writearr + 1);
654 count = writecnt - 1;
655 } else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
656 data = (uint8_t *) (writearr + 4);
657 count = writecnt - 4;
658 } else {
659 data = (uint8_t *) readarr;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000660 count = readcnt;
661 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000662
Stefan Reinauer43119562008-11-02 19:51:50 +0000663 if (run_opcode(*opcode, addr, count, data) != 0) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000664 printf_debug("run OPCODE 0x%02x failed\n", opcode->opcode);
665 return 1;
666 }
667
668 return 0;
669}