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