Commit 99570a40ebec445ad05dd586b73c6117540f0450
1 parent
dcf414d6
OMAP2 EAC module.
Not yet hooked up to any CODEC. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4886 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
556 additions
and
4 deletions
hw/nseries.c
| ... | ... | @@ -57,7 +57,7 @@ struct n800_s { |
| 57 | 57 | #define N800_MMC2_WP_GPIO 8 |
| 58 | 58 | #define N800_UNKNOWN_GPIO0 9 /* out */ |
| 59 | 59 | #define N810_MMC2_VIOSD_GPIO 9 |
| 60 | -#define N800_UNKNOWN_GPIO1 10 /* out */ | |
| 60 | +#define N810_HEADSET_AMP_GPIO 10 | |
| 61 | 61 | #define N800_CAM_TURN_GPIO 12 |
| 62 | 62 | #define N810_GPS_RESET_GPIO 12 |
| 63 | 63 | #define N800_BLIZZARD_POWERDOWN_GPIO 15 |
| ... | ... | @@ -82,7 +82,7 @@ struct n800_s { |
| 82 | 82 | #define N8X0_MMC_CS_GPIO 96 |
| 83 | 83 | #define N8X0_WLAN_PWR_GPIO 97 |
| 84 | 84 | #define N8X0_BT_HOST_WKUP_GPIO 98 |
| 85 | -#define N800_UNKNOWN_GPIO3 101 /* out */ | |
| 85 | +#define N810_SPEAKER_AMP_GPIO 101 | |
| 86 | 86 | #define N810_KB_LOCK_GPIO 102 |
| 87 | 87 | #define N800_TSC_TS_GPIO 103 |
| 88 | 88 | #define N810_TSC_TS_GPIO 106 |
| ... | ... | @@ -96,6 +96,7 @@ struct n800_s { |
| 96 | 96 | #define N800_UNKNOWN_GPIO4 112 /* out */ |
| 97 | 97 | #define N810_SLEEPX_LED_GPIO 112 |
| 98 | 98 | #define N800_TSC_RESET_GPIO 118 /* ? */ |
| 99 | +#define N810_AIC33_RESET_GPIO 118 | |
| 99 | 100 | #define N800_TSC_UNKNOWN_GPIO 119 /* out */ |
| 100 | 101 | #define N8X0_TMP105_GPIO 125 |
| 101 | 102 | ... | ... |
hw/omap.h
| ... | ... | @@ -738,6 +738,10 @@ struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk); |
| 738 | 738 | void omap_tap_init(struct omap_target_agent_s *ta, |
| 739 | 739 | struct omap_mpu_state_s *mpu); |
| 740 | 740 | |
| 741 | +struct omap_eac_s; | |
| 742 | +struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta, | |
| 743 | + qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk); | |
| 744 | + | |
| 741 | 745 | /* omap_lcdc.c */ |
| 742 | 746 | struct omap_lcd_panel_s; |
| 743 | 747 | void omap_lcdc_reset(struct omap_lcd_panel_s *s); |
| ... | ... | @@ -957,6 +961,8 @@ struct omap_mpu_state_s { |
| 957 | 961 | struct omap_mcspi_s *mcspi[2]; |
| 958 | 962 | |
| 959 | 963 | struct omap_dss_s *dss; |
| 964 | + | |
| 965 | + struct omap_eac_s *eac; | |
| 960 | 966 | }; |
| 961 | 967 | |
| 962 | 968 | /* omap1.c */ | ... | ... |
hw/omap2.c
| ... | ... | @@ -26,6 +26,7 @@ |
| 26 | 26 | #include "qemu-timer.h" |
| 27 | 27 | #include "qemu-char.h" |
| 28 | 28 | #include "flash.h" |
| 29 | +#include "audio/audio.h" | |
| 29 | 30 | |
| 30 | 31 | /* GP timers */ |
| 31 | 32 | struct omap_gp_timer_s { |
| ... | ... | @@ -1420,6 +1421,541 @@ void omap_mcspi_attach(struct omap_mcspi_s *s, |
| 1420 | 1421 | s->ch[chipselect].opaque = opaque; |
| 1421 | 1422 | } |
| 1422 | 1423 | |
| 1424 | +/* Enhanced Audio Controller (CODEC only) */ | |
| 1425 | +struct omap_eac_s { | |
| 1426 | + target_phys_addr_t base; | |
| 1427 | + qemu_irq irq; | |
| 1428 | + | |
| 1429 | + uint16_t sysconfig; | |
| 1430 | + uint8_t config[4]; | |
| 1431 | + uint8_t control; | |
| 1432 | + uint8_t address; | |
| 1433 | + uint16_t data; | |
| 1434 | + uint8_t vtol; | |
| 1435 | + uint8_t vtsl; | |
| 1436 | + uint16_t mixer; | |
| 1437 | + uint16_t gain[4]; | |
| 1438 | + uint8_t att; | |
| 1439 | + uint16_t max[7]; | |
| 1440 | + | |
| 1441 | + struct { | |
| 1442 | + qemu_irq txdrq; | |
| 1443 | + qemu_irq rxdrq; | |
| 1444 | + uint32_t (*txrx)(void *opaque, uint32_t, int); | |
| 1445 | + void *opaque; | |
| 1446 | + | |
| 1447 | +#define EAC_BUF_LEN 1024 | |
| 1448 | + uint32_t rxbuf[EAC_BUF_LEN]; | |
| 1449 | + int rxlen; | |
| 1450 | + int rxavail; | |
| 1451 | + uint32_t txbuf[EAC_BUF_LEN]; | |
| 1452 | + int txlen; | |
| 1453 | + int txavail; | |
| 1454 | + | |
| 1455 | + int enable; | |
| 1456 | + int rate; | |
| 1457 | + | |
| 1458 | + uint16_t config[4]; | |
| 1459 | + | |
| 1460 | + /* These need to be moved to the actual codec */ | |
| 1461 | + QEMUSoundCard card; | |
| 1462 | + SWVoiceIn *in_voice; | |
| 1463 | + SWVoiceOut *out_voice; | |
| 1464 | + int hw_enable; | |
| 1465 | + } codec; | |
| 1466 | + | |
| 1467 | + struct { | |
| 1468 | + uint8_t control; | |
| 1469 | + uint16_t config; | |
| 1470 | + } modem, bt; | |
| 1471 | +}; | |
| 1472 | + | |
| 1473 | +static inline void omap_eac_interrupt_update(struct omap_eac_s *s) | |
| 1474 | +{ | |
| 1475 | + qemu_set_irq(s->irq, (s->codec.config[1] >> 14) & 1); /* AURDI */ | |
| 1476 | +} | |
| 1477 | + | |
| 1478 | +static inline void omap_eac_in_dmarequest_update(struct omap_eac_s *s) | |
| 1479 | +{ | |
| 1480 | + qemu_set_irq(s->codec.rxdrq, s->codec.rxavail + s->codec.rxlen && | |
| 1481 | + ((s->codec.config[1] >> 12) & 1)); /* DMAREN */ | |
| 1482 | +} | |
| 1483 | + | |
| 1484 | +static inline void omap_eac_out_dmarequest_update(struct omap_eac_s *s) | |
| 1485 | +{ | |
| 1486 | + qemu_set_irq(s->codec.txdrq, s->codec.txlen < s->codec.txavail && | |
| 1487 | + ((s->codec.config[1] >> 11) & 1)); /* DMAWEN */ | |
| 1488 | +} | |
| 1489 | + | |
| 1490 | +static inline void omap_eac_in_refill(struct omap_eac_s *s) | |
| 1491 | +{ | |
| 1492 | + int left, start = 0; | |
| 1493 | + | |
| 1494 | + s->codec.rxlen = MIN(s->codec.rxavail, EAC_BUF_LEN); | |
| 1495 | + s->codec.rxavail -= s->codec.rxlen; | |
| 1496 | + | |
| 1497 | + for (left = s->codec.rxlen << 2; left; start = (EAC_BUF_LEN << 2) - left) | |
| 1498 | + left -= AUD_read(s->codec.in_voice, | |
| 1499 | + (uint8_t *) s->codec.rxbuf + start, left); | |
| 1500 | +} | |
| 1501 | + | |
| 1502 | +static inline void omap_eac_out_empty(struct omap_eac_s *s) | |
| 1503 | +{ | |
| 1504 | + int left, start = 0; | |
| 1505 | + | |
| 1506 | + for (left = s->codec.txlen << 2; left; start = (s->codec.txlen << 2) - left) | |
| 1507 | + left -= AUD_write(s->codec.out_voice, | |
| 1508 | + (uint8_t *) s->codec.txbuf + start, left); | |
| 1509 | + | |
| 1510 | + s->codec.txavail -= s->codec.txlen; | |
| 1511 | + s->codec.txlen = 0; | |
| 1512 | +} | |
| 1513 | + | |
| 1514 | +static void omap_eac_in_cb(void *opaque, int avail_b) | |
| 1515 | +{ | |
| 1516 | + struct omap_eac_s *s = (struct omap_eac_s *) opaque; | |
| 1517 | + | |
| 1518 | + s->codec.rxavail = avail_b >> 2; | |
| 1519 | + omap_eac_in_dmarequest_update(s); | |
| 1520 | + /* TODO: possibly discard current buffer if overrun */ | |
| 1521 | +} | |
| 1522 | + | |
| 1523 | +static void omap_eac_out_cb(void *opaque, int free_b) | |
| 1524 | +{ | |
| 1525 | + struct omap_eac_s *s = (struct omap_eac_s *) opaque; | |
| 1526 | + | |
| 1527 | + s->codec.txavail = free_b >> 2; | |
| 1528 | + if (s->codec.txlen > s->codec.txavail) | |
| 1529 | + s->codec.txlen = s->codec.txavail; | |
| 1530 | + omap_eac_out_empty(s); | |
| 1531 | + omap_eac_out_dmarequest_update(s); | |
| 1532 | +} | |
| 1533 | + | |
| 1534 | +static void omap_eac_enable_update(struct omap_eac_s *s) | |
| 1535 | +{ | |
| 1536 | + s->codec.enable = !(s->codec.config[1] & 1) && /* EACPWD */ | |
| 1537 | + (s->codec.config[1] & 2) && /* AUDEN */ | |
| 1538 | + s->codec.hw_enable; | |
| 1539 | +} | |
| 1540 | + | |
| 1541 | +static const int omap_eac_fsint[4] = { | |
| 1542 | + 8000, | |
| 1543 | + 11025, | |
| 1544 | + 22050, | |
| 1545 | + 44100, | |
| 1546 | +}; | |
| 1547 | + | |
| 1548 | +static const int omap_eac_fsint2[8] = { | |
| 1549 | + 8000, | |
| 1550 | + 11025, | |
| 1551 | + 22050, | |
| 1552 | + 44100, | |
| 1553 | + 48000, | |
| 1554 | + 0, 0, 0, | |
| 1555 | +}; | |
| 1556 | + | |
| 1557 | +static const int omap_eac_fsint3[16] = { | |
| 1558 | + 8000, | |
| 1559 | + 11025, | |
| 1560 | + 16000, | |
| 1561 | + 22050, | |
| 1562 | + 24000, | |
| 1563 | + 32000, | |
| 1564 | + 44100, | |
| 1565 | + 48000, | |
| 1566 | + 0, 0, 0, 0, 0, 0, 0, 0, | |
| 1567 | +}; | |
| 1568 | + | |
| 1569 | +static void omap_eac_rate_update(struct omap_eac_s *s) | |
| 1570 | +{ | |
| 1571 | + int fsint[3]; | |
| 1572 | + | |
| 1573 | + fsint[2] = (s->codec.config[3] >> 9) & 0xf; | |
| 1574 | + fsint[1] = (s->codec.config[2] >> 0) & 0x7; | |
| 1575 | + fsint[0] = (s->codec.config[0] >> 6) & 0x3; | |
| 1576 | + if (fsint[2] < 0xf) | |
| 1577 | + s->codec.rate = omap_eac_fsint3[fsint[2]]; | |
| 1578 | + else if (fsint[1] < 0x7) | |
| 1579 | + s->codec.rate = omap_eac_fsint2[fsint[1]]; | |
| 1580 | + else | |
| 1581 | + s->codec.rate = omap_eac_fsint[fsint[0]]; | |
| 1582 | +} | |
| 1583 | + | |
| 1584 | +static void omap_eac_volume_update(struct omap_eac_s *s) | |
| 1585 | +{ | |
| 1586 | + /* TODO */ | |
| 1587 | +} | |
| 1588 | + | |
| 1589 | +static void omap_eac_format_update(struct omap_eac_s *s) | |
| 1590 | +{ | |
| 1591 | + audsettings_t fmt; | |
| 1592 | + | |
| 1593 | + omap_eac_out_empty(s); | |
| 1594 | + | |
| 1595 | + if (s->codec.in_voice) { | |
| 1596 | + AUD_set_active_in(s->codec.in_voice, 0); | |
| 1597 | + AUD_close_in(&s->codec.card, s->codec.in_voice); | |
| 1598 | + s->codec.in_voice = 0; | |
| 1599 | + } | |
| 1600 | + if (s->codec.out_voice) { | |
| 1601 | + AUD_set_active_out(s->codec.out_voice, 0); | |
| 1602 | + AUD_close_out(&s->codec.card, s->codec.out_voice); | |
| 1603 | + s->codec.out_voice = 0; | |
| 1604 | + } | |
| 1605 | + | |
| 1606 | + omap_eac_enable_update(s); | |
| 1607 | + if (!s->codec.enable) | |
| 1608 | + return; | |
| 1609 | + | |
| 1610 | + omap_eac_rate_update(s); | |
| 1611 | + fmt.endianness = ((s->codec.config[0] >> 8) & 1); /* LI_BI */ | |
| 1612 | + fmt.nchannels = ((s->codec.config[0] >> 10) & 1) ? 2 : 1; /* MN_ST */ | |
| 1613 | + fmt.freq = s->codec.rate; | |
| 1614 | + /* TODO: signedness possibly depends on the CODEC hardware - or | |
| 1615 | + * does I2S specify it? */ | |
| 1616 | + /* All register writes are 16 bits so we we store 16-bit samples | |
| 1617 | + * in the buffers regardless of AGCFR[B8_16] value. */ | |
| 1618 | + fmt.fmt = AUD_FMT_U16; | |
| 1619 | + | |
| 1620 | + s->codec.in_voice = AUD_open_in(&s->codec.card, s->codec.in_voice, | |
| 1621 | + "eac.codec.in", s, omap_eac_in_cb, &fmt); | |
| 1622 | + s->codec.out_voice = AUD_open_out(&s->codec.card, s->codec.out_voice, | |
| 1623 | + "eac.codec.out", s, omap_eac_out_cb, &fmt); | |
| 1624 | + | |
| 1625 | + omap_eac_volume_update(s); | |
| 1626 | + | |
| 1627 | + AUD_set_active_in(s->codec.in_voice, 1); | |
| 1628 | + AUD_set_active_out(s->codec.out_voice, 1); | |
| 1629 | +} | |
| 1630 | + | |
| 1631 | +static void omap_eac_reset(struct omap_eac_s *s) | |
| 1632 | +{ | |
| 1633 | + s->sysconfig = 0; | |
| 1634 | + s->config[0] = 0x0c; | |
| 1635 | + s->config[1] = 0x09; | |
| 1636 | + s->config[2] = 0xab; | |
| 1637 | + s->config[3] = 0x03; | |
| 1638 | + s->control = 0x00; | |
| 1639 | + s->address = 0x00; | |
| 1640 | + s->data = 0x0000; | |
| 1641 | + s->vtol = 0x00; | |
| 1642 | + s->vtsl = 0x00; | |
| 1643 | + s->mixer = 0x0000; | |
| 1644 | + s->gain[0] = 0xe7e7; | |
| 1645 | + s->gain[1] = 0x6767; | |
| 1646 | + s->gain[2] = 0x6767; | |
| 1647 | + s->gain[3] = 0x6767; | |
| 1648 | + s->att = 0xce; | |
| 1649 | + s->max[0] = 0; | |
| 1650 | + s->max[1] = 0; | |
| 1651 | + s->max[2] = 0; | |
| 1652 | + s->max[3] = 0; | |
| 1653 | + s->max[4] = 0; | |
| 1654 | + s->max[5] = 0; | |
| 1655 | + s->max[6] = 0; | |
| 1656 | + | |
| 1657 | + s->modem.control = 0x00; | |
| 1658 | + s->modem.config = 0x0000; | |
| 1659 | + s->bt.control = 0x00; | |
| 1660 | + s->bt.config = 0x0000; | |
| 1661 | + s->codec.config[0] = 0x0649; | |
| 1662 | + s->codec.config[1] = 0x0000; | |
| 1663 | + s->codec.config[2] = 0x0007; | |
| 1664 | + s->codec.config[3] = 0x1ffc; | |
| 1665 | + s->codec.rxlen = 0; | |
| 1666 | + s->codec.txlen = 0; | |
| 1667 | + s->codec.rxavail = 0; | |
| 1668 | + s->codec.txavail = 0; | |
| 1669 | + | |
| 1670 | + omap_eac_format_update(s); | |
| 1671 | + omap_eac_interrupt_update(s); | |
| 1672 | +} | |
| 1673 | + | |
| 1674 | +static uint32_t omap_eac_read(void *opaque, target_phys_addr_t addr) | |
| 1675 | +{ | |
| 1676 | + struct omap_eac_s *s = (struct omap_eac_s *) opaque; | |
| 1677 | + int offset = addr - s->base; | |
| 1678 | + | |
| 1679 | + switch (offset) { | |
| 1680 | + case 0x000: /* CPCFR1 */ | |
| 1681 | + return s->config[0]; | |
| 1682 | + case 0x004: /* CPCFR2 */ | |
| 1683 | + return s->config[1]; | |
| 1684 | + case 0x008: /* CPCFR3 */ | |
| 1685 | + return s->config[2]; | |
| 1686 | + case 0x00c: /* CPCFR4 */ | |
| 1687 | + return s->config[3]; | |
| 1688 | + | |
| 1689 | + case 0x010: /* CPTCTL */ | |
| 1690 | + return s->control | ((s->codec.rxavail + s->codec.rxlen > 0) << 7) | | |
| 1691 | + ((s->codec.txlen < s->codec.txavail) << 5); | |
| 1692 | + | |
| 1693 | + case 0x014: /* CPTTADR */ | |
| 1694 | + return s->address; | |
| 1695 | + case 0x018: /* CPTDATL */ | |
| 1696 | + return s->data & 0xff; | |
| 1697 | + case 0x01c: /* CPTDATH */ | |
| 1698 | + return s->data >> 8; | |
| 1699 | + case 0x020: /* CPTVSLL */ | |
| 1700 | + return s->vtol; | |
| 1701 | + case 0x024: /* CPTVSLH */ | |
| 1702 | + return s->vtsl | (3 << 5); /* CRDY1 | CRDY2 */ | |
| 1703 | + case 0x040: /* MPCTR */ | |
| 1704 | + return s->modem.control; | |
| 1705 | + case 0x044: /* MPMCCFR */ | |
| 1706 | + return s->modem.config; | |
| 1707 | + case 0x060: /* BPCTR */ | |
| 1708 | + return s->bt.control; | |
| 1709 | + case 0x064: /* BPMCCFR */ | |
| 1710 | + return s->bt.config; | |
| 1711 | + case 0x080: /* AMSCFR */ | |
| 1712 | + return s->mixer; | |
| 1713 | + case 0x084: /* AMVCTR */ | |
| 1714 | + return s->gain[0]; | |
| 1715 | + case 0x088: /* AM1VCTR */ | |
| 1716 | + return s->gain[1]; | |
| 1717 | + case 0x08c: /* AM2VCTR */ | |
| 1718 | + return s->gain[2]; | |
| 1719 | + case 0x090: /* AM3VCTR */ | |
| 1720 | + return s->gain[3]; | |
| 1721 | + case 0x094: /* ASTCTR */ | |
| 1722 | + return s->att; | |
| 1723 | + case 0x098: /* APD1LCR */ | |
| 1724 | + return s->max[0]; | |
| 1725 | + case 0x09c: /* APD1RCR */ | |
| 1726 | + return s->max[1]; | |
| 1727 | + case 0x0a0: /* APD2LCR */ | |
| 1728 | + return s->max[2]; | |
| 1729 | + case 0x0a4: /* APD2RCR */ | |
| 1730 | + return s->max[3]; | |
| 1731 | + case 0x0a8: /* APD3LCR */ | |
| 1732 | + return s->max[4]; | |
| 1733 | + case 0x0ac: /* APD3RCR */ | |
| 1734 | + return s->max[5]; | |
| 1735 | + case 0x0b0: /* APD4R */ | |
| 1736 | + return s->max[6]; | |
| 1737 | + case 0x0b4: /* ADWR */ | |
| 1738 | + /* This should be write-only? Docs list it as read-only. */ | |
| 1739 | + return 0x0000; | |
| 1740 | + case 0x0b8: /* ADRDR */ | |
| 1741 | + if (likely(s->codec.rxlen > 1)) | |
| 1742 | + return s->codec.rxbuf[EAC_BUF_LEN - s->codec.rxlen --]; | |
| 1743 | + else if (s->codec.rxlen) { | |
| 1744 | + if (s->codec.rxavail) | |
| 1745 | + omap_eac_in_refill(s); | |
| 1746 | + else { | |
| 1747 | + s->codec.rxlen = 0; | |
| 1748 | + omap_eac_in_dmarequest_update(s); | |
| 1749 | + } | |
| 1750 | + return s->codec.rxbuf[EAC_BUF_LEN - 1]; | |
| 1751 | + } | |
| 1752 | + return 0x0000; | |
| 1753 | + case 0x0bc: /* AGCFR */ | |
| 1754 | + return s->codec.config[0]; | |
| 1755 | + case 0x0c0: /* AGCTR */ | |
| 1756 | + return s->codec.config[1] | ((s->codec.config[1] & 2) << 14); | |
| 1757 | + case 0x0c4: /* AGCFR2 */ | |
| 1758 | + return s->codec.config[2]; | |
| 1759 | + case 0x0c8: /* AGCFR3 */ | |
| 1760 | + return s->codec.config[3]; | |
| 1761 | + case 0x0cc: /* MBPDMACTR */ | |
| 1762 | + case 0x0d0: /* MPDDMARR */ | |
| 1763 | + case 0x0d8: /* MPUDMARR */ | |
| 1764 | + case 0x0e4: /* BPDDMARR */ | |
| 1765 | + case 0x0ec: /* BPUDMARR */ | |
| 1766 | + return 0x0000; | |
| 1767 | + | |
| 1768 | + case 0x100: /* VERSION_NUMBER */ | |
| 1769 | + return 0x0010; | |
| 1770 | + | |
| 1771 | + case 0x104: /* SYSCONFIG */ | |
| 1772 | + return s->sysconfig; | |
| 1773 | + | |
| 1774 | + case 0x108: /* SYSSTATUS */ | |
| 1775 | + return 1 | 0xe; /* RESETDONE | stuff */ | |
| 1776 | + } | |
| 1777 | + | |
| 1778 | + OMAP_BAD_REG(addr); | |
| 1779 | + return 0; | |
| 1780 | +} | |
| 1781 | + | |
| 1782 | +static void omap_eac_write(void *opaque, target_phys_addr_t addr, | |
| 1783 | + uint32_t value) | |
| 1784 | +{ | |
| 1785 | + struct omap_eac_s *s = (struct omap_eac_s *) opaque; | |
| 1786 | + int offset = addr - s->base; | |
| 1787 | + | |
| 1788 | + switch (offset) { | |
| 1789 | + case 0x098: /* APD1LCR */ | |
| 1790 | + case 0x09c: /* APD1RCR */ | |
| 1791 | + case 0x0a0: /* APD2LCR */ | |
| 1792 | + case 0x0a4: /* APD2RCR */ | |
| 1793 | + case 0x0a8: /* APD3LCR */ | |
| 1794 | + case 0x0ac: /* APD3RCR */ | |
| 1795 | + case 0x0b0: /* APD4R */ | |
| 1796 | + case 0x0b8: /* ADRDR */ | |
| 1797 | + case 0x0d0: /* MPDDMARR */ | |
| 1798 | + case 0x0d8: /* MPUDMARR */ | |
| 1799 | + case 0x0e4: /* BPDDMARR */ | |
| 1800 | + case 0x0ec: /* BPUDMARR */ | |
| 1801 | + case 0x100: /* VERSION_NUMBER */ | |
| 1802 | + case 0x108: /* SYSSTATUS */ | |
| 1803 | + OMAP_RO_REG(addr); | |
| 1804 | + return; | |
| 1805 | + | |
| 1806 | + case 0x000: /* CPCFR1 */ | |
| 1807 | + s->config[0] = value & 0xff; | |
| 1808 | + omap_eac_format_update(s); | |
| 1809 | + break; | |
| 1810 | + case 0x004: /* CPCFR2 */ | |
| 1811 | + s->config[1] = value & 0xff; | |
| 1812 | + omap_eac_format_update(s); | |
| 1813 | + break; | |
| 1814 | + case 0x008: /* CPCFR3 */ | |
| 1815 | + s->config[2] = value & 0xff; | |
| 1816 | + omap_eac_format_update(s); | |
| 1817 | + break; | |
| 1818 | + case 0x00c: /* CPCFR4 */ | |
| 1819 | + s->config[3] = value & 0xff; | |
| 1820 | + omap_eac_format_update(s); | |
| 1821 | + break; | |
| 1822 | + | |
| 1823 | + case 0x010: /* CPTCTL */ | |
| 1824 | + /* Assuming TXF and TXE bits are read-only... */ | |
| 1825 | + s->control = value & 0x5f; | |
| 1826 | + omap_eac_interrupt_update(s); | |
| 1827 | + break; | |
| 1828 | + | |
| 1829 | + case 0x014: /* CPTTADR */ | |
| 1830 | + s->address = value & 0xff; | |
| 1831 | + break; | |
| 1832 | + case 0x018: /* CPTDATL */ | |
| 1833 | + s->data &= 0xff00; | |
| 1834 | + s->data |= value & 0xff; | |
| 1835 | + break; | |
| 1836 | + case 0x01c: /* CPTDATH */ | |
| 1837 | + s->data &= 0x00ff; | |
| 1838 | + s->data |= value << 8; | |
| 1839 | + break; | |
| 1840 | + case 0x020: /* CPTVSLL */ | |
| 1841 | + s->vtol = value & 0xf8; | |
| 1842 | + break; | |
| 1843 | + case 0x024: /* CPTVSLH */ | |
| 1844 | + s->vtsl = value & 0x9f; | |
| 1845 | + break; | |
| 1846 | + case 0x040: /* MPCTR */ | |
| 1847 | + s->modem.control = value & 0x8f; | |
| 1848 | + break; | |
| 1849 | + case 0x044: /* MPMCCFR */ | |
| 1850 | + s->modem.config = value & 0x7fff; | |
| 1851 | + break; | |
| 1852 | + case 0x060: /* BPCTR */ | |
| 1853 | + s->bt.control = value & 0x8f; | |
| 1854 | + break; | |
| 1855 | + case 0x064: /* BPMCCFR */ | |
| 1856 | + s->bt.config = value & 0x7fff; | |
| 1857 | + break; | |
| 1858 | + case 0x080: /* AMSCFR */ | |
| 1859 | + s->mixer = value & 0x0fff; | |
| 1860 | + break; | |
| 1861 | + case 0x084: /* AMVCTR */ | |
| 1862 | + s->gain[0] = value & 0xffff; | |
| 1863 | + break; | |
| 1864 | + case 0x088: /* AM1VCTR */ | |
| 1865 | + s->gain[1] = value & 0xff7f; | |
| 1866 | + break; | |
| 1867 | + case 0x08c: /* AM2VCTR */ | |
| 1868 | + s->gain[2] = value & 0xff7f; | |
| 1869 | + break; | |
| 1870 | + case 0x090: /* AM3VCTR */ | |
| 1871 | + s->gain[3] = value & 0xff7f; | |
| 1872 | + break; | |
| 1873 | + case 0x094: /* ASTCTR */ | |
| 1874 | + s->att = value & 0xff; | |
| 1875 | + break; | |
| 1876 | + | |
| 1877 | + case 0x0b4: /* ADWR */ | |
| 1878 | + s->codec.txbuf[s->codec.txlen ++] = value; | |
| 1879 | + if (unlikely(s->codec.txlen == EAC_BUF_LEN || | |
| 1880 | + s->codec.txlen == s->codec.txavail)) { | |
| 1881 | + if (s->codec.txavail) | |
| 1882 | + omap_eac_out_empty(s); | |
| 1883 | + else | |
| 1884 | + s->codec.txlen = 0; | |
| 1885 | + } | |
| 1886 | + break; | |
| 1887 | + | |
| 1888 | + case 0x0bc: /* AGCFR */ | |
| 1889 | + s->codec.config[0] = value & 0x07ff; | |
| 1890 | + omap_eac_format_update(s); | |
| 1891 | + break; | |
| 1892 | + case 0x0c0: /* AGCTR */ | |
| 1893 | + s->codec.config[1] = value & 0x780f; | |
| 1894 | + omap_eac_format_update(s); | |
| 1895 | + break; | |
| 1896 | + case 0x0c4: /* AGCFR2 */ | |
| 1897 | + s->codec.config[2] = value & 0x003f; | |
| 1898 | + omap_eac_format_update(s); | |
| 1899 | + break; | |
| 1900 | + case 0x0c8: /* AGCFR3 */ | |
| 1901 | + s->codec.config[3] = value & 0xffff; | |
| 1902 | + omap_eac_format_update(s); | |
| 1903 | + break; | |
| 1904 | + case 0x0cc: /* MBPDMACTR */ | |
| 1905 | + case 0x0d4: /* MPDDMAWR */ | |
| 1906 | + case 0x0e0: /* MPUDMAWR */ | |
| 1907 | + case 0x0e8: /* BPDDMAWR */ | |
| 1908 | + case 0x0f0: /* BPUDMAWR */ | |
| 1909 | + break; | |
| 1910 | + | |
| 1911 | + case 0x104: /* SYSCONFIG */ | |
| 1912 | + if (value & (1 << 1)) /* SOFTRESET */ | |
| 1913 | + omap_eac_reset(s); | |
| 1914 | + s->sysconfig = value & 0x31d; | |
| 1915 | + break; | |
| 1916 | + | |
| 1917 | + default: | |
| 1918 | + OMAP_BAD_REG(addr); | |
| 1919 | + return; | |
| 1920 | + } | |
| 1921 | +} | |
| 1922 | + | |
| 1923 | +static CPUReadMemoryFunc *omap_eac_readfn[] = { | |
| 1924 | + omap_badwidth_read16, | |
| 1925 | + omap_eac_read, | |
| 1926 | + omap_badwidth_read16, | |
| 1927 | +}; | |
| 1928 | + | |
| 1929 | +static CPUWriteMemoryFunc *omap_eac_writefn[] = { | |
| 1930 | + omap_badwidth_write16, | |
| 1931 | + omap_eac_write, | |
| 1932 | + omap_badwidth_write16, | |
| 1933 | +}; | |
| 1934 | + | |
| 1935 | +struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta, | |
| 1936 | + qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk) | |
| 1937 | +{ | |
| 1938 | + int iomemtype; | |
| 1939 | + struct omap_eac_s *s = (struct omap_eac_s *) | |
| 1940 | + qemu_mallocz(sizeof(struct omap_eac_s)); | |
| 1941 | + | |
| 1942 | + s->irq = irq; | |
| 1943 | + s->codec.rxdrq = *drq ++; | |
| 1944 | + s->codec.txdrq = *drq ++; | |
| 1945 | + omap_eac_reset(s); | |
| 1946 | + | |
| 1947 | +#ifdef HAS_AUDIO | |
| 1948 | + /* TODO: do AUD_init globally for machine */ | |
| 1949 | + AUD_register_card(AUD_init(), "OMAP EAC", &s->codec.card); | |
| 1950 | + | |
| 1951 | + iomemtype = cpu_register_io_memory(0, omap_eac_readfn, | |
| 1952 | + omap_eac_writefn, s); | |
| 1953 | + s->base = omap_l4_attach(ta, 0, iomemtype); | |
| 1954 | +#endif | |
| 1955 | + | |
| 1956 | + return s; | |
| 1957 | +} | |
| 1958 | + | |
| 1423 | 1959 | /* STI/XTI (emulation interface) console - reverse engineered only */ |
| 1424 | 1960 | struct omap_sti_s { |
| 1425 | 1961 | target_phys_addr_t base; |
| ... | ... | @@ -2566,6 +3102,7 @@ static void omap_prcm_write(void *opaque, target_phys_addr_t addr, |
| 2566 | 3102 | case 0x200: /* CM_FCLKEN1_CORE */ |
| 2567 | 3103 | s->clken[0] = value & 0xbfffffff; |
| 2568 | 3104 | /* TODO update clocks */ |
| 3105 | + /* The EN_EAC bit only gets/puts func_96m_clk. */ | |
| 2569 | 3106 | break; |
| 2570 | 3107 | case 0x204: /* CM_FCLKEN2_CORE */ |
| 2571 | 3108 | s->clken[1] = value & 0x00000007; |
| ... | ... | @@ -2574,6 +3111,7 @@ static void omap_prcm_write(void *opaque, target_phys_addr_t addr, |
| 2574 | 3111 | case 0x210: /* CM_ICLKEN1_CORE */ |
| 2575 | 3112 | s->clken[2] = value & 0xfffffff9; |
| 2576 | 3113 | /* TODO update clocks */ |
| 3114 | + /* The EN_EAC bit only gets/puts core_l4_iclk. */ | |
| 2577 | 3115 | break; |
| 2578 | 3116 | case 0x214: /* CM_ICLKEN2_CORE */ |
| 2579 | 3117 | s->clken[3] = value & 0x00000007; |
| ... | ... | @@ -3969,12 +4507,12 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size, |
| 3969 | 4507 | omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk")); |
| 3970 | 4508 | |
| 3971 | 4509 | s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4, |
| 3972 | - s->irq[0][OMAP_INT_24XX_MCSPI1_IRQ], | |
| 4510 | + s->irq[0][OMAP_INT_24XX_MCSPI1_IRQ], | |
| 3973 | 4511 | &s->drq[OMAP24XX_DMA_SPI1_TX0], |
| 3974 | 4512 | omap_findclk(s, "spi1_fclk"), |
| 3975 | 4513 | omap_findclk(s, "spi1_iclk")); |
| 3976 | 4514 | s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2, |
| 3977 | - s->irq[0][OMAP_INT_24XX_MCSPI2_IRQ], | |
| 4515 | + s->irq[0][OMAP_INT_24XX_MCSPI2_IRQ], | |
| 3978 | 4516 | &s->drq[OMAP24XX_DMA_SPI2_TX0], |
| 3979 | 4517 | omap_findclk(s, "spi2_fclk"), |
| 3980 | 4518 | omap_findclk(s, "spi2_iclk")); |
| ... | ... | @@ -3992,6 +4530,13 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size, |
| 3992 | 4530 | serial_hds[0] && serial_hds[1] && serial_hds[2] ? |
| 3993 | 4531 | serial_hds[3] : 0); |
| 3994 | 4532 | |
| 4533 | + s->eac = omap_eac_init(omap_l4ta(s->l4, 32), | |
| 4534 | + s->irq[0][OMAP_INT_24XX_EAC_IRQ], | |
| 4535 | + /* Ten consecutive lines */ | |
| 4536 | + &s->drq[OMAP24XX_DMA_EAC_AC_RD], | |
| 4537 | + omap_findclk(s, "func_96m_clk"), | |
| 4538 | + omap_findclk(s, "core_l4_iclk")); | |
| 4539 | + | |
| 3995 | 4540 | /* All register mappings (includin those not currenlty implemented): |
| 3996 | 4541 | * SystemControlMod 48000000 - 48000fff |
| 3997 | 4542 | * SystemControlL4 48001000 - 48001fff | ... | ... |