Commit a6569fc532698a7df1cc9c04f26503727a5a5bfd
1 parent
c9fb531a
tc6393xb: initial support for nand control (Dmitry Baryshkov).
Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com> Signed-off-by: Andrzej Zaborowski <andrew.zaborowski@intel.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5611 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
221 additions
and
23 deletions
hw/tc6393xb.c
... | ... | @@ -10,6 +10,15 @@ |
10 | 10 | #include "hw.h" |
11 | 11 | #include "pxa.h" |
12 | 12 | #include "devices.h" |
13 | +#include "flash.h" | |
14 | + | |
15 | +#define IRQ_TC6393_NAND 0 | |
16 | +#define IRQ_TC6393_MMC 1 | |
17 | +#define IRQ_TC6393_OHCI 2 | |
18 | +#define IRQ_TC6393_SERIAL 3 | |
19 | +#define IRQ_TC6393_FB 4 | |
20 | + | |
21 | +#define TC6393XB_NR_IRQS 8 | |
13 | 22 | |
14 | 23 | #define TC6393XB_GPIOS 16 |
15 | 24 | |
... | ... | @@ -40,8 +49,37 @@ |
40 | 49 | #define SCR_CONFIG 0xfc /* b Configuration Control */ |
41 | 50 | #define SCR_DEBUG 0xff /* b Debug */ |
42 | 51 | |
52 | +#define NAND_CFG_COMMAND 0x04 /* w Command */ | |
53 | +#define NAND_CFG_BASE 0x10 /* l Control Base Address */ | |
54 | +#define NAND_CFG_INTP 0x3d /* b Interrupt Pin */ | |
55 | +#define NAND_CFG_INTE 0x48 /* b Int Enable */ | |
56 | +#define NAND_CFG_EC 0x4a /* b Event Control */ | |
57 | +#define NAND_CFG_ICC 0x4c /* b Internal Clock Control */ | |
58 | +#define NAND_CFG_ECCC 0x5b /* b ECC Control */ | |
59 | +#define NAND_CFG_NFTC 0x60 /* b NAND Flash Transaction Control */ | |
60 | +#define NAND_CFG_NFM 0x61 /* b NAND Flash Monitor */ | |
61 | +#define NAND_CFG_NFPSC 0x62 /* b NAND Flash Power Supply Control */ | |
62 | +#define NAND_CFG_NFDC 0x63 /* b NAND Flash Detect Control */ | |
63 | + | |
64 | +#define NAND_DATA 0x00 /* l Data */ | |
65 | +#define NAND_MODE 0x04 /* b Mode */ | |
66 | +#define NAND_STATUS 0x05 /* b Status */ | |
67 | +#define NAND_ISR 0x06 /* b Interrupt Status */ | |
68 | +#define NAND_IMR 0x07 /* b Interrupt Mask */ | |
69 | + | |
70 | +#define NAND_MODE_WP 0x80 | |
71 | +#define NAND_MODE_CE 0x10 | |
72 | +#define NAND_MODE_ALE 0x02 | |
73 | +#define NAND_MODE_CLE 0x01 | |
74 | +#define NAND_MODE_ECC_MASK 0x60 | |
75 | +#define NAND_MODE_ECC_EN 0x20 | |
76 | +#define NAND_MODE_ECC_READ 0x40 | |
77 | +#define NAND_MODE_ECC_RST 0x60 | |
78 | + | |
43 | 79 | struct tc6393xb_s { |
44 | 80 | target_phys_addr_t target_base; |
81 | + qemu_irq irq; | |
82 | + qemu_irq *sub_irqs; | |
45 | 83 | struct { |
46 | 84 | uint8_t ISR; |
47 | 85 | uint8_t IMR; |
... | ... | @@ -71,6 +109,16 @@ struct tc6393xb_s { |
71 | 109 | uint32_t prev_level; |
72 | 110 | qemu_irq handler[TC6393XB_GPIOS]; |
73 | 111 | qemu_irq *gpio_in; |
112 | + | |
113 | + struct { | |
114 | + uint8_t mode; | |
115 | + uint8_t isr; | |
116 | + uint8_t imr; | |
117 | + } nand; | |
118 | + int nand_enable; | |
119 | + uint32_t nand_phys; | |
120 | + struct nand_flash_s *flash; | |
121 | + struct ecc_state_s ecc; | |
74 | 122 | }; |
75 | 123 | |
76 | 124 | qemu_irq *tc6393xb_gpio_in_get(struct tc6393xb_s *s) |
... | ... | @@ -116,6 +164,17 @@ static void tc6393xb_gpio_handler_update(struct tc6393xb_s *s) |
116 | 164 | s->prev_level = level; |
117 | 165 | } |
118 | 166 | |
167 | +static void tc6393xb_sub_irq(void *opaque, int line, int level) { | |
168 | + struct tc6393xb_s *s = opaque; | |
169 | + uint8_t isr = s->scr.ISR; | |
170 | + if (level) | |
171 | + isr |= 1 << line; | |
172 | + else | |
173 | + isr &= ~(1 << line); | |
174 | + s->scr.ISR = isr; | |
175 | + qemu_set_irq(s->irq, isr & s->scr.IMR); | |
176 | +} | |
177 | + | |
119 | 178 | #define SCR_REG_B(N) \ |
120 | 179 | case SCR_ ##N: return s->scr.N |
121 | 180 | #define SCR_REG_W(N) \ |
... | ... | @@ -131,10 +190,8 @@ static void tc6393xb_gpio_handler_update(struct tc6393xb_s *s) |
131 | 190 | case SCR_ ##N(1): return s->scr.N[1]; \ |
132 | 191 | case SCR_ ##N(2): return s->scr.N[2] |
133 | 192 | |
134 | -static uint32_t tc6393xb_readb(void *opaque, target_phys_addr_t addr) | |
193 | +static uint32_t tc6393xb_scr_readb(struct tc6393xb_s *s, target_phys_addr_t addr) | |
135 | 194 | { |
136 | - struct tc6393xb_s *s = opaque; | |
137 | - addr -= s->target_base; | |
138 | 195 | switch (addr) { |
139 | 196 | case SCR_REVID: |
140 | 197 | return 3; |
... | ... | @@ -171,7 +228,7 @@ static uint32_t tc6393xb_readb(void *opaque, target_phys_addr_t addr) |
171 | 228 | SCR_REG_B(CONFIG); |
172 | 229 | SCR_REG_B(DEBUG); |
173 | 230 | } |
174 | - fprintf(stderr, "tc6393xb: unhandled read at %08x\n", (uint32_t) addr); | |
231 | + fprintf(stderr, "tc6393xb_scr: unhandled read at %08x\n", (uint32_t) addr); | |
175 | 232 | return 0; |
176 | 233 | } |
177 | 234 | #undef SCR_REG_B |
... | ... | @@ -180,24 +237,22 @@ static uint32_t tc6393xb_readb(void *opaque, target_phys_addr_t addr) |
180 | 237 | #undef SCR_REG_A |
181 | 238 | |
182 | 239 | #define SCR_REG_B(N) \ |
183 | - case SCR_ ##N: s->scr.N = value; break; | |
240 | + case SCR_ ##N: s->scr.N = value; return; | |
184 | 241 | #define SCR_REG_W(N) \ |
185 | - case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); break; \ | |
186 | - case SCR_ ##N + 1: s->scr.N = (s->scr.N & 0xff) | (value << 8); break | |
242 | + case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \ | |
243 | + case SCR_ ##N + 1: s->scr.N = (s->scr.N & 0xff) | (value << 8); return | |
187 | 244 | #define SCR_REG_L(N) \ |
188 | - case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); break; \ | |
189 | - case SCR_ ##N + 1: s->scr.N = (s->scr.N & ~(0xff << 8)) | (value & (0xff << 8)); break; \ | |
190 | - case SCR_ ##N + 2: s->scr.N = (s->scr.N & ~(0xff << 16)) | (value & (0xff << 16)); break; \ | |
191 | - case SCR_ ##N + 3: s->scr.N = (s->scr.N & ~(0xff << 24)) | (value & (0xff << 24)); break; | |
245 | + case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \ | |
246 | + case SCR_ ##N + 1: s->scr.N = (s->scr.N & ~(0xff << 8)) | (value & (0xff << 8)); return; \ | |
247 | + case SCR_ ##N + 2: s->scr.N = (s->scr.N & ~(0xff << 16)) | (value & (0xff << 16)); return; \ | |
248 | + case SCR_ ##N + 3: s->scr.N = (s->scr.N & ~(0xff << 24)) | (value & (0xff << 24)); return; | |
192 | 249 | #define SCR_REG_A(N) \ |
193 | - case SCR_ ##N(0): s->scr.N[0] = value; break; \ | |
194 | - case SCR_ ##N(1): s->scr.N[1] = value; break; \ | |
195 | - case SCR_ ##N(2): s->scr.N[2] = value; break | |
250 | + case SCR_ ##N(0): s->scr.N[0] = value; return; \ | |
251 | + case SCR_ ##N(1): s->scr.N[1] = value; return; \ | |
252 | + case SCR_ ##N(2): s->scr.N[2] = value; return | |
196 | 253 | |
197 | -static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) | |
254 | +static void tc6393xb_scr_writeb(struct tc6393xb_s *s, target_phys_addr_t addr, uint32_t value) | |
198 | 255 | { |
199 | - struct tc6393xb_s *s = opaque; | |
200 | - addr -= s->target_base; | |
201 | 256 | switch (addr) { |
202 | 257 | SCR_REG_B(ISR); |
203 | 258 | SCR_REG_B(IMR); |
... | ... | @@ -212,13 +267,13 @@ static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, uint32_t valu |
212 | 267 | case SCR_GPO_DSR(2): |
213 | 268 | s->gpio_level = (s->gpio_level & ~(0xff << ((addr - SCR_GPO_DSR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DSR(0))*8)); |
214 | 269 | tc6393xb_gpio_handler_update(s); |
215 | - break; | |
270 | + return; | |
216 | 271 | case SCR_GPO_DOECR(0): |
217 | 272 | case SCR_GPO_DOECR(1): |
218 | 273 | case SCR_GPO_DOECR(2): |
219 | 274 | s->gpio_dir = (s->gpio_dir & ~(0xff << ((addr - SCR_GPO_DOECR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DOECR(0))*8)); |
220 | 275 | tc6393xb_gpio_handler_update(s); |
221 | - break; | |
276 | + return; | |
222 | 277 | SCR_REG_A(GP_IARCR); |
223 | 278 | SCR_REG_A(GP_IARLCR); |
224 | 279 | SCR_REG_A(GPI_BCR); |
... | ... | @@ -233,17 +288,155 @@ static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, uint32_t valu |
233 | 288 | SCR_REG_W(MCR); |
234 | 289 | SCR_REG_B(CONFIG); |
235 | 290 | SCR_REG_B(DEBUG); |
236 | - default: | |
237 | - fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n", | |
238 | - (uint32_t) addr, value & 0xff); | |
239 | - break; | |
240 | 291 | } |
292 | + fprintf(stderr, "tc6393xb_scr: unhandled write at %08x: %02x\n", | |
293 | + (uint32_t) addr, value & 0xff); | |
241 | 294 | } |
242 | 295 | #undef SCR_REG_B |
243 | 296 | #undef SCR_REG_W |
244 | 297 | #undef SCR_REG_L |
245 | 298 | #undef SCR_REG_A |
246 | 299 | |
300 | +static void tc6393xb_nand_irq(struct tc6393xb_s *s) { | |
301 | + qemu_set_irq(s->sub_irqs[IRQ_TC6393_NAND], | |
302 | + (s->nand.imr & 0x80) && (s->nand.imr & s->nand.isr)); | |
303 | +} | |
304 | + | |
305 | +static uint32_t tc6393xb_nand_cfg_readb(struct tc6393xb_s *s, target_phys_addr_t addr) { | |
306 | + switch (addr) { | |
307 | + case NAND_CFG_COMMAND: | |
308 | + return s->nand_enable ? 2 : 0; | |
309 | + case NAND_CFG_BASE: | |
310 | + case NAND_CFG_BASE + 1: | |
311 | + case NAND_CFG_BASE + 2: | |
312 | + case NAND_CFG_BASE + 3: | |
313 | + return s->nand_phys >> (addr - NAND_CFG_BASE); | |
314 | + } | |
315 | + fprintf(stderr, "tc6393xb_nand_cfg: unhandled read at %08x\n", (uint32_t) addr); | |
316 | + return 0; | |
317 | +} | |
318 | +static void tc6393xb_nand_cfg_writeb(struct tc6393xb_s *s, target_phys_addr_t addr, uint32_t value) { | |
319 | + switch (addr) { | |
320 | + case NAND_CFG_COMMAND: | |
321 | + s->nand_enable = (value & 0x2); | |
322 | + return; | |
323 | + case NAND_CFG_BASE: | |
324 | + case NAND_CFG_BASE + 1: | |
325 | + case NAND_CFG_BASE + 2: | |
326 | + case NAND_CFG_BASE + 3: | |
327 | + s->nand_phys &= ~(0xff << ((addr - NAND_CFG_BASE) * 8)); | |
328 | + s->nand_phys |= (value & 0xff) << ((addr - NAND_CFG_BASE) * 8); | |
329 | + return; | |
330 | + } | |
331 | + fprintf(stderr, "tc6393xb_nand_cfg: unhandled write at %08x: %02x\n", | |
332 | + (uint32_t) addr, value & 0xff); | |
333 | +} | |
334 | + | |
335 | +static uint32_t tc6393xb_nand_readb(struct tc6393xb_s *s, target_phys_addr_t addr) { | |
336 | + switch (addr) { | |
337 | + case NAND_DATA + 0: | |
338 | + case NAND_DATA + 1: | |
339 | + case NAND_DATA + 2: | |
340 | + case NAND_DATA + 3: | |
341 | + return nand_getio(s->flash); | |
342 | + case NAND_MODE: | |
343 | + return s->nand.mode; | |
344 | + case NAND_STATUS: | |
345 | + return 0x14; | |
346 | + case NAND_ISR: | |
347 | + return s->nand.isr; | |
348 | + case NAND_IMR: | |
349 | + return s->nand.imr; | |
350 | + } | |
351 | + fprintf(stderr, "tc6393xb_nand: unhandled read at %08x\n", (uint32_t) addr); | |
352 | + return 0; | |
353 | +} | |
354 | +static void tc6393xb_nand_writeb(struct tc6393xb_s *s, target_phys_addr_t addr, uint32_t value) { | |
355 | +// fprintf(stderr, "tc6393xb_nand: write at %08x: %02x\n", | |
356 | +// (uint32_t) addr, value & 0xff); | |
357 | + switch (addr) { | |
358 | + case NAND_DATA + 0: | |
359 | + case NAND_DATA + 1: | |
360 | + case NAND_DATA + 2: | |
361 | + case NAND_DATA + 3: | |
362 | + nand_setio(s->flash, value); | |
363 | + s->nand.isr &= 1; | |
364 | + tc6393xb_nand_irq(s); | |
365 | + return; | |
366 | + case NAND_MODE: | |
367 | + s->nand.mode = value; | |
368 | + nand_setpins(s->flash, | |
369 | + value & NAND_MODE_CLE, | |
370 | + value & NAND_MODE_ALE, | |
371 | + !(value & NAND_MODE_CE), | |
372 | + value & NAND_MODE_WP, | |
373 | + 0); // FIXME: gnd | |
374 | + switch (value & NAND_MODE_ECC_MASK) { | |
375 | + case NAND_MODE_ECC_RST: | |
376 | + ecc_reset(&s->ecc); | |
377 | + break; | |
378 | + case NAND_MODE_ECC_READ: | |
379 | + // FIXME | |
380 | + break; | |
381 | + case NAND_MODE_ECC_EN: | |
382 | + ecc_reset(&s->ecc); | |
383 | + } | |
384 | + return; | |
385 | + case NAND_ISR: | |
386 | + s->nand.isr = value; | |
387 | + tc6393xb_nand_irq(s); | |
388 | + return; | |
389 | + case NAND_IMR: | |
390 | + s->nand.imr = value; | |
391 | + tc6393xb_nand_irq(s); | |
392 | + return; | |
393 | + } | |
394 | + fprintf(stderr, "tc6393xb_nand: unhandled write at %08x: %02x\n", | |
395 | + (uint32_t) addr, value & 0xff); | |
396 | +} | |
397 | + | |
398 | +static uint32_t tc6393xb_readb(void *opaque, target_phys_addr_t addr) { | |
399 | + struct tc6393xb_s *s = opaque; | |
400 | + addr -= s->target_base; | |
401 | + | |
402 | + switch (addr >> 8) { | |
403 | + case 0: | |
404 | + return tc6393xb_scr_readb(s, addr & 0xff); | |
405 | + case 1: | |
406 | + return tc6393xb_nand_cfg_readb(s, addr & 0xff); | |
407 | + }; | |
408 | + | |
409 | + if ((addr &~0xff) == s->nand_phys && s->nand_enable) { | |
410 | +// return tc6393xb_nand_readb(s, addr & 0xff); | |
411 | + uint8_t d = tc6393xb_nand_readb(s, addr & 0xff); | |
412 | +// fprintf(stderr, "tc6393xb_nand: read at %08x: %02hhx\n", (uint32_t) addr, d); | |
413 | + return d; | |
414 | + } | |
415 | + | |
416 | +// fprintf(stderr, "tc6393xb: unhandled read at %08x\n", (uint32_t) addr); | |
417 | + return 0; | |
418 | +} | |
419 | + | |
420 | +static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) { | |
421 | + struct tc6393xb_s *s = opaque; | |
422 | + addr -= s->target_base; | |
423 | + | |
424 | + switch (addr >> 8) { | |
425 | + case 0: | |
426 | + tc6393xb_scr_writeb(s, addr & 0xff, value); | |
427 | + return; | |
428 | + case 1: | |
429 | + tc6393xb_nand_cfg_writeb(s, addr & 0xff, value); | |
430 | + return; | |
431 | + }; | |
432 | + | |
433 | + if ((addr &~0xff) == s->nand_phys && s->nand_enable) | |
434 | + tc6393xb_nand_writeb(s, addr & 0xff, value); | |
435 | + else | |
436 | + fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n", | |
437 | + (uint32_t) addr, value & 0xff); | |
438 | +} | |
439 | + | |
247 | 440 | static uint32_t tc6393xb_readw(void *opaque, target_phys_addr_t addr) |
248 | 441 | { |
249 | 442 | return (tc6393xb_readb(opaque, addr) & 0xff) | |
... | ... | @@ -289,8 +482,13 @@ struct tc6393xb_s *tc6393xb_init(uint32_t base, qemu_irq irq) |
289 | 482 | |
290 | 483 | s = (struct tc6393xb_s *) qemu_mallocz(sizeof(struct tc6393xb_s)); |
291 | 484 | s->target_base = base; |
485 | + s->irq = irq; | |
292 | 486 | s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS); |
293 | 487 | |
488 | + s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS); | |
489 | + | |
490 | + s->flash = nand_init(NAND_MFR_TOSHIBA, 0x76); | |
491 | + | |
294 | 492 | iomemtype = cpu_register_io_memory(0, tc6393xb_readfn, |
295 | 493 | tc6393xb_writefn, s); |
296 | 494 | cpu_register_physical_memory(s->target_base, 0x200000, iomemtype); | ... | ... |