blob: 4486186bd7c7ee40c7a5788e52a1d1f841fa9013 [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
53
54static __inline__ int write_lockbits_49lfxxxc(volatile uint8_t *bios, int size,
55 unsigned char bits)
56{
57 int i, left = size;
58 unsigned long address;
59
60 //printf("bios=0x%08lx\n", (unsigned long)bios);
61 for (i = 0; left > 65536; i++, left -= 65536) {
62 //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFC00000 - size + (i * 65536) + 2, *(bios + (i * 65536) + 2) );
63 *(bios + (i * 65536) + 2) = bits;
64 }
65 address = i * 65536;
66 //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) );
67 *(bios + address + 2) = bits;
68 address += 32768;
69 //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) );
70 *(bios + address + 2) = bits;
71 address += 8192;
72 //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) );
73 *(bios + address + 2) = bits;
74 address += 8192;
75 //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) );
76 *(bios + address + 2) = bits;
77
78
79 return (0);
80}
81
82static __inline__ int erase_sector_49lfxxxc(volatile uint8_t *bios,
83 unsigned long address)
84{
85 unsigned char status;
86
87 *bios = SECTOR_ERASE;
88 *(bios + address) = ERASE;
89
90 do {
91 status = *bios;
92 if (status & (STATUS_ESS | STATUS_BPS)) {
93 printf("sector erase FAILED at address=0x%08lx status=0x%01x\n", (unsigned long)bios + address, status);
94 *bios = CLEAR_STATUS;
95 return(-1);
96 }
97 } while (!(status & STATUS_WSMS));
98
99 return (0);
100}
101
102static __inline__ int write_sector_49lfxxxc(volatile uint8_t *bios,
103 uint8_t *src,
104 volatile uint8_t *dst,
105 unsigned int page_size)
106{
107 int i;
108 unsigned char status;
109
110 *bios = CLEAR_STATUS;
111 for (i = 0; i < page_size; i++) {
112 /* transfer data from source to destination */
113 if (*src == 0xFF) {
114 dst++, src++;
115 /* If the data is 0xFF, don't program it */
116 continue;
117 }
118 /*issue AUTO PROGRAM command */
119 *bios = AUTO_PGRM;
120 *dst++ = *src++;
121
122 do {
123 status = *bios;
124 if (status & (STATUS_ESS | STATUS_BPS)) {
125 printf("sector write FAILED at address=0x%08lx status=0x%01x\n", (unsigned long)dst, status);
126 *bios = CLEAR_STATUS;
127 return(-1);
128 }
129 } while (!(status & STATUS_WSMS));
130 }
131
132 return (0);
133}
134
135int probe_49lfxxxc(struct flashchip *flash)
136{
137 volatile uint8_t *bios = flash->virt_addr;
138 uint8_t id1, id2;
139 size_t size = flash->total_size * 1024;
140
141 *bios = RESET;
142
143 *bios = READ_ID;
144 id1 = *(volatile uint8_t *) bios;
145 id2 = *(volatile uint8_t *) (bios + 0x01);
146
147 *bios = RESET;
148
149 printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2);
150 if (!(id1 == flash->manufacture_id && id2 == flash->model_id))
151 return 0;
152
153 bios = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED,
154 flash->fd_mem, (off_t) (0xFFFFFFFF - 0x400000 - size + 1));
155 if (bios == MAP_FAILED) {
156 // it's this part but we can't map it ...
157 perror("Error MMAP /dev/mem");
158 exit(1);
159 }
160 flash->virt_addr_2 = bios;
161 return 1;
162}
163
164int erase_49lfxxxc(struct flashchip *flash)
165{
166 volatile uint8_t *bios = flash->virt_addr;
167 volatile uint8_t *bios2 = flash->virt_addr_2;
168 int i;
169 unsigned int total_size = flash->total_size * 1024;
170
171 write_lockbits_49lfxxxc(bios2, total_size, 0);
172 for (i = 0; i < total_size; i += flash->page_size)
173 if (erase_sector_49lfxxxc(bios, i) != 0 )
174 return (-1);
175
176 *bios = RESET;
177 return (0);
178}
179
180int write_49lfxxxc(struct flashchip *flash, uint8_t *buf)
181{
182 int i;
183 int total_size = flash->total_size * 1024, page_size =
184 flash->page_size;
185 volatile uint8_t *bios = flash->virt_addr;
186
187
188 write_lockbits_49lfxxxc(flash->virt_addr_2, total_size, 0);
189 printf("Programming Page: ");
190 for (i = 0; i < total_size / page_size; i++) {
191 /* erase the page before programming */
192 erase_sector_49lfxxxc(bios, i * page_size);
193
194 /* write to the sector */
195 printf("%04d at address: 0x%08x", i, i * page_size);
196 write_sector_49lfxxxc(bios, buf + i * page_size,
197 bios + i * page_size, page_size);
198 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");
199 }
200 printf("\n");
201
202 *bios = RESET;
203 return (0);
204}