Commit 99570a40ebec445ad05dd586b73c6117540f0450

Authored by balrog
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
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
... ...