32 |
#define NVRAM_PRINTF(fmt, args...) do { } while (0) |
#define NVRAM_PRINTF(fmt, args...) do { } while (0) |
33 |
#endif |
#endif |
34 |
|
|
35 |
#define NVRAM_MAX_MEM 0xfff0 |
#define NVRAM_MAX_MEM 0x1ff0 |
36 |
|
#define NVRAM_MAXADDR 0x1fff |
37 |
|
|
38 |
struct m48t08_t { |
struct m48t08_t { |
|
/* Hardware parameters */ |
|
|
int mem_index; |
|
|
uint32_t mem_base; |
|
|
uint16_t size; |
|
39 |
/* RTC management */ |
/* RTC management */ |
40 |
time_t time_offset; |
time_t time_offset; |
41 |
time_t stop_time; |
time_t stop_time; |
42 |
/* NVRAM storage */ |
/* NVRAM storage */ |
|
uint8_t lock; |
|
|
uint16_t addr; |
|
43 |
uint8_t *buffer; |
uint8_t *buffer; |
44 |
}; |
}; |
45 |
|
|
78 |
} |
} |
79 |
|
|
80 |
/* Direct access to NVRAM */ |
/* Direct access to NVRAM */ |
81 |
void m48t08_write (m48t08_t *NVRAM, uint32_t val) |
void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val) |
82 |
{ |
{ |
83 |
struct tm tm; |
struct tm tm; |
84 |
int tmp; |
int tmp; |
85 |
|
|
86 |
if (NVRAM->addr > NVRAM_MAX_MEM && NVRAM->addr < 0x2000) |
addr &= NVRAM_MAXADDR; |
87 |
NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val); |
switch (addr) { |
|
switch (NVRAM->addr) { |
|
88 |
case 0x1FF8: |
case 0x1FF8: |
89 |
/* control */ |
/* control */ |
90 |
NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90; |
NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90; |
161 |
} |
} |
162 |
break; |
break; |
163 |
default: |
default: |
164 |
/* Check lock registers state */ |
NVRAM->buffer[addr] = val & 0xFF; |
|
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) |
|
|
break; |
|
|
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) |
|
|
break; |
|
|
if (NVRAM->addr < NVRAM_MAX_MEM || |
|
|
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { |
|
|
NVRAM->buffer[NVRAM->addr] = val & 0xFF; |
|
|
} |
|
165 |
break; |
break; |
166 |
} |
} |
167 |
} |
} |
168 |
|
|
169 |
uint32_t m48t08_read (m48t08_t *NVRAM) |
uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr) |
170 |
{ |
{ |
171 |
struct tm tm; |
struct tm tm; |
172 |
uint32_t retval = 0xFF; |
uint8_t retval = 0xFF; |
173 |
|
|
174 |
switch (NVRAM->addr) { |
addr &= NVRAM_MAXADDR; |
175 |
|
switch (addr) { |
176 |
case 0x1FF8: |
case 0x1FF8: |
177 |
/* control */ |
/* control */ |
178 |
goto do_read; |
goto do_read; |
212 |
retval = toBCD(tm.tm_year); |
retval = toBCD(tm.tm_year); |
213 |
break; |
break; |
214 |
default: |
default: |
215 |
/* Check lock registers state */ |
do_read: |
216 |
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) |
retval = NVRAM->buffer[addr]; |
|
break; |
|
|
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) |
|
|
break; |
|
|
if (NVRAM->addr < NVRAM_MAX_MEM || |
|
|
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { |
|
|
do_read: |
|
|
retval = NVRAM->buffer[NVRAM->addr]; |
|
|
} |
|
217 |
break; |
break; |
218 |
} |
} |
|
if (NVRAM->addr > NVRAM_MAX_MEM + 1 && NVRAM->addr < 0x2000) |
|
|
NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval); |
|
|
|
|
219 |
return retval; |
return retval; |
220 |
} |
} |
221 |
|
|
|
void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr) |
|
|
{ |
|
|
NVRAM->addr = addr; |
|
|
} |
|
|
|
|
|
void m48t08_toggle_lock (m48t08_t *NVRAM, int lock) |
|
|
{ |
|
|
NVRAM->lock ^= 1 << lock; |
|
|
} |
|
|
|
|
222 |
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) |
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) |
223 |
{ |
{ |
224 |
m48t08_t *NVRAM = opaque; |
m48t08_t *NVRAM = opaque; |
225 |
|
|
226 |
addr -= NVRAM->mem_base; |
m48t08_write(NVRAM, addr, value); |
|
if (addr < NVRAM_MAX_MEM) |
|
|
NVRAM->buffer[addr] = value; |
|
227 |
} |
} |
228 |
|
|
229 |
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) |
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) |
230 |
{ |
{ |
231 |
m48t08_t *NVRAM = opaque; |
m48t08_t *NVRAM = opaque; |
232 |
|
|
233 |
addr -= NVRAM->mem_base; |
m48t08_write(NVRAM, addr, value); |
234 |
if (addr < NVRAM_MAX_MEM) { |
m48t08_write(NVRAM, addr + 1, value >> 8); |
|
NVRAM->buffer[addr] = value >> 8; |
|
|
NVRAM->buffer[addr + 1] = value; |
|
|
} |
|
235 |
} |
} |
236 |
|
|
237 |
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) |
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) |
238 |
{ |
{ |
239 |
m48t08_t *NVRAM = opaque; |
m48t08_t *NVRAM = opaque; |
240 |
|
|
241 |
addr -= NVRAM->mem_base; |
m48t08_write(NVRAM, addr, value); |
242 |
if (addr < NVRAM_MAX_MEM) { |
m48t08_write(NVRAM, addr + 1, value >> 8); |
243 |
NVRAM->buffer[addr] = value >> 24; |
m48t08_write(NVRAM, addr + 2, value >> 16); |
244 |
NVRAM->buffer[addr + 1] = value >> 16; |
m48t08_write(NVRAM, addr + 3, value >> 24); |
|
NVRAM->buffer[addr + 2] = value >> 8; |
|
|
NVRAM->buffer[addr + 3] = value; |
|
|
} |
|
245 |
} |
} |
246 |
|
|
247 |
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) |
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) |
249 |
m48t08_t *NVRAM = opaque; |
m48t08_t *NVRAM = opaque; |
250 |
uint32_t retval = 0; |
uint32_t retval = 0; |
251 |
|
|
252 |
addr -= NVRAM->mem_base; |
retval = m48t08_read(NVRAM, addr); |
|
if (addr < NVRAM_MAX_MEM) |
|
|
retval = NVRAM->buffer[addr]; |
|
|
|
|
253 |
return retval; |
return retval; |
254 |
} |
} |
255 |
|
|
258 |
m48t08_t *NVRAM = opaque; |
m48t08_t *NVRAM = opaque; |
259 |
uint32_t retval = 0; |
uint32_t retval = 0; |
260 |
|
|
261 |
addr -= NVRAM->mem_base; |
retval = m48t08_read(NVRAM, addr) << 8; |
262 |
if (addr < NVRAM_MAX_MEM) { |
retval |= m48t08_read(NVRAM, addr + 1); |
|
retval = NVRAM->buffer[addr] << 8; |
|
|
retval |= NVRAM->buffer[addr + 1]; |
|
|
} |
|
|
|
|
263 |
return retval; |
return retval; |
264 |
} |
} |
265 |
|
|
268 |
m48t08_t *NVRAM = opaque; |
m48t08_t *NVRAM = opaque; |
269 |
uint32_t retval = 0; |
uint32_t retval = 0; |
270 |
|
|
271 |
addr -= NVRAM->mem_base; |
retval = m48t08_read(NVRAM, addr) << 24; |
272 |
if (addr < NVRAM_MAX_MEM) { |
retval |= m48t08_read(NVRAM, addr + 1) << 16; |
273 |
retval = NVRAM->buffer[addr] << 24; |
retval |= m48t08_read(NVRAM, addr + 2) << 8; |
274 |
retval |= NVRAM->buffer[addr + 1] << 16; |
retval |= m48t08_read(NVRAM, addr + 3); |
|
retval |= NVRAM->buffer[addr + 2] << 8; |
|
|
retval |= NVRAM->buffer[addr + 3]; |
|
|
} |
|
|
|
|
275 |
return retval; |
return retval; |
276 |
} |
} |
277 |
|
|
287 |
&nvram_readl, |
&nvram_readl, |
288 |
}; |
}; |
289 |
|
|
290 |
|
static void nvram_save(QEMUFile *f, void *opaque) |
291 |
|
{ |
292 |
|
m48t08_t *s = opaque; |
293 |
|
|
294 |
|
qemu_put_be32s(f, (uint32_t *)&s->time_offset); |
295 |
|
qemu_put_be32s(f, (uint32_t *)&s->stop_time); |
296 |
|
qemu_put_buffer(f, s->buffer, 0x2000); |
297 |
|
} |
298 |
|
|
299 |
|
static int nvram_load(QEMUFile *f, void *opaque, int version_id) |
300 |
|
{ |
301 |
|
m48t08_t *s = opaque; |
302 |
|
|
303 |
|
if (version_id != 1) |
304 |
|
return -EINVAL; |
305 |
|
|
306 |
|
qemu_get_be32s(f, (uint32_t *)&s->time_offset); |
307 |
|
qemu_get_be32s(f, (uint32_t *)&s->stop_time); |
308 |
|
qemu_get_buffer(f, s->buffer, 0x2000); |
309 |
|
return 0; |
310 |
|
} |
311 |
|
|
312 |
|
static void m48t08_reset(void *opaque) |
313 |
|
{ |
314 |
|
m48t08_t *s = opaque; |
315 |
|
|
316 |
|
s->time_offset = 0; |
317 |
|
s->stop_time = 0; |
318 |
|
} |
319 |
|
|
320 |
|
|
321 |
/* Initialisation routine */ |
/* Initialisation routine */ |
322 |
m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr) |
m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size) |
323 |
{ |
{ |
324 |
m48t08_t *s; |
m48t08_t *s; |
325 |
int i; |
int mem_index; |
|
unsigned char tmp = 0; |
|
326 |
|
|
327 |
s = qemu_mallocz(sizeof(m48t08_t)); |
s = qemu_mallocz(sizeof(m48t08_t)); |
328 |
if (!s) |
if (!s) |
332 |
qemu_free(s); |
qemu_free(s); |
333 |
return NULL; |
return NULL; |
334 |
} |
} |
|
s->size = size; |
|
|
s->mem_base = mem_base; |
|
|
s->addr = 0; |
|
335 |
if (mem_base != 0) { |
if (mem_base != 0) { |
336 |
s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); |
mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); |
337 |
cpu_register_physical_memory(mem_base, 0x4000, s->mem_index); |
cpu_register_physical_memory(mem_base, 0x2000, mem_index); |
338 |
} |
} |
|
s->lock = 0; |
|
339 |
|
|
340 |
i = 0x1fd8; |
register_savevm("nvram", mem_base, 1, nvram_save, nvram_load, s); |
341 |
s->buffer[i++] = 0x01; |
qemu_register_reset(m48t08_reset, s); |
|
s->buffer[i++] = 0x80; /* Sun4m OBP */ |
|
|
memcpy(&s->buffer[i], macaddr, 6); |
|
|
|
|
|
/* Calculate checksum */ |
|
|
for (i = 0x1fd8; i < 0x1fe7; i++) { |
|
|
tmp ^= s->buffer[i]; |
|
|
} |
|
|
s->buffer[0x1fe7] = tmp; |
|
342 |
return s; |
return s; |
343 |
} |
} |
344 |
|
|