b6693efb11d5e22076b0484cdc0b18633bf13c64
[coreboot.git] / util / flashrom / sst49lfxxxc.c
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2000 Silicon Integrated System Corporation
5  * Copyright (C) 2005-2007 coresystems GmbH
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
20  */
21
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <sys/mman.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include "flash.h"
30
31 #define SECTOR_ERASE            0x30
32 #define BLOCK_ERASE             0x20
33 #define ERASE                   0xD0
34 #define AUTO_PGRM               0x10
35 #define RESET                   0xFF
36 #define READ_ID                 0x90
37 #define READ_STATUS             0x70
38 #define CLEAR_STATUS            0x50
39
40 #define STATUS_BPS              (1 << 1)
41 #define STATUS_ESS              (1 << 6)
42 #define STATUS_WSMS             (1 << 7)
43
44 static __inline__ int write_lockbits_49lfxxxc(volatile uint8_t *bios, int size,
45                                               unsigned char bits)
46 {
47         int i, left = size;
48         unsigned long address;
49
50         //printf("bios=0x%08lx\n", (unsigned long)bios);
51         for (i = 0; left > 65536; i++, left -= 65536) {
52                 //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFC00000 - size + (i * 65536) + 2, *(bios + (i * 65536) + 2) );
53                 *(bios + (i * 65536) + 2) = bits;
54         }
55         address = i * 65536;
56         //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) );
57         *(bios + address + 2) = bits;
58         address += 32768;
59         //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) );
60         *(bios + address + 2) = bits;
61         address += 8192;
62         //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) );
63         *(bios + address + 2) = bits;
64         address += 8192;
65         //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) );
66         *(bios + address + 2) = bits;
67
68         return 0;
69 }
70
71 static __inline__ int erase_sector_49lfxxxc(volatile uint8_t *bios,
72                                             unsigned long address)
73 {
74         unsigned char status;
75
76         *bios = SECTOR_ERASE;
77         *(bios + address) = ERASE;
78
79         do {
80                 status = *bios;
81                 if (status & (STATUS_ESS | STATUS_BPS)) {
82                         printf("sector erase FAILED at address=0x%08lx status=0x%01x\n", (unsigned long)bios + address, status);
83                         *bios = CLEAR_STATUS;
84                         return (-1);
85                 }
86         } while (!(status & STATUS_WSMS));
87
88         return 0;
89 }
90
91 static __inline__ int write_sector_49lfxxxc(volatile uint8_t *bios,
92                                             uint8_t *src,
93                                             volatile uint8_t *dst,
94                                             unsigned int page_size)
95 {
96         int i;
97         unsigned char status;
98
99         *bios = CLEAR_STATUS;
100         for (i = 0; i < page_size; i++) {
101                 /* transfer data from source to destination */
102                 if (*src == 0xFF) {
103                         dst++, src++;
104                         /* If the data is 0xFF, don't program it */
105                         continue;
106                 }
107                 /*issue AUTO PROGRAM command */
108                 *bios = AUTO_PGRM;
109                 *dst++ = *src++;
110
111                 do {
112                         status = *bios;
113                         if (status & (STATUS_ESS | STATUS_BPS)) {
114                                 printf("sector write FAILED at address=0x%08lx status=0x%01x\n", (unsigned long)dst, status);
115                                 *bios = CLEAR_STATUS;
116                                 return (-1);
117                         }
118                 } while (!(status & STATUS_WSMS));
119         }
120
121         return 0;
122 }
123
124 int probe_49lfxxxc(struct flashchip *flash)
125 {
126         volatile uint8_t *bios = flash->virtual_memory;
127
128         uint8_t id1, id2;
129
130         *bios = RESET;
131
132         *bios = READ_ID;
133         id1 = *(volatile uint8_t *)bios;
134         id2 = *(volatile uint8_t *)(bios + 0x01);
135
136         *bios = RESET;
137
138         printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2);
139
140         if (!(id1 == flash->manufacture_id && id2 == flash->model_id))
141                 return 0;
142
143         map_flash_registers(flash);
144
145         return 1;
146 }
147
148 int erase_49lfxxxc(struct flashchip *flash)
149 {
150         volatile uint8_t *bios = flash->virtual_memory;
151         volatile uint8_t *registers = flash->virtual_registers;
152         int i;
153         unsigned int total_size = flash->total_size * 1024;
154
155         write_lockbits_49lfxxxc(registers, total_size, 0);
156         for (i = 0; i < total_size; i += flash->page_size)
157                 if (erase_sector_49lfxxxc(bios, i) != 0)
158                         return (-1);
159
160         *bios = RESET;
161
162         return 0;
163 }
164
165 int write_49lfxxxc(struct flashchip *flash, uint8_t *buf)
166 {
167         int i;
168         int total_size = flash->total_size * 1024;
169         int page_size = flash->page_size;
170         volatile uint8_t *bios = flash->virtual_memory;
171
172         write_lockbits_49lfxxxc(flash->virtual_registers, total_size, 0);
173         printf("Programming page: ");
174         for (i = 0; i < total_size / page_size; i++) {
175                 /* erase the page before programming */
176                 erase_sector_49lfxxxc(bios, i * page_size);
177
178                 /* write to the sector */
179                 printf("%04d at address: 0x%08x", i, i * page_size);
180                 write_sector_49lfxxxc(bios, buf + i * page_size,
181                                       bios + i * page_size, page_size);
182                 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");
183         }
184         printf("\n");
185
186         *bios = RESET;
187
188         return 0;
189 }