blob: deca4452e6b5f048fa54b2ef829f8486d4b14e4f [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>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 */
23
24/*
25 * This module is designed for supporting the devices
26 * ST M25P40
27 * ST M25P80
28 * ST M25P16
29 * ST M25P32 already tested
30 * ST M25P64
31 * AT 25DF321 already tested
32 *
33 */
34
35#include <stdio.h>
36#include <string.h>
37#include <stdint.h>
38#include <sys/mman.h>
39#include <pci/pci.h>
40#include "flash.h"
41#include "spi.h"
42
43#define MAXDATABYTES 0x40
44
45/*ICH9 controller register definition*/
46#define REG_FADDR 0x08 /* 32 Bits */
47#define REG_FDATA0 0x10 /* 64 Bytes */
48#define REG_SSFS 0x90 /* 08 Bits */
49#define SSFS_SCIP 0x00000001
50#define SSFS_CDS 0x00000004
51#define SSFS_FCERR 0x00000008
52#define SSFS_AEL 0x00000010
53#define REG_SSFC 0x91 /* 24 Bits */
54#define SSFC_SCGO 0x00000200
55#define SSFC_ACS 0x00000400
56#define SSFC_SPOP 0x00000800
57#define SSFC_COP 0x00001000
58#define SSFC_DBC 0x00010000
59#define SSFC_DS 0x00400000
60#define SSFC_SME 0x00800000
61#define SSFC_SCF 0x01000000
62#define SSFC_SCF_20MHZ 0x00000000
63#define SSFC_SCF_33MHZ 0x01000000
64#define REG_PREOP 0x94 /* 16 Bits */
65#define REG_OPTYPE 0x96 /* 16 Bits */
66#define REG_OPMENU 0x98 /* 64 BITS */
67
68// ICH9R SPI commands
69#define SPI_OPCODE_TYPE_READ_NO_ADDRESS 0
70#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS 1
71#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS 2
72#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS 3
73
Dominik Geyerb46acba2008-05-16 12:55:55 +000074typedef struct _OPCODE {
75 uint8_t opcode; //This commands spi opcode
76 uint8_t spi_type; //This commands spi type
77 uint8_t atomic; //Use preop: (0: none, 1: preop0, 2: preop1
78} OPCODE;
79
80/* Opcode definition:
81 * Preop 1: Write Enable
82 * Preop 2: Write Status register enable
83 *
84 * OP 0: Write address
85 * OP 1: Read Address
86 * OP 2: ERASE block
87 * OP 3: Read Status register
88 * OP 4: Read ID
89 * OP 5: Write Status register
90 * OP 6: chip private (read JDEC id)
91 * OP 7: Chip erase
92 */
93typedef struct _OPCODES {
94 uint8_t preop[2];
95 OPCODE opcode[8];
96} OPCODES;
97
Stefan Reinauer325b5d42008-06-27 15:18:20 +000098static OPCODES *curopcodes = NULL;
Dominik Geyerb46acba2008-05-16 12:55:55 +000099
100/* HW access functions */
101static inline uint32_t REGREAD32(int X)
102{
103 volatile uint32_t regval;
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000104 regval = *(volatile uint32_t *)((uint8_t *) ich_spibar + X);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000105 return regval;
106}
107
108#define REGWRITE32(X,Y) (*(uint32_t *)((uint8_t *)ich_spibar+X)=Y)
109#define REGWRITE16(X,Y) (*(uint16_t *)((uint8_t *)ich_spibar+X)=Y)
110#define REGWRITE8(X,Y) (*(uint8_t *)((uint8_t *)ich_spibar+X)=Y)
111
Dominik Geyerb46acba2008-05-16 12:55:55 +0000112/* Common SPI functions */
113static int program_opcodes(OPCODES * op);
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000114static int run_opcode(uint8_t nr, OPCODE op, uint32_t offset,
115 uint8_t datalength, uint8_t * data);
116static int ich_spi_read_page(struct flashchip *flash, uint8_t * buf,
117 int Offset);
118static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
119 int Offset);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000120static int ich_spi_erase_block(struct flashchip *flash, int offset);
121
Dominik Geyerb46acba2008-05-16 12:55:55 +0000122OPCODES O_ST_M25P = {
123 {
124 JEDEC_WREN,
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000125 0},
Dominik Geyerb46acba2008-05-16 12:55:55 +0000126 {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000127 {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Write Byte
128 {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data
129 {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Erase Sector
130 {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg
131 {JEDEC_RES, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Resume Deep Power-Down
132 {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Write Status Register
133 {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID
134 {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Bulk erase
135 }
Dominik Geyerb46acba2008-05-16 12:55:55 +0000136};
137
Dominik Geyerb46acba2008-05-16 12:55:55 +0000138int program_opcodes(OPCODES * op)
139{
140 uint8_t a;
141 uint16_t temp16;
142 uint32_t temp32;
143
144 /* Program Prefix Opcodes */
145 temp16 = 0;
146 /* 0:7 Prefix Opcode 1 */
147 temp16 = (op->preop[0]);
148 /* 8:16 Prefix Opcode 2 */
149 temp16 |= ((uint16_t) op->preop[1]) << 8;
150 REGWRITE16(REG_PREOP, temp16);
151
152 /*Program Opcode Types 0 - 7 */
153 temp16 = 0;
154 for (a = 0; a < 8; a++) {
155 temp16 |= ((uint16_t) op->opcode[a].spi_type) << (a * 2);
156 }
157 REGWRITE16(REG_OPTYPE, temp16);
158
159 /*Program Allowable Opcodes 0 - 3 */
160 temp32 = 0;
161 for (a = 0; a < 4; a++) {
162 temp32 |= ((uint32_t) op->opcode[a].opcode) << (a * 8);
163 }
164 REGWRITE32(REG_OPMENU, temp32);
165
166 /*Program Allowable Opcodes 4 - 7 */
167 temp32 = 0;
168 for (a = 4; a < 8; a++) {
169 temp32 |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
170 }
171 REGWRITE32(REG_OPMENU + 4, temp32);
172
173 return 0;
174}
175
176int run_opcode(uint8_t nr, OPCODE op, uint32_t offset, uint8_t datalength,
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000177 uint8_t * data)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000178{
179 int write_cmd = 0;
180 uint32_t temp32;
181 uint32_t a;
182
183 /* Is it a write command? */
184 if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
185 || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
186 write_cmd = 1;
187 }
188
189 /* Programm Offset in Flash into FADDR */
190 REGWRITE32(REG_FADDR, (offset & 0x00FFFFFF)); /*SPI addresses are 24 BIT only */
191
192 /* Program data into FDATA0 to N */
193 if (write_cmd && (datalength != 0)) {
194 temp32 = 0;
195 for (a = 0; a < datalength; a++) {
196 if ((a % 4) == 0) {
197 temp32 = 0;
198 }
199
200 temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
201
202 if ((a % 4) == 3) {
203 REGWRITE32(REG_FDATA0 + (a - (a % 4)), temp32);
204 }
205 }
206 if (((a - 1) % 4) != 3) {
207 REGWRITE32(REG_FDATA0 + ((a - 1) - ((a - 1) % 4)),
208 temp32);
209 }
210
211 }
212
213 /* Assemble SSFS + SSFC */
214 temp32 = 0;
215
216 /* clear error status registers */
217 temp32 |= (SSFS_CDS + SSFS_FCERR);
218 /* USE 20 MhZ */
219 temp32 |= SSFC_SCF_20MHZ;
220
221 if (datalength != 0) {
222 uint32_t datatemp;
223 temp32 |= SSFC_DS;
224 datatemp = ((uint32_t) ((datalength - 1) & 0x3f)) << (8 + 8);
225 temp32 |= datatemp;
226 }
227
228 /* Select opcode */
229 temp32 |= ((uint32_t) (nr & 0x07)) << (8 + 4);
230
231 /* Handle Atomic */
232 if (op.atomic != 0) {
233 /* Select atomic command */
234 temp32 |= SSFC_ACS;
235 /* Selct prefix opcode */
236 if ((op.atomic - 1) == 1) {
237 /*Select prefix opcode 2 */
238 temp32 |= SSFC_SPOP;
239 }
240 }
241
242 /* Start */
243 temp32 |= SSFC_SCGO;
244
245 /* write it */
246 REGWRITE32(REG_SSFS, temp32);
247
248 /*wait for cycle complete */
249 while ((REGREAD32(REG_SSFS) & SSFS_CDS) == 0) {
250 /*TODO; Do something that this can't lead into an endless loop. but some
251 * commands may cause this to be last more than 30 seconds */
252 }
253
254 if ((REGREAD32(REG_SSFS) & SSFS_FCERR) != 0) {
255 printf_debug("Transaction error!\n");
256 return 1;
257 }
258
259 if ((!write_cmd) && (datalength != 0)) {
260 for (a = 0; a < datalength; a++) {
261 if ((a % 4) == 0) {
262 temp32 = REGREAD32(REG_FDATA0 + (a));
263 }
264
265 data[a] =
266 (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8))) >>
267 ((a % 4) * 8);
268 }
269 }
270
271 return 0;
272}
273
Dominik Geyerb46acba2008-05-16 12:55:55 +0000274static int ich_spi_erase_block(struct flashchip *flash, int offset)
275{
276 printf_debug("Spi_Erase,Offset=%d,sectors=%d\n", offset, 1);
277
278 if (run_opcode(2, curopcodes->opcode[2], offset, 0, NULL) != 0) {
279 printf_debug("Error erasing sector at 0x%x", offset);
280 return -1;
281 }
282
283 printf("DONE BLOCK 0x%x\n", offset);
284
285 return 0;
286}
287
288static int ich_spi_read_page(struct flashchip *flash, uint8_t * buf, int Offset)
289{
290 int page_size = flash->page_size;
291 uint32_t remaining = flash->page_size;
292 int a;
293
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000294 printf_debug("Spi_Read,Offset=%d,number=%d,buf=%p\n", Offset, page_size,
295 buf);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000296
297 for (a = 0; a < page_size; a += MAXDATABYTES) {
298 if (remaining < MAXDATABYTES) {
299
300 if (run_opcode
301 (1, curopcodes->opcode[1],
302 Offset + (page_size - remaining), remaining,
303 &buf[page_size - remaining]) != 0) {
304 printf_debug("Error reading");
305 return 1;
306 }
307 remaining = 0;
308 } else {
309 if (run_opcode
310 (1, curopcodes->opcode[1],
311 Offset + (page_size - remaining), MAXDATABYTES,
312 &buf[page_size - remaining]) != 0) {
313 printf_debug("Error reading");
314 return 1;
315 }
316 remaining -= MAXDATABYTES;
317 }
318 }
319
320 return 0;
321}
322
323static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000324 int Offset)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000325{
326 int page_size = flash->page_size;
327 uint32_t remaining = page_size;
328 int a;
329
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000330 printf_debug("write_page_ichspi,Offset=%d,number=%d,buf=%p\n", Offset,
331 page_size, bytes);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000332
333 for (a = 0; a < page_size; a += MAXDATABYTES) {
334 if (remaining < MAXDATABYTES) {
335 if (run_opcode
336 (0, curopcodes->opcode[0],
337 Offset + (page_size - remaining), remaining,
338 &bytes[page_size - remaining]) != 0) {
339 printf_debug("Error writing");
340 return 1;
341 }
342 remaining = 0;
343 } else {
344 if (run_opcode
345 (0, curopcodes->opcode[0],
346 Offset + (page_size - remaining), MAXDATABYTES,
347 &bytes[page_size - remaining]) != 0) {
348 printf_debug("Error writing");
349 return 1;
350 }
351 remaining -= MAXDATABYTES;
352 }
353 }
354
355 return 0;
356}
357
Dominik Geyerb46acba2008-05-16 12:55:55 +0000358int ich_spi_read(struct flashchip *flash, uint8_t * buf)
359{
360 int i, rc = 0;
361 int total_size = flash->total_size * 1024;
362 int page_size = flash->page_size;
363
364 for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
365 rc = ich_spi_read_page(flash, (void *)(buf + i * page_size),
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000366 i * page_size);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000367 }
368
369 return rc;
370}
371
Dominik Geyerb46acba2008-05-16 12:55:55 +0000372int ich_spi_write(struct flashchip *flash, uint8_t * buf)
373{
374 int i, j, rc = 0;
375 int total_size = flash->total_size * 1024;
376 int page_size = flash->page_size;
377 int erase_size = 64 * 1024;
378
379 spi_disable_blockprotect();
380
381 printf("Programming page: \n");
382
383 for (i = 0; i < total_size / erase_size; i++) {
384 rc = ich_spi_erase_block(flash, i * erase_size);
385 if (rc) {
386 printf("Error erasing block at 0x%x\n", i);
387 break;
388 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000389
Dominik Geyerb46acba2008-05-16 12:55:55 +0000390 for (j = 0; j < erase_size / page_size; j++) {
391 ich_spi_write_page(flash, (void *)(buf + (i * erase_size) + (j * page_size)),
392 (i * erase_size) + (j * page_size));
393 }
394 }
395
396 printf("\n");
397
398 return rc;
399}
400
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000401int ich_spi_command(unsigned int writecnt, unsigned int readcnt,
402 const unsigned char *writearr, unsigned char *readarr)
Dominik Geyerb46acba2008-05-16 12:55:55 +0000403{
404 int a;
405 int opcode_index = -1;
406 const unsigned char cmd = *writearr;
407 OPCODE *opcode;
408 uint32_t addr = 0;
409 uint8_t *data;
410 int count;
411
412 /* program opcodes if not already done */
413 if (curopcodes == NULL) {
414 printf_debug("Programming OPCODES\n");
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000415 curopcodes = &O_ST_M25P;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000416 program_opcodes(curopcodes);
417 }
418
419 /* find cmd in opcodes-table */
420 for (a = 0; a < 8; a++) {
421 if ((curopcodes->opcode[a]).opcode == cmd) {
422 opcode_index = a;
423 break;
424 }
425 }
426
427 /* unknown / not programmed command */
428 if (opcode_index == -1) {
429 printf_debug("Invalid OPCODE 0x%02x\n", cmd);
430 return 1;
431 }
432
433 opcode = &(curopcodes->opcode[opcode_index]);
434
435 /* if opcode-type requires an address */
436 if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS ||
437 opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000438 addr = (writearr[1] << 16) |
439 (writearr[2] << 8) | (writearr[3] << 0);
Dominik Geyerb46acba2008-05-16 12:55:55 +0000440 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000441
Dominik Geyerb46acba2008-05-16 12:55:55 +0000442 /* translate read/write array/count */
443 if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) {
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000444 data = (uint8_t *) (writearr + 1);
445 count = writecnt - 1;
446 } else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
447 data = (uint8_t *) (writearr + 4);
448 count = writecnt - 4;
449 } else {
450 data = (uint8_t *) readarr;
Dominik Geyerb46acba2008-05-16 12:55:55 +0000451 count = readcnt;
452 }
Stefan Reinauer325b5d42008-06-27 15:18:20 +0000453
Dominik Geyerb46acba2008-05-16 12:55:55 +0000454 if (run_opcode(opcode_index, *opcode, addr, count, data) != 0) {
455 printf_debug("run OPCODE 0x%02x failed\n", opcode->opcode);
456 return 1;
457 }
458
459 return 0;
460}