Revision 99570a40 hw/omap2.c
b/hw/omap2.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 |
Also available in: Unified diff