blob: 74ce3f0c24bb477a72cdd36cc9a03845c356db7e [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 +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;
Uwe Hermann394131e2008-10-18 21:14:13 +0000187
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 }
Uwe Hermann394131e2008-10-18 21:14:13 +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) {
Uwe Hermann394131e2008-10-18 21:14:13 +0000207 case BUS_TYPE_ICH7_SPI:
208 case BUS_TYPE_VIA_SPI:
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000209 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 Reinauer43119562008-11-02 19:51:50 +0000228static int ich7_run_opcode(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;
Stefan Reinauer43119562008-11-02 19:51:50 +0000236 uint64_t opmenu;
237 int opcode_index;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000238
239 /* Is it a write command? */
240 if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
241 || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
242 write_cmd = 1;
243 }
244
245 /* Programm Offset in Flash into FADDR */
Stefan Reinauera9424d52008-06-27 16:28:34 +0000246 REGWRITE32(ICH7_REG_SPIA, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */
Dominik Geyerb46acba2008-05-16 12:55:55 +0000247
248 /* Program data into FDATA0 to N */
249 if (write_cmd && (datalength != 0)) {
250 temp32 = 0;
251 for (a = 0; a < datalength; a++) {
252 if ((a % 4) == 0) {
253 temp32 = 0;
254 }
255
256 temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
257
258 if ((a % 4) == 3) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000259 REGWRITE32(ICH7_REG_SPID0 + (a - (a % 4)),
260 temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000261 }
262 }
263 if (((a - 1) % 4) != 3) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000264 REGWRITE32(ICH7_REG_SPID0 +
265 ((a - 1) - ((a - 1) % 4)), temp32);
266 }
267
268 }
269
270 /* Assemble SPIS */
271 temp16 = 0;
272 /* clear error status registers */
273 temp16 |= (SPIS_CDS + SPIS_FCERR);
274 REGWRITE16(ICH7_REG_SPIS, temp16);
275
276 /* Assemble SPIC */
277 temp16 = 0;
278
279 if (datalength != 0) {
280 temp16 |= SPIC_DS;
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000281 temp16 |= ((uint32_t) ((datalength - 1) & (maxdata - 1))) << 8;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000282 }
283
284 /* Select opcode */
Stefan Reinauer43119562008-11-02 19:51:50 +0000285 opmenu = REGREAD32(ICH7_REG_OPMENU);
286 opmenu |= ((uint64_t)REGREAD32(ICH7_REG_OPMENU + 4)) << 32;
287
288 for (opcode_index=0; opcode_index<8; opcode_index++) {
289 if((opmenu & 0xff) == op.opcode) {
290 break;
291 }
292 opmenu >>= 8;
293 }
294 if (opcode_index == 8) {
295 printf_debug("Opcode %x not found.\n", op.opcode);
296 return 1;
297 }
298 temp16 |= ((uint16_t) (opcode_index & 0x07)) << 4;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000299
300 /* Handle Atomic */
301 if (op.atomic != 0) {
302 /* Select atomic command */
303 temp16 |= SPIC_ACS;
304 /* Selct prefix opcode */
305 if ((op.atomic - 1) == 1) {
306 /*Select prefix opcode 2 */
307 temp16 |= SPIC_SPOP;
308 }
309 }
310
311 /* Start */
312 temp16 |= SPIC_SCGO;
313
314 /* write it */
315 REGWRITE16(ICH7_REG_SPIC, temp16);
316
317 /* wait for cycle complete */
318 timeout = 1000 * 60; // 60s is a looong timeout.
319 while (((REGREAD16(ICH7_REG_SPIS) & SPIS_CDS) == 0) && --timeout) {
320 myusec_delay(1000);
321 }
322 if (!timeout) {
323 printf_debug("timeout\n");
324 }
325
326 if ((REGREAD16(ICH7_REG_SPIS) & SPIS_FCERR) != 0) {
327 printf_debug("Transaction error!\n");
328 return 1;
329 }
330
331 if ((!write_cmd) && (datalength != 0)) {
332 for (a = 0; a < datalength; a++) {
333 if ((a % 4) == 0) {
334 temp32 = REGREAD32(ICH7_REG_SPID0 + (a));
335 }
336
337 data[a] =
338 (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
339 >> ((a % 4) * 8);
340 }
341 }
342
343 return 0;
344}
345
Stefan Reinauer43119562008-11-02 19:51:50 +0000346static int ich9_run_opcode(OPCODE op, uint32_t offset,
Stefan Reinauera9424d52008-06-27 16:28:34 +0000347 uint8_t datalength, uint8_t * data)
348{
349 int write_cmd = 0;
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000350 int timeout;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000351 uint32_t temp32;
352 uint32_t a;
Stefan Reinauer43119562008-11-02 19:51:50 +0000353 uint64_t opmenu;
354 int opcode_index;
Stefan Reinauera9424d52008-06-27 16:28:34 +0000355
356 /* Is it a write command? */
357 if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
358 || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
359 write_cmd = 1;
360 }
361
362 /* Programm Offset in Flash into FADDR */
363 REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF)); /* SPI addresses are 24 BIT only */
364
365 /* Program data into FDATA0 to N */
366 if (write_cmd && (datalength != 0)) {
367 temp32 = 0;
368 for (a = 0; a < datalength; a++) {
369 if ((a % 4) == 0) {
370 temp32 = 0;
371 }
372
373 temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
374
375 if ((a % 4) == 3) {
376 REGWRITE32(ICH9_REG_FDATA0 + (a - (a % 4)),
377 temp32);
378 }
379 }
380 if (((a - 1) % 4) != 3) {
381 REGWRITE32(ICH9_REG_FDATA0 +
382 ((a - 1) - ((a - 1) % 4)), temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000383 }
384
385 }
386
387 /* Assemble SSFS + SSFC */
388 temp32 = 0;
389
390 /* clear error status registers */
391 temp32 |= (SSFS_CDS + SSFS_FCERR);
392 /* USE 20 MhZ */
393 temp32 |= SSFC_SCF_20MHZ;
394
395 if (datalength != 0) {
396 uint32_t datatemp;
397 temp32 |= SSFC_DS;
398 datatemp = ((uint32_t) ((datalength - 1) & 0x3f)) << (8 + 8);
399 temp32 |= datatemp;
400 }
401
402 /* Select opcode */
Stefan Reinauer43119562008-11-02 19:51:50 +0000403 opmenu = REGREAD32(ICH9_REG_OPMENU);
404 opmenu |= ((uint64_t)REGREAD32(ICH9_REG_OPMENU + 4)) << 32;
405
406 for (opcode_index=0; opcode_index<8; opcode_index++) {
407 if((opmenu & 0xff) == op.opcode) {
408 break;
409 }
410 opmenu >>= 8;
411 }
412 if (opcode_index == 8) {
413 printf_debug("Opcode %x not found.\n", op.opcode);
414 return 1;
415 }
416 temp32 |= ((uint32_t) (opcode_index & 0x07)) << (8 + 4);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000417
418 /* Handle Atomic */
419 if (op.atomic != 0) {
420 /* Select atomic command */
421 temp32 |= SSFC_ACS;
422 /* Selct prefix opcode */
423 if ((op.atomic - 1) == 1) {
424 /*Select prefix opcode 2 */
425 temp32 |= SSFC_SPOP;
426 }
427 }
428
429 /* Start */
430 temp32 |= SSFC_SCGO;
431
432 /* write it */
Stefan Reinauera9424d52008-06-27 16:28:34 +0000433 REGWRITE32(ICH9_REG_SSFS, temp32);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000434
435 /*wait for cycle complete */
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000436 timeout = 1000 * 60; // 60s is a looong timeout.
437 while (((REGREAD32(ICH9_REG_SSFS) & SSFS_CDS) == 0) && --timeout) {
438 myusec_delay(1000);
439 }
440 if (!timeout) {
441 printf_debug("timeout\n");
Dominik Geyerb46acba2008-05-16 12:55:55 +0000442 }
443
Stefan Reinauera9424d52008-06-27 16:28:34 +0000444 if ((REGREAD32(ICH9_REG_SSFS) & SSFS_FCERR) != 0) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000445 printf_debug("Transaction error!\n");
446 return 1;
447 }
448
449 if ((!write_cmd) && (datalength != 0)) {
450 for (a = 0; a < datalength; a++) {
451 if ((a % 4) == 0) {
Stefan Reinauera9424d52008-06-27 16:28:34 +0000452 temp32 = REGREAD32(ICH9_REG_FDATA0 + (a));
Dominik Geyerb46acba2008-05-16 12:55:55 +0000453 }
454
455 data[a] =
Stefan Reinauera9424d52008-06-27 16:28:34 +0000456 (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8)))
457 >> ((a % 4) * 8);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000458 }
459 }
460
461 return 0;
462}
463
Stefan Reinauer43119562008-11-02 19:51:50 +0000464static int run_opcode(OPCODE op, uint32_t offset,
Stefan Reinauera9424d52008-06-27 16:28:34 +0000465 uint8_t datalength, uint8_t * data)
466{
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000467 switch (flashbus) {
468 case BUS_TYPE_VIA_SPI:
Stefan Reinauer43119562008-11-02 19:51:50 +0000469 return ich7_run_opcode(op, offset, datalength, data, 16);
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000470 case BUS_TYPE_ICH7_SPI:
Stefan Reinauer43119562008-11-02 19:51:50 +0000471 return ich7_run_opcode(op, offset, datalength, data, 64);
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000472 case BUS_TYPE_ICH9_SPI:
Stefan Reinauer43119562008-11-02 19:51:50 +0000473 return ich9_run_opcode(op, offset, datalength, data);
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000474 default:
475 printf_debug("%s: unsupported chipset\n", __FUNCTION__);
476 }
Stefan Reinauera9424d52008-06-27 16:28:34 +0000477
478 /* If we ever get here, something really weird happened */
479 return -1;
480}
481
Dominik Geyerb46acba2008-05-16 12:55:55 +0000482static int ich_spi_erase_block(struct flashchip *flash, int offset)
483{
Uwe Hermann394131e2008-10-18 21:14:13 +0000484 printf_debug("ich_spi_erase_block: offset=%d, sectors=%d\n", offset, 1);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000485
Stefan Reinauer43119562008-11-02 19:51:50 +0000486 if (run_opcode(curopcodes->opcode[2], offset, 0, NULL) != 0) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000487 printf_debug("Error erasing sector at 0x%x", offset);
488 return -1;
489 }
490
491 printf("DONE BLOCK 0x%x\n", offset);
492
493 return 0;
494}
495
Uwe Hermann394131e2008-10-18 21:14:13 +0000496static int ich_spi_read_page(struct flashchip *flash, uint8_t * buf, int offset,
497 int maxdata)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000498{
499 int page_size = flash->page_size;
500 uint32_t remaining = flash->page_size;
501 int a;
502
Stefan Reinauera9424d52008-06-27 16:28:34 +0000503 printf_debug("ich_spi_read_page: offset=%d, number=%d, buf=%p\n",
504 offset, page_size, buf);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000505
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000506 for (a = 0; a < page_size; a += maxdata) {
507 if (remaining < maxdata) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000508
509 if (run_opcode
Stefan Reinauer43119562008-11-02 19:51:50 +0000510 (curopcodes->opcode[1],
Stefan Reinauera9424d52008-06-27 16:28:34 +0000511 offset + (page_size - remaining), remaining,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000512 &buf[page_size - remaining]) != 0) {
513 printf_debug("Error reading");
514 return 1;
515 }
516 remaining = 0;
517 } else {
518 if (run_opcode
Stefan Reinauer43119562008-11-02 19:51:50 +0000519 (curopcodes->opcode[1],
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000520 offset + (page_size - remaining), maxdata,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000521 &buf[page_size - remaining]) != 0) {
522 printf_debug("Error reading");
523 return 1;
524 }
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000525 remaining -= maxdata;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000526 }
527 }
528
529 return 0;
530}
531
532static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000533 int offset, int maxdata)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000534{
535 int page_size = flash->page_size;
536 uint32_t remaining = page_size;
537 int a;
538
Stefan Reinauera9424d52008-06-27 16:28:34 +0000539 printf_debug("ich_spi_write_page: offset=%d, number=%d, buf=%p\n",
540 offset, page_size, bytes);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000541
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000542 for (a = 0; a < page_size; a += maxdata) {
543 if (remaining < maxdata) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000544 if (run_opcode
Stefan Reinauer43119562008-11-02 19:51:50 +0000545 (curopcodes->opcode[0],
Stefan Reinauera9424d52008-06-27 16:28:34 +0000546 offset + (page_size - remaining), remaining,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000547 &bytes[page_size - remaining]) != 0) {
548 printf_debug("Error writing");
549 return 1;
550 }
551 remaining = 0;
552 } else {
553 if (run_opcode
Stefan Reinauer43119562008-11-02 19:51:50 +0000554 (curopcodes->opcode[0],
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000555 offset + (page_size - remaining), maxdata,
Dominik Geyerb46acba2008-05-16 12:55:55 +0000556 &bytes[page_size - remaining]) != 0) {
557 printf_debug("Error writing");
558 return 1;
559 }
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000560 remaining -= maxdata;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000561 }
562 }
563
564 return 0;
565}
566
Dominik Geyerb46acba2008-05-16 12:55:55 +0000567int ich_spi_read(struct flashchip *flash, uint8_t * buf)
568{
569 int i, rc = 0;
570 int total_size = flash->total_size * 1024;
571 int page_size = flash->page_size;
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000572 int maxdata = 64;
573
Stefan Reinauer2cb94e12008-06-30 23:45:22 +0000574 if (flashbus == BUS_TYPE_VIA_SPI) {
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000575 maxdata = 16;
576 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000577
578 for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
579 rc = ich_spi_read_page(flash, (void *)(buf + i * page_size),
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000580 i * page_size, maxdata);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000581 }
582
583 return rc;
584}
585
Dominik Geyerb46acba2008-05-16 12:55:55 +0000586int ich_spi_write(struct flashchip *flash, uint8_t * buf)
587{
588 int i, j, rc = 0;
589 int total_size = flash->total_size * 1024;
590 int page_size = flash->page_size;
591 int erase_size = 64 * 1024;
Rudolf Marek3fdbccf2008-06-30 21:38:30 +0000592 int maxdata = 64;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000593
594 spi_disable_blockprotect();
595
596 printf("Programming page: \n");
597
598 for (i = 0; i < total_size / erase_size; i++) {
599 rc = ich_spi_erase_block(flash, i * erase_size);
600 if (rc) {
601 printf("Error erasing block at 0x%x\n", i);
602 break;
603 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000604
Peter Stuge6a214162008-07-07 05:14:06 +0000605 if (flashbus == BUS_TYPE_VIA_SPI)
606 maxdata = 16;
607
Dominik Geyerb46acba2008-05-16 12:55:55 +0000608 for (j = 0; j < erase_size / page_size; j++) {
Uwe Hermann394131e2008-10-18 21:14:13 +0000609 ich_spi_write_page(flash,
610 (void *)(buf + (i * erase_size) + (j * page_size)),
611 (i * erase_size) + (j * page_size), maxdata);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000612 }
613 }
614
615 printf("\n");
616
617 return rc;
618}
619
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000620int ich_spi_command(unsigned int writecnt, unsigned int readcnt,
621 const unsigned char *writearr, unsigned char *readarr)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000622{
623 int a;
624 int opcode_index = -1;
625 const unsigned char cmd = *writearr;
626 OPCODE *opcode;
627 uint32_t addr = 0;
628 uint8_t *data;
629 int count;
630
631 /* program opcodes if not already done */
632 if (curopcodes == NULL) {
Carl-Daniel Hailfinger10693352008-06-29 10:57:13 +0000633 printf_debug("Programming OPCODES... ");
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000634 curopcodes = &O_ST_M25P;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000635 program_opcodes(curopcodes);
Carl-Daniel Hailfinger10693352008-06-29 10:57:13 +0000636 printf_debug("done\n");
Dominik Geyerb46acba2008-05-16 12:55:55 +0000637 }
638
639 /* find cmd in opcodes-table */
640 for (a = 0; a < 8; a++) {
641 if ((curopcodes->opcode[a]).opcode == cmd) {
642 opcode_index = a;
643 break;
644 }
645 }
646
647 /* unknown / not programmed command */
648 if (opcode_index == -1) {
649 printf_debug("Invalid OPCODE 0x%02x\n", cmd);
650 return 1;
651 }
652
653 opcode = &(curopcodes->opcode[opcode_index]);
654
655 /* if opcode-type requires an address */
656 if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS ||
657 opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000658 addr = (writearr[1] << 16) |
659 (writearr[2] << 8) | (writearr[3] << 0);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000660 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000661
Dominik Geyerb46acba2008-05-16 12:55:55 +0000662 /* translate read/write array/count */
663 if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000664 data = (uint8_t *) (writearr + 1);
665 count = writecnt - 1;
666 } else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
667 data = (uint8_t *) (writearr + 4);
668 count = writecnt - 4;
669 } else {
670 data = (uint8_t *) readarr;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000671 count = readcnt;
672 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000673
Stefan Reinauer43119562008-11-02 19:51:50 +0000674 if (run_opcode(*opcode, addr, count, data) != 0) {
Dominik Geyerb46acba2008-05-16 12:55:55 +0000675 printf_debug("run OPCODE 0x%02x failed\n", opcode->opcode);
676 return 1;
677 }
678
679 return 0;
680}