Commit 29885477725df546145dd09678556e4551961cb3

Authored by balrog
1 parent 4d3b6f6e

Make omap I2C controller work (previously untested). Implement post-OMAP1 chang…

…es.  Introduce omap L4 abstraction.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3977 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 116 additions and 15 deletions
hw/omap.h
... ... @@ -60,6 +60,10 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
60 60 unsigned long size, unsigned char nbanks,
61 61 qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk);
62 62  
  63 +struct omap_target_agent_s;
  64 +static inline target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta,
  65 + int region, int iotype) { return 0; }
  66 +
63 67 /*
64 68 * Common IRQ numbers for level 1 interrupt handler
65 69 * See /usr/include/asm-arm/arch-omap/irqs.h in Linux.
... ... @@ -573,6 +577,8 @@ void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover);
573 577 struct omap_i2c_s;
574 578 struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
575 579 qemu_irq irq, qemu_irq *dma, omap_clk clk);
  580 +struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
  581 + qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk);
576 582 void omap_i2c_reset(struct omap_i2c_s *s);
577 583 i2c_bus *omap_i2c_bus(struct omap_i2c_s *s);
578 584  
... ...
hw/omap_i2c.c
... ... @@ -29,6 +29,7 @@ struct omap_i2c_s {
29 29 i2c_slave slave;
30 30 i2c_bus *bus;
31 31  
  32 + uint8_t revision;
32 33 uint8_t mask;
33 34 uint16_t stat;
34 35 uint16_t dma;
... ... @@ -44,6 +45,9 @@ struct omap_i2c_s {
44 45 uint16_t test;
45 46 };
46 47  
  48 +#define OMAP2_INTR_REV 0x34
  49 +#define OMAP2_GC_REV 0x34
  50 +
47 51 static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
48 52 {
49 53 qemu_set_irq(s->irq, s->stat & s->mask);
... ... @@ -124,6 +128,7 @@ static void omap_i2c_fifo_run(struct omap_i2c_s *s)
124 128 i2c_end_transfer(s->bus);
125 129 s->control &= ~(1 << 1); /* STP */
126 130 s->count_cur = s->count;
  131 + s->txlen = 0;
127 132 } else if ((s->control >> 9) & 1) { /* TRX */
128 133 while (ack && s->txlen)
129 134 ack = (i2c_send(s->bus,
... ... @@ -162,6 +167,7 @@ static void omap_i2c_fifo_run(struct omap_i2c_s *s)
162 167 i2c_end_transfer(s->bus);
163 168 s->control &= ~(1 << 1); /* STP */
164 169 s->count_cur = s->count;
  170 + s->txlen = 0;
165 171 } else {
166 172 s->stat |= 1 << 2; /* ARDY */
167 173 s->control &= ~(1 << 10); /* MST */
... ... @@ -201,8 +207,7 @@ static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
201 207  
202 208 switch (offset) {
203 209 case 0x00: /* I2C_REV */
204   - /* TODO: set a value greater or equal to real hardware */
205   - return 0x11; /* REV */
  210 + return s->revision; /* REV */
206 211  
207 212 case 0x04: /* I2C_IE */
208 213 return s->mask;
... ... @@ -211,12 +216,17 @@ static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
211 216 return s->stat | (i2c_bus_busy(s->bus) << 12);
212 217  
213 218 case 0x0c: /* I2C_IV */
  219 + if (s->revision >= OMAP2_INTR_REV)
  220 + break;
214 221 ret = ffs(s->stat & s->mask);
215 222 if (ret)
216 223 s->stat ^= 1 << (ret - 1);
217 224 omap_i2c_interrupts_update(s);
218 225 return ret;
219 226  
  227 + case 0x10: /* I2C_SYSS */
  228 + return (s->control >> 15) & 1; /* I2C_EN */
  229 +
220 230 case 0x14: /* I2C_BUF */
221 231 return s->dma;
222 232  
... ... @@ -242,7 +252,7 @@ static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
242 252 } else
243 253 /* XXX: remote access (qualifier) error - what's that? */;
244 254 if (!s->rxlen) {
245   - s->stat |= ~(1 << 3); /* RRDY */
  255 + s->stat &= ~(1 << 3); /* RRDY */
246 256 if (((s->control >> 10) & 1) && /* MST */
247 257 ((~s->control >> 9) & 1)) { /* TRX */
248 258 s->stat |= 1 << 2; /* ARDY */
... ... @@ -254,6 +264,9 @@ static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
254 264 omap_i2c_interrupts_update(s);
255 265 return ret;
256 266  
  267 + case 0x20: /* I2C_SYSC */
  268 + return 0;
  269 +
257 270 case 0x24: /* I2C_CON */
258 271 return s->control;
259 272  
... ... @@ -293,13 +306,23 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
293 306  
294 307 switch (offset) {
295 308 case 0x00: /* I2C_REV */
296   - case 0x08: /* I2C_STAT */
297 309 case 0x0c: /* I2C_IV */
298   - OMAP_BAD_REG(addr);
  310 + case 0x10: /* I2C_SYSS */
  311 + OMAP_RO_REG(addr);
299 312 return;
300 313  
301 314 case 0x04: /* I2C_IE */
302   - s->mask = value & 0x1f;
  315 + s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
  316 + break;
  317 +
  318 + case 0x08: /* I2C_STAT */
  319 + if (s->revision < OMAP2_INTR_REV) {
  320 + OMAP_RO_REG(addr);
  321 + return;
  322 + }
  323 +
  324 + s->stat &= ~(value & 0x3f);
  325 + omap_i2c_interrupts_update(s);
303 326 break;
304 327  
305 328 case 0x14: /* I2C_BUF */
... ... @@ -335,29 +358,42 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
335 358 omap_i2c_interrupts_update(s);
336 359 break;
337 360  
  361 + case 0x20: /* I2C_SYSC */
  362 + if (s->revision < OMAP2_INTR_REV) {
  363 + OMAP_BAD_REG(addr);
  364 + return;
  365 + }
  366 +
  367 + if (value & 2)
  368 + omap_i2c_reset(s);
  369 + break;
  370 +
338 371 case 0x24: /* I2C_CON */
339   - s->control = value & 0xcf07;
  372 + s->control = value & 0xcf87;
340 373 if (~value & (1 << 15)) { /* I2C_EN */
341   - omap_i2c_reset(s);
  374 + if (s->revision < OMAP2_INTR_REV)
  375 + omap_i2c_reset(s);
342 376 break;
343 377 }
344   - if (~value & (1 << 10)) { /* MST */
  378 + if ((value & (1 << 15)) && !(value & (1 << 10))) { /* MST */
345 379 printf("%s: I^2C slave mode not supported\n", __FUNCTION__);
346 380 break;
347 381 }
348   - if (value & (1 << 9)) { /* XA */
  382 + if ((value & (1 << 15)) && value & (1 << 8)) { /* XA */
349 383 printf("%s: 10-bit addressing mode not supported\n", __FUNCTION__);
350 384 break;
351 385 }
352   - if (value & (1 << 0)) { /* STT */
  386 + if ((value & (1 << 15)) && value & (1 << 0)) { /* STT */
353 387 nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */
354 388 (~value >> 9) & 1); /* TRX */
355 389 s->stat |= nack << 1; /* NACK */
356 390 s->control &= ~(1 << 0); /* STT */
357 391 if (nack)
358 392 s->control &= ~(1 << 1); /* STP */
359   - else
  393 + else {
  394 + s->count_cur = s->count;
360 395 omap_i2c_fifo_run(s);
  396 + }
361 397 omap_i2c_interrupts_update(s);
362 398 }
363 399 break;
... ... @@ -384,7 +420,12 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
384 420 break;
385 421  
386 422 case 0x3c: /* I2C_SYSTEST */
387   - s->test = value & 0xf00f;
  423 + s->test = value & 0xf80f;
  424 + if (value & (1 << 11)) /* SBB */
  425 + if (s->revision >= OMAP2_INTR_REV) {
  426 + s->stat |= 0x3f;
  427 + omap_i2c_interrupts_update(s);
  428 + }
388 429 if (value & (1 << 15)) /* ST_EN */
389 430 printf("%s: System Test not supported\n", __FUNCTION__);
390 431 break;
... ... @@ -395,6 +436,34 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
395 436 }
396 437 }
397 438  
  439 +static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr,
  440 + uint32_t value)
  441 +{
  442 + struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
  443 + int offset = addr & OMAP_MPUI_REG_MASK;
  444 +
  445 + switch (offset) {
  446 + case 0x1c: /* I2C_DATA */
  447 + if (s->txlen > 2) {
  448 + /* XXX: remote access (qualifier) error - what's that? */
  449 + break;
  450 + }
  451 + s->fifo <<= 8;
  452 + s->txlen += 1;
  453 + s->fifo |= value & 0xff;
  454 + s->stat &= ~(1 << 10); /* XUDF */
  455 + if (s->txlen > 2)
  456 + s->stat &= ~(1 << 4); /* XRDY */
  457 + omap_i2c_fifo_run(s);
  458 + omap_i2c_interrupts_update(s);
  459 + break;
  460 +
  461 + default:
  462 + OMAP_BAD_REG(addr);
  463 + return;
  464 + }
  465 +}
  466 +
398 467 static CPUReadMemoryFunc *omap_i2c_readfn[] = {
399 468 omap_badwidth_read16,
400 469 omap_i2c_read,
... ... @@ -402,9 +471,9 @@ static CPUReadMemoryFunc *omap_i2c_readfn[] = {
402 471 };
403 472  
404 473 static CPUWriteMemoryFunc *omap_i2c_writefn[] = {
405   - omap_badwidth_write16,
  474 + omap_i2c_writeb, /* Only the last fifo write can be 8 bit. */
406 475 omap_i2c_write,
407   - omap_i2c_write, /* TODO: Only the last fifo write can be 8 bit. */
  476 + omap_badwidth_write16,
408 477 };
409 478  
410 479 struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
... ... @@ -414,6 +483,8 @@ struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
414 483 struct omap_i2c_s *s = (struct omap_i2c_s *)
415 484 qemu_mallocz(sizeof(struct omap_i2c_s));
416 485  
  486 + /* TODO: set a value greater or equal to real hardware */
  487 + s->revision = 0x11;
417 488 s->base = base;
418 489 s->irq = irq;
419 490 s->drq[0] = dma[0];
... ... @@ -431,6 +502,30 @@ struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
431 502 return s;
432 503 }
433 504  
  505 +struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
  506 + qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk)
  507 +{
  508 + int iomemtype;
  509 + struct omap_i2c_s *s = (struct omap_i2c_s *)
  510 + qemu_mallocz(sizeof(struct omap_i2c_s));
  511 +
  512 + s->revision = 0x34;
  513 + s->irq = irq;
  514 + s->drq[0] = dma[0];
  515 + s->drq[1] = dma[1];
  516 + s->slave.event = omap_i2c_event;
  517 + s->slave.recv = omap_i2c_rx;
  518 + s->slave.send = omap_i2c_tx;
  519 + s->bus = i2c_init_bus();
  520 + omap_i2c_reset(s);
  521 +
  522 + iomemtype = cpu_register_io_memory(0, omap_i2c_readfn,
  523 + omap_i2c_writefn, s);
  524 + s->base = omap_l4_attach(ta, 0, iomemtype);
  525 +
  526 + return s;
  527 +}
  528 +
434 529 i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
435 530 {
436 531 return s->bus;
... ...