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