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