1 // am29.cxx - Implementation of AMD's 29xxx flash memory. -*- C++ -*-
3 // Copyright (C) 1999, 2000 Red Hat.
4 // This file is part of SID and is licensed under the GPL.
5 // See the file COPYING.SID for conditions for redistribution.
8 #include <sidbusutil.h>
31 AUTOSELECT_CMD = 0x90,
33 ERASE_CHIP_CMD = 0x10,
34 ERASE_SECTOR_CMD = 0x30,
39 BYPASS_PROG_CMD = 0xA0,
40 BYPASS_RESET_CMD = 0x90
43 am29_flash_memory::am29_flash_memory (size_t ms, size_t ss, host_int_1 id)
45 manufacturerCode(0x01)
47 // set incoming parameters
50 if (!attempt_resize(ms))
58 add_bus("read-write-port", &this->my_bus);
59 add_attribute_ro("mode", &mode);
60 add_attribute("device-code", &deviceIdCode, "setting");
61 add_attribute_ro_value("manufacturer-code", manufacturerCode, "setting");
65 am29_flash_memory::stream_state (ostream& out) const
67 flash_uniform_sector_memory::stream_state(out);
71 out << ':' << "device-code " << deviceIdCode;
75 am29_flash_memory::destream_state (istream& in)
77 flash_uniform_sector_memory::destream_state(in);
87 in.setstate(ios::badbit);
91 if (key != "device-code")
93 in.setstate(ios::badbit);
100 // Erase the entire chip.
102 am29_flash_memory::erase()
104 for (unsigned i = 0; i < buffer_length; i++)
112 am29_flash_memory::erase(unsigned sector)
114 host_int_4 start_addr = sector_size * sector;
116 if (start_addr >= buffer_length)
119 host_int_4 end_addr = sector_size * (sector + 1);
121 if (end_addr > buffer_length)
122 end_addr = buffer_length;
124 assert(start_addr < end_addr);
125 assert(start_addr < buffer_length);
126 assert(end_addr < buffer_length);
128 for (unsigned i = start_addr; i < end_addr; i++)
136 am29_flash_memory::write_ok(host_int_4 address)
138 return (mode == STATE_PROGRAM);
143 am29_flash_memory::am29_bus::read(host_int_4 address,
144 little_int_1& data) throw ()
148 if (target->mode == STATE_AUTOSELECT)
150 if ((address & 0xF) == 0)
151 data = target->manufacturerCode;
152 else if ((address & 0xF) == 1)
153 data = target->deviceIdCode;
154 else if ((address & 0xF) == 2)
156 // FIXME: All sectors are unprotected.
162 // Bounds check the memory reference.
163 if (address > target->buffer_length)
165 return bus::unmapped;
167 data = target->buffer[address];
172 return sid::bus::delayed;
178 am29_flash_memory::am29_bus::read(host_int_4 address,
179 big_int_1& data) throw ()
183 little_int_1 littleData(data);
184 bus::status result = read(address, littleData);
190 return sid::bus::delayed;
196 am29_flash_memory::am29_bus::write(host_int_4 address,
197 little_int_1 le_data) throw()
201 host_int_1 data = le_data;
203 switch (target->mode)
206 if (address == UNLOCK && data == UNLOCK1_CMD)
208 target->mode = STATE_UNLOCK1;
211 return bus::unpermitted;
213 case STATE_AUTOSELECT:
214 // Don't care about the address bits for the reset command.
217 target->mode = STATE_READ;
223 // Don't care about address bits for the bypass program cmd.
224 if (data == BYPASS_PROG_CMD)
225 target->mode = STATE_PROGRAM;
226 else if (data == BYPASS_RESET_CMD)
227 target->mode = STATE_BYPASS_RESET;
229 target->mode = STATE_READ;
232 case STATE_BYPASS_RESET:
233 // Go back to read mode unconditionally -- this is the
234 // expected behaviour even if the magic codes are wrong.
235 target->mode = STATE_READ;
239 if (address == UNLOCK && data == UNLOCK1_CMD)
240 target->mode = STATE_ERASE1;
242 target->mode = STATE_READ;
246 if (address == UNLOCK2 && data == UNLOCK2_CMD)
247 target->mode = STATE_ERASE2;
249 target->mode = STATE_READ;
253 if (address == UNLOCK && data == ERASE_CHIP_CMD)
257 else if (UNLOCK && data == ERASE_SECTOR_CMD)
259 target->erase((address >> 16));
261 target->mode = STATE_READ;
265 if (address == UNLOCK2 && data == UNLOCK2_CMD)
266 target->mode = STATE_UNLOCK2;
268 target->mode = STATE_READ;
272 if (address == UNLOCK && data == AUTOSELECT_CMD)
273 target->mode = STATE_AUTOSELECT;
274 else if (address == UNLOCK && data == PROGRAM_CMD)
275 target->mode = STATE_PROGRAM;
276 else if (address == UNLOCK && data == ERASE_CMD)
277 target->mode = STATE_ERASE0;
278 else if (address == UNLOCK && data == BYPASS_CMD)
279 target->mode = STATE_BYPASS;
281 target->mode = STATE_READ;
285 if (address > target->buffer_length)
287 return bus::unmapped;
290 if (target->write_ok(address))
292 little_int_1 old_data = target->buffer[address];
293 for (int i = 0; i < 8; i++)
296 if (((old_data & mask) == 0) && ((data & mask) != 0))
298 // Cannot change a 0 back to a 1, so clear this bit.
303 target->buffer[address] = data;
304 target->mode = STATE_READ;
318 am29_flash_memory::am29_bus::write(host_int_4 address,
319 big_int_1 data) throw ()
321 return write(address, little_int_1(data));
324 // static const description table for flash family
325 // Details taken from AMD data sheet, publication no. 21354, 1999-05-18.
327 const am29_flash_memory_type am29_flash_memory::types[] =
329 { "f010a", 128*1024, 16*1024, 0x20 },
330 { "lv010b", 128*1024, 16*1024, 0x6E },
331 { "lv040b", 512*1024, 64*1024, 0x4F },
332 { "lv081b", 1024*1024, 64*1024, 0x38 },
333 { "lv017b", 2*1024*1024, 64*1024, 0xC8 },
334 { "lv033c", 4*1024*1024, 64*1024, 0xA3 },