blob: 16f84df4a15b329a62541ef288bfb9471089a2a4 [file] [log] [blame]
Yinghai Luca782972007-01-22 20:21:17 +00001/*
2 * 49lfxxxc.c: driver for SST49LFXXXC flash models.
3 *
4 *
5 * Copyright 2000 Silicon Integrated System Corporation
6 * Copyright 2005 coresystems GmbH <stepan@openbios.org>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 *
23 * Reference:
24 * SST49LFxxxC data sheets
25 *
26 */
27
28#include <errno.h>
29#include <fcntl.h>
30#include <sys/mman.h>
Yinghai Luca782972007-01-22 20:21:17 +000031#include <unistd.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <stdint.h>
Adam Kaufman064b1f22007-02-06 19:47:50 +000035
Yinghai Luca782972007-01-22 20:21:17 +000036#include "flash.h"
37#include "jedec.h"
38#include "debug.h"
39
40#define SECTOR_ERASE 0x30
41#define BLOCK_ERASE 0x20
42#define ERASE 0xD0
43#define AUTO_PGRM 0x10
44#define RESET 0xFF
45#define READ_ID 0x90
46#define READ_STATUS 0x70
47#define CLEAR_STATUS 0x50
48
49#define STATUS_BPS (1 << 1)
50#define STATUS_ESS (1 << 6)
51#define STATUS_WSMS (1 << 7)
52
Yinghai Luca782972007-01-22 20:21:17 +000053static __inline__ int write_lockbits_49lfxxxc(volatile uint8_t *bios, int size,
Uwe Hermanna7e05482007-05-09 10:17:44 +000054 unsigned char bits)
Yinghai Luca782972007-01-22 20:21:17 +000055{
56 int i, left = size;
57 unsigned long address;
58
59 //printf("bios=0x%08lx\n", (unsigned long)bios);
60 for (i = 0; left > 65536; i++, left -= 65536) {
61 //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFC00000 - size + (i * 65536) + 2, *(bios + (i * 65536) + 2) );
62 *(bios + (i * 65536) + 2) = bits;
63 }
64 address = i * 65536;
Uwe Hermanna7e05482007-05-09 10:17:44 +000065 //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) );
Yinghai Luca782972007-01-22 20:21:17 +000066 *(bios + address + 2) = bits;
67 address += 32768;
Uwe Hermanna7e05482007-05-09 10:17:44 +000068 //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) );
Yinghai Luca782972007-01-22 20:21:17 +000069 *(bios + address + 2) = bits;
70 address += 8192;
Uwe Hermanna7e05482007-05-09 10:17:44 +000071 //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) );
Yinghai Luca782972007-01-22 20:21:17 +000072 *(bios + address + 2) = bits;
73 address += 8192;
Uwe Hermanna7e05482007-05-09 10:17:44 +000074 //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) );
Yinghai Luca782972007-01-22 20:21:17 +000075 *(bios + address + 2) = bits;
76
Yinghai Luca782972007-01-22 20:21:17 +000077 return (0);
78}
79
80static __inline__ int erase_sector_49lfxxxc(volatile uint8_t *bios,
Uwe Hermanna7e05482007-05-09 10:17:44 +000081 unsigned long address)
Yinghai Luca782972007-01-22 20:21:17 +000082{
83 unsigned char status;
84
85 *bios = SECTOR_ERASE;
86 *(bios + address) = ERASE;
87
88 do {
Uwe Hermanna7e05482007-05-09 10:17:44 +000089 status = *bios;
Yinghai Luca782972007-01-22 20:21:17 +000090 if (status & (STATUS_ESS | STATUS_BPS)) {
Uwe Hermanna7e05482007-05-09 10:17:44 +000091 printf("sector erase FAILED at address=0x%08lx status=0x%01x\n", (unsigned long)bios + address, status);
Yinghai Luca782972007-01-22 20:21:17 +000092 *bios = CLEAR_STATUS;
Uwe Hermanna7e05482007-05-09 10:17:44 +000093 return (-1);
Yinghai Luca782972007-01-22 20:21:17 +000094 }
Uwe Hermanna7e05482007-05-09 10:17:44 +000095 } while (!(status & STATUS_WSMS));
Yinghai Luca782972007-01-22 20:21:17 +000096
97 return (0);
98}
99
100static __inline__ int write_sector_49lfxxxc(volatile uint8_t *bios,
Uwe Hermanna7e05482007-05-09 10:17:44 +0000101 uint8_t *src,
102 volatile uint8_t *dst,
103 unsigned int page_size)
Yinghai Luca782972007-01-22 20:21:17 +0000104{
105 int i;
106 unsigned char status;
107
108 *bios = CLEAR_STATUS;
109 for (i = 0; i < page_size; i++) {
110 /* transfer data from source to destination */
111 if (*src == 0xFF) {
112 dst++, src++;
113 /* If the data is 0xFF, don't program it */
114 continue;
115 }
116 /*issue AUTO PROGRAM command */
117 *bios = AUTO_PGRM;
118 *dst++ = *src++;
119
120 do {
121 status = *bios;
122 if (status & (STATUS_ESS | STATUS_BPS)) {
Uwe Hermanna7e05482007-05-09 10:17:44 +0000123 printf("sector write FAILED at address=0x%08lx status=0x%01x\n", (unsigned long)dst, status);
Yinghai Luca782972007-01-22 20:21:17 +0000124 *bios = CLEAR_STATUS;
Uwe Hermanna7e05482007-05-09 10:17:44 +0000125 return (-1);
Yinghai Luca782972007-01-22 20:21:17 +0000126 }
127 } while (!(status & STATUS_WSMS));
128 }
129
130 return (0);
131}
132
133int probe_49lfxxxc(struct flashchip *flash)
134{
Stefan Reinauerce532972007-05-23 17:20:56 +0000135 volatile uint8_t *bios = flash->virtual_memory;
Stefan Reinauerce532972007-05-23 17:20:56 +0000136
Yinghai Luca782972007-01-22 20:21:17 +0000137 uint8_t id1, id2;
Yinghai Luca782972007-01-22 20:21:17 +0000138
139 *bios = RESET;
140
141 *bios = READ_ID;
Uwe Hermanna7e05482007-05-09 10:17:44 +0000142 id1 = *(volatile uint8_t *)bios;
143 id2 = *(volatile uint8_t *)(bios + 0x01);
Yinghai Luca782972007-01-22 20:21:17 +0000144
145 *bios = RESET;
146
147 printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2);
Stefan Reinauerff4f1972007-05-24 08:48:10 +0000148
Yinghai Luca782972007-01-22 20:21:17 +0000149 if (!(id1 == flash->manufacture_id && id2 == flash->model_id))
150 return 0;
151
Stefan Reinauerff4f1972007-05-24 08:48:10 +0000152 map_flash_registers(flash);
153
Yinghai Luca782972007-01-22 20:21:17 +0000154 return 1;
155}
156
157int erase_49lfxxxc(struct flashchip *flash)
158{
Stefan Reinauerce532972007-05-23 17:20:56 +0000159 volatile uint8_t *bios = flash->virtual_memory;
160 volatile uint8_t *registers = flash->virtual_registers;
Yinghai Luca782972007-01-22 20:21:17 +0000161 int i;
162 unsigned int total_size = flash->total_size * 1024;
163
Stefan Reinauerce532972007-05-23 17:20:56 +0000164 write_lockbits_49lfxxxc(registers, total_size, 0);
Yinghai Luca782972007-01-22 20:21:17 +0000165 for (i = 0; i < total_size; i += flash->page_size)
Uwe Hermanna7e05482007-05-09 10:17:44 +0000166 if (erase_sector_49lfxxxc(bios, i) != 0)
167 return (-1);
Yinghai Luca782972007-01-22 20:21:17 +0000168
169 *bios = RESET;
170 return (0);
171}
172
173int write_49lfxxxc(struct flashchip *flash, uint8_t *buf)
174{
175 int i;
Uwe Hermanna7e05482007-05-09 10:17:44 +0000176 int total_size = flash->total_size * 1024;
177 int page_size = flash->page_size;
Stefan Reinauerce532972007-05-23 17:20:56 +0000178 volatile uint8_t *bios = flash->virtual_memory;
Yinghai Luca782972007-01-22 20:21:17 +0000179
Stefan Reinauerce532972007-05-23 17:20:56 +0000180 write_lockbits_49lfxxxc(flash->virtual_registers, total_size, 0);
Yinghai Luca782972007-01-22 20:21:17 +0000181 printf("Programming Page: ");
182 for (i = 0; i < total_size / page_size; i++) {
183 /* erase the page before programming */
184 erase_sector_49lfxxxc(bios, i * page_size);
185
186 /* write to the sector */
187 printf("%04d at address: 0x%08x", i, i * page_size);
188 write_sector_49lfxxxc(bios, buf + i * page_size,
Uwe Hermanna7e05482007-05-09 10:17:44 +0000189 bios + i * page_size, page_size);
Yinghai Luca782972007-01-22 20:21:17 +0000190 printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
191 }
192 printf("\n");
193
194 *bios = RESET;
195 return (0);
196}