blob: 2ca5842d852e99a603223cc42d6aefa3c2ccf208 [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
Stefan Reinauer7ed78c82007-05-24 09:26:39 +00006 * Copyright 2005-2007 coresystems GmbH
Yinghai Luca782972007-01-22 20:21:17 +00007 *
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>
Yinghai Luca782972007-01-22 20:21:17 +000035#include "flash.h"
Yinghai Luca782972007-01-22 20:21:17 +000036
37#define SECTOR_ERASE 0x30
38#define BLOCK_ERASE 0x20
39#define ERASE 0xD0
40#define AUTO_PGRM 0x10
41#define RESET 0xFF
42#define READ_ID 0x90
43#define READ_STATUS 0x70
44#define CLEAR_STATUS 0x50
45
46#define STATUS_BPS (1 << 1)
47#define STATUS_ESS (1 << 6)
48#define STATUS_WSMS (1 << 7)
49
Yinghai Luca782972007-01-22 20:21:17 +000050static __inline__ int write_lockbits_49lfxxxc(volatile uint8_t *bios, int size,
Uwe Hermanna7e05482007-05-09 10:17:44 +000051 unsigned char bits)
Yinghai Luca782972007-01-22 20:21:17 +000052{
53 int i, left = size;
54 unsigned long address;
55
56 //printf("bios=0x%08lx\n", (unsigned long)bios);
57 for (i = 0; left > 65536; i++, left -= 65536) {
58 //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFC00000 - size + (i * 65536) + 2, *(bios + (i * 65536) + 2) );
59 *(bios + (i * 65536) + 2) = bits;
60 }
61 address = i * 65536;
Uwe Hermanna7e05482007-05-09 10:17:44 +000062 //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 +000063 *(bios + address + 2) = bits;
64 address += 32768;
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 += 8192;
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
Uwe Hermannffec5f32007-08-23 16:08:21 +000074 return 0;
Yinghai Luca782972007-01-22 20:21:17 +000075}
76
77static __inline__ int erase_sector_49lfxxxc(volatile uint8_t *bios,
Uwe Hermanna7e05482007-05-09 10:17:44 +000078 unsigned long address)
Yinghai Luca782972007-01-22 20:21:17 +000079{
80 unsigned char status;
81
82 *bios = SECTOR_ERASE;
83 *(bios + address) = ERASE;
84
85 do {
Uwe Hermanna7e05482007-05-09 10:17:44 +000086 status = *bios;
Yinghai Luca782972007-01-22 20:21:17 +000087 if (status & (STATUS_ESS | STATUS_BPS)) {
Uwe Hermanna7e05482007-05-09 10:17:44 +000088 printf("sector erase FAILED at address=0x%08lx status=0x%01x\n", (unsigned long)bios + address, status);
Yinghai Luca782972007-01-22 20:21:17 +000089 *bios = CLEAR_STATUS;
Uwe Hermanna7e05482007-05-09 10:17:44 +000090 return (-1);
Yinghai Luca782972007-01-22 20:21:17 +000091 }
Uwe Hermanna7e05482007-05-09 10:17:44 +000092 } while (!(status & STATUS_WSMS));
Yinghai Luca782972007-01-22 20:21:17 +000093
Uwe Hermannffec5f32007-08-23 16:08:21 +000094 return 0;
Yinghai Luca782972007-01-22 20:21:17 +000095}
96
97static __inline__ int write_sector_49lfxxxc(volatile uint8_t *bios,
Uwe Hermanna7e05482007-05-09 10:17:44 +000098 uint8_t *src,
99 volatile uint8_t *dst,
100 unsigned int page_size)
Yinghai Luca782972007-01-22 20:21:17 +0000101{
102 int i;
103 unsigned char status;
104
105 *bios = CLEAR_STATUS;
106 for (i = 0; i < page_size; i++) {
107 /* transfer data from source to destination */
108 if (*src == 0xFF) {
109 dst++, src++;
110 /* If the data is 0xFF, don't program it */
111 continue;
112 }
113 /*issue AUTO PROGRAM command */
114 *bios = AUTO_PGRM;
115 *dst++ = *src++;
116
117 do {
118 status = *bios;
119 if (status & (STATUS_ESS | STATUS_BPS)) {
Uwe Hermanna7e05482007-05-09 10:17:44 +0000120 printf("sector write FAILED at address=0x%08lx status=0x%01x\n", (unsigned long)dst, status);
Yinghai Luca782972007-01-22 20:21:17 +0000121 *bios = CLEAR_STATUS;
Uwe Hermanna7e05482007-05-09 10:17:44 +0000122 return (-1);
Yinghai Luca782972007-01-22 20:21:17 +0000123 }
124 } while (!(status & STATUS_WSMS));
125 }
126
Uwe Hermannffec5f32007-08-23 16:08:21 +0000127 return 0;
Yinghai Luca782972007-01-22 20:21:17 +0000128}
129
130int probe_49lfxxxc(struct flashchip *flash)
131{
Stefan Reinauerce532972007-05-23 17:20:56 +0000132 volatile uint8_t *bios = flash->virtual_memory;
Stefan Reinauerce532972007-05-23 17:20:56 +0000133
Yinghai Luca782972007-01-22 20:21:17 +0000134 uint8_t id1, id2;
Yinghai Luca782972007-01-22 20:21:17 +0000135
136 *bios = RESET;
137
138 *bios = READ_ID;
Uwe Hermanna7e05482007-05-09 10:17:44 +0000139 id1 = *(volatile uint8_t *)bios;
140 id2 = *(volatile uint8_t *)(bios + 0x01);
Yinghai Luca782972007-01-22 20:21:17 +0000141
142 *bios = RESET;
143
144 printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2);
Stefan Reinauerff4f1972007-05-24 08:48:10 +0000145
Yinghai Luca782972007-01-22 20:21:17 +0000146 if (!(id1 == flash->manufacture_id && id2 == flash->model_id))
147 return 0;
148
Stefan Reinauerff4f1972007-05-24 08:48:10 +0000149 map_flash_registers(flash);
150
Yinghai Luca782972007-01-22 20:21:17 +0000151 return 1;
152}
153
154int erase_49lfxxxc(struct flashchip *flash)
155{
Stefan Reinauerce532972007-05-23 17:20:56 +0000156 volatile uint8_t *bios = flash->virtual_memory;
157 volatile uint8_t *registers = flash->virtual_registers;
Yinghai Luca782972007-01-22 20:21:17 +0000158 int i;
159 unsigned int total_size = flash->total_size * 1024;
160
Stefan Reinauerce532972007-05-23 17:20:56 +0000161 write_lockbits_49lfxxxc(registers, total_size, 0);
Yinghai Luca782972007-01-22 20:21:17 +0000162 for (i = 0; i < total_size; i += flash->page_size)
Uwe Hermanna7e05482007-05-09 10:17:44 +0000163 if (erase_sector_49lfxxxc(bios, i) != 0)
164 return (-1);
Yinghai Luca782972007-01-22 20:21:17 +0000165
166 *bios = RESET;
Uwe Hermannffec5f32007-08-23 16:08:21 +0000167
168 return 0;
Yinghai Luca782972007-01-22 20:21:17 +0000169}
170
171int write_49lfxxxc(struct flashchip *flash, uint8_t *buf)
172{
173 int i;
Uwe Hermanna7e05482007-05-09 10:17:44 +0000174 int total_size = flash->total_size * 1024;
175 int page_size = flash->page_size;
Stefan Reinauerce532972007-05-23 17:20:56 +0000176 volatile uint8_t *bios = flash->virtual_memory;
Yinghai Luca782972007-01-22 20:21:17 +0000177
Stefan Reinauerce532972007-05-23 17:20:56 +0000178 write_lockbits_49lfxxxc(flash->virtual_registers, total_size, 0);
Yinghai Luca782972007-01-22 20:21:17 +0000179 printf("Programming Page: ");
180 for (i = 0; i < total_size / page_size; i++) {
181 /* erase the page before programming */
182 erase_sector_49lfxxxc(bios, i * page_size);
183
184 /* write to the sector */
185 printf("%04d at address: 0x%08x", i, i * page_size);
186 write_sector_49lfxxxc(bios, buf + i * page_size,
Uwe Hermanna7e05482007-05-09 10:17:44 +0000187 bios + i * page_size, page_size);
Yinghai Luca782972007-01-22 20:21:17 +0000188 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");
189 }
190 printf("\n");
191
192 *bios = RESET;
Uwe Hermannffec5f32007-08-23 16:08:21 +0000193
194 return 0;
Yinghai Luca782972007-01-22 20:21:17 +0000195}