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,7 +57,7 @@ struct n800_s { | ||
| 57 | #define N800_MMC2_WP_GPIO 8 | 57 | #define N800_MMC2_WP_GPIO 8 |
| 58 | #define N800_UNKNOWN_GPIO0 9 /* out */ | 58 | #define N800_UNKNOWN_GPIO0 9 /* out */ |
| 59 | #define N810_MMC2_VIOSD_GPIO 9 | 59 | #define N810_MMC2_VIOSD_GPIO 9 |
| 60 | -#define N800_UNKNOWN_GPIO1 10 /* out */ | 60 | +#define N810_HEADSET_AMP_GPIO 10 |
| 61 | #define N800_CAM_TURN_GPIO 12 | 61 | #define N800_CAM_TURN_GPIO 12 |
| 62 | #define N810_GPS_RESET_GPIO 12 | 62 | #define N810_GPS_RESET_GPIO 12 |
| 63 | #define N800_BLIZZARD_POWERDOWN_GPIO 15 | 63 | #define N800_BLIZZARD_POWERDOWN_GPIO 15 |
| @@ -82,7 +82,7 @@ struct n800_s { | @@ -82,7 +82,7 @@ struct n800_s { | ||
| 82 | #define N8X0_MMC_CS_GPIO 96 | 82 | #define N8X0_MMC_CS_GPIO 96 |
| 83 | #define N8X0_WLAN_PWR_GPIO 97 | 83 | #define N8X0_WLAN_PWR_GPIO 97 |
| 84 | #define N8X0_BT_HOST_WKUP_GPIO 98 | 84 | #define N8X0_BT_HOST_WKUP_GPIO 98 |
| 85 | -#define N800_UNKNOWN_GPIO3 101 /* out */ | 85 | +#define N810_SPEAKER_AMP_GPIO 101 |
| 86 | #define N810_KB_LOCK_GPIO 102 | 86 | #define N810_KB_LOCK_GPIO 102 |
| 87 | #define N800_TSC_TS_GPIO 103 | 87 | #define N800_TSC_TS_GPIO 103 |
| 88 | #define N810_TSC_TS_GPIO 106 | 88 | #define N810_TSC_TS_GPIO 106 |
| @@ -96,6 +96,7 @@ struct n800_s { | @@ -96,6 +96,7 @@ struct n800_s { | ||
| 96 | #define N800_UNKNOWN_GPIO4 112 /* out */ | 96 | #define N800_UNKNOWN_GPIO4 112 /* out */ |
| 97 | #define N810_SLEEPX_LED_GPIO 112 | 97 | #define N810_SLEEPX_LED_GPIO 112 |
| 98 | #define N800_TSC_RESET_GPIO 118 /* ? */ | 98 | #define N800_TSC_RESET_GPIO 118 /* ? */ |
| 99 | +#define N810_AIC33_RESET_GPIO 118 | ||
| 99 | #define N800_TSC_UNKNOWN_GPIO 119 /* out */ | 100 | #define N800_TSC_UNKNOWN_GPIO 119 /* out */ |
| 100 | #define N8X0_TMP105_GPIO 125 | 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,6 +738,10 @@ struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk); | ||
| 738 | void omap_tap_init(struct omap_target_agent_s *ta, | 738 | void omap_tap_init(struct omap_target_agent_s *ta, |
| 739 | struct omap_mpu_state_s *mpu); | 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 | /* omap_lcdc.c */ | 745 | /* omap_lcdc.c */ |
| 742 | struct omap_lcd_panel_s; | 746 | struct omap_lcd_panel_s; |
| 743 | void omap_lcdc_reset(struct omap_lcd_panel_s *s); | 747 | void omap_lcdc_reset(struct omap_lcd_panel_s *s); |
| @@ -957,6 +961,8 @@ struct omap_mpu_state_s { | @@ -957,6 +961,8 @@ struct omap_mpu_state_s { | ||
| 957 | struct omap_mcspi_s *mcspi[2]; | 961 | struct omap_mcspi_s *mcspi[2]; |
| 958 | 962 | ||
| 959 | struct omap_dss_s *dss; | 963 | struct omap_dss_s *dss; |
| 964 | + | ||
| 965 | + struct omap_eac_s *eac; | ||
| 960 | }; | 966 | }; |
| 961 | 967 | ||
| 962 | /* omap1.c */ | 968 | /* omap1.c */ |
hw/omap2.c
| @@ -26,6 +26,7 @@ | @@ -26,6 +26,7 @@ | ||
| 26 | #include "qemu-timer.h" | 26 | #include "qemu-timer.h" |
| 27 | #include "qemu-char.h" | 27 | #include "qemu-char.h" |
| 28 | #include "flash.h" | 28 | #include "flash.h" |
| 29 | +#include "audio/audio.h" | ||
| 29 | 30 | ||
| 30 | /* GP timers */ | 31 | /* GP timers */ |
| 31 | struct omap_gp_timer_s { | 32 | struct omap_gp_timer_s { |
| @@ -1420,6 +1421,541 @@ void omap_mcspi_attach(struct omap_mcspi_s *s, | @@ -1420,6 +1421,541 @@ void omap_mcspi_attach(struct omap_mcspi_s *s, | ||
| 1420 | s->ch[chipselect].opaque = opaque; | 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 | /* STI/XTI (emulation interface) console - reverse engineered only */ | 1959 | /* STI/XTI (emulation interface) console - reverse engineered only */ |
| 1424 | struct omap_sti_s { | 1960 | struct omap_sti_s { |
| 1425 | target_phys_addr_t base; | 1961 | target_phys_addr_t base; |
| @@ -2566,6 +3102,7 @@ static void omap_prcm_write(void *opaque, target_phys_addr_t addr, | @@ -2566,6 +3102,7 @@ static void omap_prcm_write(void *opaque, target_phys_addr_t addr, | ||
| 2566 | case 0x200: /* CM_FCLKEN1_CORE */ | 3102 | case 0x200: /* CM_FCLKEN1_CORE */ |
| 2567 | s->clken[0] = value & 0xbfffffff; | 3103 | s->clken[0] = value & 0xbfffffff; |
| 2568 | /* TODO update clocks */ | 3104 | /* TODO update clocks */ |
| 3105 | + /* The EN_EAC bit only gets/puts func_96m_clk. */ | ||
| 2569 | break; | 3106 | break; |
| 2570 | case 0x204: /* CM_FCLKEN2_CORE */ | 3107 | case 0x204: /* CM_FCLKEN2_CORE */ |
| 2571 | s->clken[1] = value & 0x00000007; | 3108 | s->clken[1] = value & 0x00000007; |
| @@ -2574,6 +3111,7 @@ static void omap_prcm_write(void *opaque, target_phys_addr_t addr, | @@ -2574,6 +3111,7 @@ static void omap_prcm_write(void *opaque, target_phys_addr_t addr, | ||
| 2574 | case 0x210: /* CM_ICLKEN1_CORE */ | 3111 | case 0x210: /* CM_ICLKEN1_CORE */ |
| 2575 | s->clken[2] = value & 0xfffffff9; | 3112 | s->clken[2] = value & 0xfffffff9; |
| 2576 | /* TODO update clocks */ | 3113 | /* TODO update clocks */ |
| 3114 | + /* The EN_EAC bit only gets/puts core_l4_iclk. */ | ||
| 2577 | break; | 3115 | break; |
| 2578 | case 0x214: /* CM_ICLKEN2_CORE */ | 3116 | case 0x214: /* CM_ICLKEN2_CORE */ |
| 2579 | s->clken[3] = value & 0x00000007; | 3117 | s->clken[3] = value & 0x00000007; |
| @@ -3969,12 +4507,12 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size, | @@ -3969,12 +4507,12 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size, | ||
| 3969 | omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk")); | 4507 | omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk")); |
| 3970 | 4508 | ||
| 3971 | s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4, | 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 | &s->drq[OMAP24XX_DMA_SPI1_TX0], | 4511 | &s->drq[OMAP24XX_DMA_SPI1_TX0], |
| 3974 | omap_findclk(s, "spi1_fclk"), | 4512 | omap_findclk(s, "spi1_fclk"), |
| 3975 | omap_findclk(s, "spi1_iclk")); | 4513 | omap_findclk(s, "spi1_iclk")); |
| 3976 | s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2, | 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 | &s->drq[OMAP24XX_DMA_SPI2_TX0], | 4516 | &s->drq[OMAP24XX_DMA_SPI2_TX0], |
| 3979 | omap_findclk(s, "spi2_fclk"), | 4517 | omap_findclk(s, "spi2_fclk"), |
| 3980 | omap_findclk(s, "spi2_iclk")); | 4518 | omap_findclk(s, "spi2_iclk")); |
| @@ -3992,6 +4530,13 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size, | @@ -3992,6 +4530,13 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size, | ||
| 3992 | serial_hds[0] && serial_hds[1] && serial_hds[2] ? | 4530 | serial_hds[0] && serial_hds[1] && serial_hds[2] ? |
| 3993 | serial_hds[3] : 0); | 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 | /* All register mappings (includin those not currenlty implemented): | 4540 | /* All register mappings (includin those not currenlty implemented): |
| 3996 | * SystemControlMod 48000000 - 48000fff | 4541 | * SystemControlMod 48000000 - 48000fff |
| 3997 | * SystemControlL4 48001000 - 48001fff | 4542 | * SystemControlL4 48001000 - 48001fff |