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 | ... | ... |