Drop remainders of the removed Totalimpact board. Fix typos.
[coreboot.git] / src / mainboard / motorola / sandpoint / flash / amd800.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2000 AG Electronics Ltd.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20 #include <console/console.h>
21 #include <stdlib.h>
22 #include "../flash.h"
23
24 struct data_amd800
25 {
26     unsigned base;
27     unsigned spacing;
28     unsigned cs;
29     const char *tag;
30 };
31
32 static const char *identify_amd (struct flash_device *flash_device);
33 static int erase_flash_amd800 (void *data, unsigned offset, unsigned length);
34 static int program_flash_amd800 (void *data, unsigned offset, const void *source,
35                                  unsigned length);
36 static uint8_t read_byte_amd800(void *data, unsigned offset);
37
38 static flash_fn fn_amd800 = {
39     identify_amd,
40     0,
41     0,
42     erase_flash_amd800,
43     program_flash_amd800,
44     read_byte_amd800
45 };
46
47 const char *identify_amd (struct flash_device *flash_device)
48 {
49     struct data_amd800 *d800 = flash_device->data;
50
51     if (!d800->tag)
52     {
53         volatile unsigned char *flash =
54
55             (volatile unsigned char *) d800->base;
56         unsigned char type,
57          id;
58
59         *(flash + 0xaaa * d800->spacing) = 0xaa;
60         *(flash + 0x555 * d800->spacing) = 0x55;
61         *(flash + 0xaaa * d800->spacing) = 0x90;
62         type = *(flash + 2 * d800->spacing);
63         id = *flash;
64         *flash = 0xf0;
65         if ((id == 1 || id == 0x20) && type == 0x5b)
66         {
67             d800->cs = 45;
68             d800->tag = "Am29LV800BB";
69             flash_device->base = d800->base;
70             flash_device->size = 1024*1024;
71             flash_device->erase_size = 64*1024;
72             flash_device->store_size = 1;
73         }
74         else
75         {
76             printk_info("Unknown flash ID: 0x%02x 0x%02x\n", id, type);
77         }
78     }
79     return d800->tag;
80 }
81
82 int erase_flash_amd800 (void *data, unsigned offset, unsigned length)
83 {
84     struct data_amd800 *d800 = data;
85     volatile unsigned char *flash = (volatile unsigned char *) d800->base;
86     volatile unsigned char *flash_aaa = flash + 0xaaa * d800->spacing;
87     volatile unsigned char *flash_555 = flash + 0x555 * d800->spacing;
88     int id;
89     int cs = 9999;
90
91     printk_info("Erase from 0x%08x to 0x%08x\n", offset, offset + length);
92     *flash_aaa = 0xAA;          // Chip Erase
93     *flash_555 = 0x55;
94     *flash_aaa = 0x80;
95     *flash_aaa = 0xAA;
96     *flash_555 = 0x55;
97     *flash_aaa = 0x10;
98
99     for (; cs > 0; cs--)
100     {
101         id = *(flash + 16);
102         if (id & 0xA0)          // DQ7 or DQ5 set: done or error
103             break;
104         printk_info("%4d\b\b\b\b", cs);
105     }
106
107     *flash_aaa = 0xF0;          // In case of error
108
109     printk_info("\b\b\b\b    \b\b\b\b");
110     if (cs == 0)
111     {
112         printk_info("Could not erase flash, timeout.\n");
113         return -1;
114     }
115     else if ((id & 0x80) == 0)
116     {
117         printk_info("Could not erase flash, status=%02x.\n", id);
118         return -1;
119     }
120     printk_info("Flash erased\n");
121     return 0;
122 }
123
124 int init_flash_amd800 (char *tag, unsigned base, unsigned spacing)
125 {
126     struct data_amd800 *data = malloc (sizeof (struct data_amd800));
127
128     if (data)
129     {
130         data->base = base;
131         data->spacing = spacing;
132         data->tag = 0;
133         if (register_flash_device (&fn_amd800, tag, data) < 0)
134         {
135             free (data);
136             return -1;
137         }
138     }
139     else
140         return -1;
141     return 0;
142 }
143
144 int program_flash_amd800 (void *data, unsigned offset, const void *source,
145                           unsigned length)
146 {
147     struct data_amd800 *d800 = data;
148     volatile unsigned char *flash = (volatile unsigned char *) d800->base;
149     volatile unsigned char *flash_aaa = flash + 0xaaa * d800->spacing;
150     volatile unsigned char *flash_555 = flash + 0x555 * d800->spacing;
151     int id = 0;
152     int cs;
153     int errs = 0;
154     volatile char *s;
155     volatile char *d;
156
157     printk_info("Program from 0x%08x to 0x%08x\n", offset, offset + length);
158     printk_info("Data at %p\n", source);
159
160     *flash_aaa = 0xAA;          // Unlock Bypass
161     *flash_555 = 0x55;
162     *flash_aaa = 0x20;
163
164     s = (unsigned char *) source;
165     d = flash + offset * d800->spacing;
166     cs = length;
167
168     while (cs > 0 && !errs)
169     {
170         *flash = 0xA0;  // Unlock Bypass Program
171         *d = *s;                // Program data
172
173         while (1)
174         {
175             id = *d;
176             if ((id & 0x80) == (*s & 0x80))     // DQ7 right? => program done
177                 break;
178             else if (id & 0x20)
179             {                   // DQ5 set? => maybe errors
180                 id = *d;
181                 if ((id & 0x80) != (*s & 0x80))
182                 {
183                     errs++;
184                     break;
185                 }
186             }
187         }
188
189         // PRINT("Set %08lx = %02x\n", d, *d);
190
191         s += 1;
192         d += d800->spacing;
193         cs--;
194     }
195
196     *flash = 0x90;              // Unlock Bypass Program Reset
197     *flash = 0x00;
198     *flash = 0xF0;
199
200     if (errs != 0)
201     {
202         printk_info("FAIL: Status=%02x Address=%p.\n", id, d - d800->spacing);
203         return -1;
204     }
205     printk_info("OK.\n");
206
207
208     // Step 4: Verify the flash.
209
210     printk_info("  Verifying flash : ...");
211     errs = 0;
212     s = (unsigned char *) source;
213     d = flash + offset * d800->spacing;
214     for (cs = 0; cs < length; cs++)
215     {
216         if (*s != *d)
217         {
218             if (errs == 0)
219                 printk_info("ERROR: Addr: %08p, PCI: %02x Lcl: %02x.\n",
220                        s, *s, *d);
221             errs++;
222         }
223         s += 1;
224         d += d800->spacing;
225     }
226
227     if (errs == 0)
228         printk_info("OK.\n");
229     else
230     {
231         printk_info("  FAIL: %d errors.\n", errs);
232         return -1;
233     }
234
235     return 0;
236 }
237
238 uint8_t read_byte_amd800 (void *data, unsigned offset)
239 {
240     struct data_amd800 *d800 = data;
241     volatile unsigned char *flash = (volatile unsigned char *) d800->base;
242     return *(flash + offset * d800->spacing);
243 }
244