blob: 52f865a225afabfe3700f2e76a4c94be32174c19 [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{
135 volatile uint8_t *bios = flash->virt_addr;
136 uint8_t id1, id2;
137 size_t size = flash->total_size * 1024;
138
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);
148 if (!(id1 == flash->manufacture_id && id2 == flash->model_id))
149 return 0;
150
151 bios = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED,
Stefan Reinauer70385642007-04-06 11:58:03 +0000152 fd_mem, (off_t) (0xFFFFFFFF - 0x400000 - size + 1));
Yinghai Luca782972007-01-22 20:21:17 +0000153 if (bios == MAP_FAILED) {
154 // it's this part but we can't map it ...
155 perror("Error MMAP /dev/mem");
156 exit(1);
157 }
158 flash->virt_addr_2 = bios;
159 return 1;
160}
161
162int erase_49lfxxxc(struct flashchip *flash)
163{
164 volatile uint8_t *bios = flash->virt_addr;
165 volatile uint8_t *bios2 = flash->virt_addr_2;
166 int i;
167 unsigned int total_size = flash->total_size * 1024;
168
169 write_lockbits_49lfxxxc(bios2, total_size, 0);
170 for (i = 0; i < total_size; i += flash->page_size)
Uwe Hermanna7e05482007-05-09 10:17:44 +0000171 if (erase_sector_49lfxxxc(bios, i) != 0)
172 return (-1);
Yinghai Luca782972007-01-22 20:21:17 +0000173
174 *bios = RESET;
175 return (0);
176}
177
178int write_49lfxxxc(struct flashchip *flash, uint8_t *buf)
179{
180 int i;
Uwe Hermanna7e05482007-05-09 10:17:44 +0000181 int total_size = flash->total_size * 1024;
182 int page_size = flash->page_size;
Yinghai Luca782972007-01-22 20:21:17 +0000183 volatile uint8_t *bios = flash->virt_addr;
184
Yinghai Luca782972007-01-22 20:21:17 +0000185 write_lockbits_49lfxxxc(flash->virt_addr_2, total_size, 0);
186 printf("Programming Page: ");
187 for (i = 0; i < total_size / page_size; i++) {
188 /* erase the page before programming */
189 erase_sector_49lfxxxc(bios, i * page_size);
190
191 /* write to the sector */
192 printf("%04d at address: 0x%08x", i, i * page_size);
193 write_sector_49lfxxxc(bios, buf + i * page_size,
Uwe Hermanna7e05482007-05-09 10:17:44 +0000194 bios + i * page_size, page_size);
Yinghai Luca782972007-01-22 20:21:17 +0000195 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");
196 }
197 printf("\n");
198
199 *bios = RESET;
200 return (0);
201}