Commit 026459262747819f90a4056292582661294342ce

Authored by balrog
1 parent 5c1c390f

Split I^2C controller out of hw/omap.c.

Insert a list of missing memory mappings from OMAP310 datasheet.
Add missing "rtc" field for RTC.
Correct PWL and PWT register read/write handler pointers.
Add a Changelog entry about OMAP emulation.
Add a qemu-doc snippet about Palm T|E platform.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3516 c046a42c-6fe2-441c-8c8c-71466251a162
Changelog
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau) 5 - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau)
6 - Several Sparc fixes (Aurelien Jarno, Blue Swirl, Robert Reif) 6 - Several Sparc fixes (Aurelien Jarno, Blue Swirl, Robert Reif)
7 - MIPS 64-bit FPU support (Thiemo Seufer) 7 - MIPS 64-bit FPU support (Thiemo Seufer)
8 - - Xscale PDA emulation (Andrzei Zaborowski) 8 + - Xscale PDA emulation (Andrzej Zaborowski)
9 - ColdFire system emulation (Paul Brook) 9 - ColdFire system emulation (Paul Brook)
10 - Improved SH4 support (Magnus Damm) 10 - Improved SH4 support (Magnus Damm)
11 - MIPS64 support (Aurelien Jarno, Thiemo Seufer) 11 - MIPS64 support (Aurelien Jarno, Thiemo Seufer)
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 - SPARC32PLUS execution support (Blue Swirl) 16 - SPARC32PLUS execution support (Blue Swirl)
17 - MIPS mipssim pequdo machine (Thiemo Seufer) 17 - MIPS mipssim pequdo machine (Thiemo Seufer)
18 - Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh) 18 - Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh)
  19 + - OMAP310 MPU emulation plus Palm T|E machine (Andrzej Zaborowski)
19 20
20 version 0.9.0: 21 version 0.9.0:
21 22
Makefile.target
@@ -519,7 +519,8 @@ VL_OBJS+= arm-semi.o @@ -519,7 +519,8 @@ VL_OBJS+= arm-semi.o
519 VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o 519 VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
520 VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o 520 VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o
521 VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o ecc.o $(AUDIODRV) wm8750.o 521 VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o ecc.o $(AUDIODRV) wm8750.o
522 -VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o palm.o tsc210x.o 522 +VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o omap_i2c.o
  523 +VL_OBJS+= palm.o tsc210x.o
523 CPPFLAGS += -DHAS_AUDIO 524 CPPFLAGS += -DHAS_AUDIO
524 endif 525 endif
525 ifeq ($(TARGET_BASE_ARCH), sh4) 526 ifeq ($(TARGET_BASE_ARCH), sh4)
hw/omap.c
@@ -24,8 +24,11 @@ @@ -24,8 +24,11 @@
24 /* Should signal the TCMI */ 24 /* Should signal the TCMI */
25 uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr) 25 uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr)
26 { 26 {
  27 + uint8_t ret;
  28 +
27 OMAP_8B_REG(addr); 29 OMAP_8B_REG(addr);
28 - return 0; 30 + cpu_physical_memory_read(addr, &ret, 1);
  31 + return ret;
29 } 32 }
30 33
31 void omap_badwidth_write8(void *opaque, target_phys_addr_t addr, 34 void omap_badwidth_write8(void *opaque, target_phys_addr_t addr,
@@ -3466,15 +3469,15 @@ static void omap_pwl_write(void *opaque, target_phys_addr_t addr, @@ -3466,15 +3469,15 @@ static void omap_pwl_write(void *opaque, target_phys_addr_t addr,
3466 } 3469 }
3467 3470
3468 static CPUReadMemoryFunc *omap_pwl_readfn[] = { 3471 static CPUReadMemoryFunc *omap_pwl_readfn[] = {
  3472 + omap_pwl_read,
3469 omap_badwidth_read8, 3473 omap_badwidth_read8,
3470 omap_badwidth_read8, 3474 omap_badwidth_read8,
3471 - omap_pwl_read,  
3472 }; 3475 };
3473 3476
3474 static CPUWriteMemoryFunc *omap_pwl_writefn[] = { 3477 static CPUWriteMemoryFunc *omap_pwl_writefn[] = {
  3478 + omap_pwl_write,
3475 omap_badwidth_write8, 3479 omap_badwidth_write8,
3476 omap_badwidth_write8, 3480 omap_badwidth_write8,
3477 - omap_pwl_write,  
3478 }; 3481 };
3479 3482
3480 void omap_pwl_reset(struct omap_mpu_state_s *s) 3483 void omap_pwl_reset(struct omap_mpu_state_s *s)
@@ -3571,15 +3574,15 @@ static void omap_pwt_write(void *opaque, target_phys_addr_t addr, @@ -3571,15 +3574,15 @@ static void omap_pwt_write(void *opaque, target_phys_addr_t addr,
3571 } 3574 }
3572 3575
3573 static CPUReadMemoryFunc *omap_pwt_readfn[] = { 3576 static CPUReadMemoryFunc *omap_pwt_readfn[] = {
  3577 + omap_pwt_read,
3574 omap_badwidth_read8, 3578 omap_badwidth_read8,
3575 omap_badwidth_read8, 3579 omap_badwidth_read8,
3576 - omap_pwt_read,  
3577 }; 3580 };
3578 3581
3579 static CPUWriteMemoryFunc *omap_pwt_writefn[] = { 3582 static CPUWriteMemoryFunc *omap_pwt_writefn[] = {
  3583 + omap_pwt_write,
3580 omap_badwidth_write8, 3584 omap_badwidth_write8,
3581 omap_badwidth_write8, 3585 omap_badwidth_write8,
3582 - omap_pwt_write,  
3583 }; 3586 };
3584 3587
3585 void omap_pwt_reset(struct omap_mpu_state_s *s) 3588 void omap_pwt_reset(struct omap_mpu_state_s *s)
@@ -3603,421 +3606,6 @@ static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s, @@ -3603,421 +3606,6 @@ static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s,
3603 cpu_register_physical_memory(s->pwt.base, 0x800, iomemtype); 3606 cpu_register_physical_memory(s->pwt.base, 0x800, iomemtype);
3604 } 3607 }
3605 3608
3606 -/* Inter-Integrated Circuit Controller (only the "New I2C") */  
3607 -struct omap_i2c_s {  
3608 - target_phys_addr_t base;  
3609 - qemu_irq irq;  
3610 - qemu_irq drq[2];  
3611 - i2c_slave slave;  
3612 - i2c_bus *bus;  
3613 -  
3614 - uint8_t mask;  
3615 - uint16_t stat;  
3616 - uint16_t dma;  
3617 - uint16_t count;  
3618 - int count_cur;  
3619 - uint32_t fifo;  
3620 - int rxlen;  
3621 - int txlen;  
3622 - uint16_t control;  
3623 - uint16_t addr[2];  
3624 - uint8_t divider;  
3625 - uint8_t times[2];  
3626 - uint16_t test;  
3627 -};  
3628 -  
3629 -static void omap_i2c_interrupts_update(struct omap_i2c_s *s)  
3630 -{  
3631 - qemu_set_irq(s->irq, s->stat & s->mask);  
3632 - if ((s->dma >> 15) & 1) /* RDMA_EN */  
3633 - qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */  
3634 - if ((s->dma >> 7) & 1) /* XDMA_EN */  
3635 - qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */  
3636 -}  
3637 -  
3638 -/* These are only stubs now. */  
3639 -static void omap_i2c_event(i2c_slave *i2c, enum i2c_event event)  
3640 -{  
3641 - struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;  
3642 -  
3643 - if ((~s->control >> 15) & 1) /* I2C_EN */  
3644 - return;  
3645 -  
3646 - switch (event) {  
3647 - case I2C_START_SEND:  
3648 - case I2C_START_RECV:  
3649 - s->stat |= 1 << 9; /* AAS */  
3650 - break;  
3651 - case I2C_FINISH:  
3652 - s->stat |= 1 << 2; /* ARDY */  
3653 - break;  
3654 - case I2C_NACK:  
3655 - s->stat |= 1 << 1; /* NACK */  
3656 - break;  
3657 - }  
3658 -  
3659 - omap_i2c_interrupts_update(s);  
3660 -}  
3661 -  
3662 -static int omap_i2c_rx(i2c_slave *i2c)  
3663 -{  
3664 - struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;  
3665 - uint8_t ret = 0;  
3666 -  
3667 - if ((~s->control >> 15) & 1) /* I2C_EN */  
3668 - return -1;  
3669 -  
3670 - if (s->txlen)  
3671 - ret = s->fifo >> ((-- s->txlen) << 3) & 0xff;  
3672 - else  
3673 - s->stat |= 1 << 10; /* XUDF */  
3674 - s->stat |= 1 << 4; /* XRDY */  
3675 -  
3676 - omap_i2c_interrupts_update(s);  
3677 - return ret;  
3678 -}  
3679 -  
3680 -static int omap_i2c_tx(i2c_slave *i2c, uint8_t data)  
3681 -{  
3682 - struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;  
3683 -  
3684 - if ((~s->control >> 15) & 1) /* I2C_EN */  
3685 - return 1;  
3686 -  
3687 - if (s->rxlen < 4)  
3688 - s->fifo |= data << ((s->rxlen ++) << 3);  
3689 - else  
3690 - s->stat |= 1 << 11; /* ROVR */  
3691 - s->stat |= 1 << 3; /* RRDY */  
3692 -  
3693 - omap_i2c_interrupts_update(s);  
3694 - return 1;  
3695 -}  
3696 -  
3697 -static void omap_i2c_fifo_run(struct omap_i2c_s *s)  
3698 -{  
3699 - int ack = 1;  
3700 -  
3701 - if (!i2c_bus_busy(s->bus))  
3702 - return;  
3703 -  
3704 - if ((s->control >> 2) & 1) { /* RM */  
3705 - if ((s->control >> 1) & 1) { /* STP */  
3706 - i2c_end_transfer(s->bus);  
3707 - s->control &= ~(1 << 1); /* STP */  
3708 - s->count_cur = s->count;  
3709 - } else if ((s->control >> 9) & 1) { /* TRX */  
3710 - while (ack && s->txlen)  
3711 - ack = (i2c_send(s->bus,  
3712 - (s->fifo >> ((-- s->txlen) << 3)) &  
3713 - 0xff) >= 0);  
3714 - s->stat |= 1 << 4; /* XRDY */  
3715 - } else {  
3716 - while (s->rxlen < 4)  
3717 - s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);  
3718 - s->stat |= 1 << 3; /* RRDY */  
3719 - }  
3720 - } else {  
3721 - if ((s->control >> 9) & 1) { /* TRX */  
3722 - while (ack && s->count_cur && s->txlen) {  
3723 - ack = (i2c_send(s->bus,  
3724 - (s->fifo >> ((-- s->txlen) << 3)) &  
3725 - 0xff) >= 0);  
3726 - s->count_cur --;  
3727 - }  
3728 - if (ack && s->count_cur)  
3729 - s->stat |= 1 << 4; /* XRDY */  
3730 - if (!s->count_cur) {  
3731 - s->stat |= 1 << 2; /* ARDY */  
3732 - s->control &= ~(1 << 10); /* MST */  
3733 - }  
3734 - } else {  
3735 - while (s->count_cur && s->rxlen < 4) {  
3736 - s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);  
3737 - s->count_cur --;  
3738 - }  
3739 - if (s->rxlen)  
3740 - s->stat |= 1 << 3; /* RRDY */  
3741 - }  
3742 - if (!s->count_cur) {  
3743 - if ((s->control >> 1) & 1) { /* STP */  
3744 - i2c_end_transfer(s->bus);  
3745 - s->control &= ~(1 << 1); /* STP */  
3746 - s->count_cur = s->count;  
3747 - } else {  
3748 - s->stat |= 1 << 2; /* ARDY */  
3749 - s->control &= ~(1 << 10); /* MST */  
3750 - }  
3751 - }  
3752 - }  
3753 -  
3754 - s->stat |= (!ack) << 1; /* NACK */  
3755 - if (!ack)  
3756 - s->control &= ~(1 << 1); /* STP */  
3757 -}  
3758 -  
3759 -static void omap_i2c_reset(struct omap_i2c_s *s)  
3760 -{  
3761 - s->mask = 0;  
3762 - s->stat = 0;  
3763 - s->dma = 0;  
3764 - s->count = 0;  
3765 - s->count_cur = 0;  
3766 - s->fifo = 0;  
3767 - s->rxlen = 0;  
3768 - s->txlen = 0;  
3769 - s->control = 0;  
3770 - s->addr[0] = 0;  
3771 - s->addr[1] = 0;  
3772 - s->divider = 0;  
3773 - s->times[0] = 0;  
3774 - s->times[1] = 0;  
3775 - s->test = 0;  
3776 -}  
3777 -  
3778 -static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)  
3779 -{  
3780 - struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;  
3781 - int offset = addr - s->base;  
3782 - uint16_t ret;  
3783 -  
3784 - switch (offset) {  
3785 - case 0x00: /* I2C_REV */  
3786 - /* TODO: set a value greater or equal to real hardware */  
3787 - return 0x11; /* REV */  
3788 -  
3789 - case 0x04: /* I2C_IE */  
3790 - return s->mask;  
3791 -  
3792 - case 0x08: /* I2C_STAT */  
3793 - return s->stat | (i2c_bus_busy(s->bus) << 12);  
3794 -  
3795 - case 0x0c: /* I2C_IV */  
3796 - ret = ffs(s->stat & s->mask);  
3797 - if (ret)  
3798 - s->stat ^= 1 << (ret - 1);  
3799 - omap_i2c_interrupts_update(s);  
3800 - return ret;  
3801 -  
3802 - case 0x14: /* I2C_BUF */  
3803 - return s->dma;  
3804 -  
3805 - case 0x18: /* I2C_CNT */  
3806 - return s->count_cur; /* DCOUNT */  
3807 -  
3808 - case 0x1c: /* I2C_DATA */  
3809 - ret = 0;  
3810 - if (s->control & (1 << 14)) { /* BE */  
3811 - ret |= ((s->fifo >> 0) & 0xff) << 8;  
3812 - ret |= ((s->fifo >> 8) & 0xff) << 0;  
3813 - } else {  
3814 - ret |= ((s->fifo >> 8) & 0xff) << 8;  
3815 - ret |= ((s->fifo >> 0) & 0xff) << 0;  
3816 - }  
3817 - if (s->rxlen == 1) {  
3818 - s->stat |= 1 << 15; /* SBD */  
3819 - s->rxlen = 0;  
3820 - } else if (s->rxlen > 1) {  
3821 - if (s->rxlen > 2)  
3822 - s->fifo >>= 16;  
3823 - s->rxlen -= 2;  
3824 - } else  
3825 - /* XXX: remote access (qualifier) error - what's that? */;  
3826 - if (!s->rxlen) {  
3827 - s->stat |= ~(1 << 3); /* RRDY */  
3828 - if (((s->control >> 10) & 1) && /* MST */  
3829 - ((~s->control >> 9) & 1)) { /* TRX */  
3830 - s->stat |= 1 << 2; /* ARDY */  
3831 - s->control &= ~(1 << 10); /* MST */  
3832 - }  
3833 - }  
3834 - s->stat &= ~(1 << 11); /* ROVR */  
3835 - omap_i2c_fifo_run(s);  
3836 - omap_i2c_interrupts_update(s);  
3837 - return ret;  
3838 -  
3839 - case 0x24: /* I2C_CON */  
3840 - return s->control;  
3841 -  
3842 - case 0x28: /* I2C_OA */  
3843 - return s->addr[0];  
3844 -  
3845 - case 0x2c: /* I2C_SA */  
3846 - return s->addr[1];  
3847 -  
3848 - case 0x30: /* I2C_PSC */  
3849 - return s->divider;  
3850 -  
3851 - case 0x34: /* I2C_SCLL */  
3852 - return s->times[0];  
3853 -  
3854 - case 0x38: /* I2C_SCLH */  
3855 - return s->times[1];  
3856 -  
3857 - case 0x3c: /* I2C_SYSTEST */  
3858 - if (s->test & (1 << 15)) { /* ST_EN */  
3859 - s->test ^= 0xa;  
3860 - return s->test;  
3861 - } else  
3862 - return s->test & ~0x300f;  
3863 - }  
3864 -  
3865 - OMAP_BAD_REG(addr);  
3866 - return 0;  
3867 -}  
3868 -  
3869 -static void omap_i2c_write(void *opaque, target_phys_addr_t addr,  
3870 - uint32_t value)  
3871 -{  
3872 - struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;  
3873 - int offset = addr - s->base;  
3874 - int nack;  
3875 -  
3876 - switch (offset) {  
3877 - case 0x00: /* I2C_REV */  
3878 - case 0x08: /* I2C_STAT */  
3879 - case 0x0c: /* I2C_IV */  
3880 - OMAP_BAD_REG(addr);  
3881 - return;  
3882 -  
3883 - case 0x04: /* I2C_IE */  
3884 - s->mask = value & 0x1f;  
3885 - break;  
3886 -  
3887 - case 0x14: /* I2C_BUF */  
3888 - s->dma = value & 0x8080;  
3889 - if (value & (1 << 15)) /* RDMA_EN */  
3890 - s->mask &= ~(1 << 3); /* RRDY_IE */  
3891 - if (value & (1 << 7)) /* XDMA_EN */  
3892 - s->mask &= ~(1 << 4); /* XRDY_IE */  
3893 - break;  
3894 -  
3895 - case 0x18: /* I2C_CNT */  
3896 - s->count = value; /* DCOUNT */  
3897 - break;  
3898 -  
3899 - case 0x1c: /* I2C_DATA */  
3900 - if (s->txlen > 2) {  
3901 - /* XXX: remote access (qualifier) error - what's that? */  
3902 - break;  
3903 - }  
3904 - s->fifo <<= 16;  
3905 - s->txlen += 2;  
3906 - if (s->control & (1 << 14)) { /* BE */  
3907 - s->fifo |= ((value >> 8) & 0xff) << 8;  
3908 - s->fifo |= ((value >> 0) & 0xff) << 0;  
3909 - } else {  
3910 - s->fifo |= ((value >> 0) & 0xff) << 8;  
3911 - s->fifo |= ((value >> 8) & 0xff) << 0;  
3912 - }  
3913 - s->stat &= ~(1 << 10); /* XUDF */  
3914 - if (s->txlen > 2)  
3915 - s->stat &= ~(1 << 4); /* XRDY */  
3916 - omap_i2c_fifo_run(s);  
3917 - omap_i2c_interrupts_update(s);  
3918 - break;  
3919 -  
3920 - case 0x24: /* I2C_CON */  
3921 - s->control = value & 0xcf07;  
3922 - if (~value & (1 << 15)) { /* I2C_EN */  
3923 - omap_i2c_reset(s);  
3924 - break;  
3925 - }  
3926 - if (~value & (1 << 10)) { /* MST */  
3927 - printf("%s: I^2C slave mode not supported\n", __FUNCTION__);  
3928 - break;  
3929 - }  
3930 - if (value & (1 << 9)) { /* XA */  
3931 - printf("%s: 10-bit addressing mode not supported\n", __FUNCTION__);  
3932 - break;  
3933 - }  
3934 - if (value & (1 << 0)) { /* STT */  
3935 - nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */  
3936 - (~value >> 9) & 1); /* TRX */  
3937 - s->stat |= nack << 1; /* NACK */  
3938 - s->control &= ~(1 << 0); /* STT */  
3939 - if (nack)  
3940 - s->control &= ~(1 << 1); /* STP */  
3941 - else  
3942 - omap_i2c_fifo_run(s);  
3943 - omap_i2c_interrupts_update(s);  
3944 - }  
3945 - break;  
3946 -  
3947 - case 0x28: /* I2C_OA */  
3948 - s->addr[0] = value & 0x3ff;  
3949 - i2c_set_slave_address(&s->slave, value & 0x7f);  
3950 - break;  
3951 -  
3952 - case 0x2c: /* I2C_SA */  
3953 - s->addr[1] = value & 0x3ff;  
3954 - break;  
3955 -  
3956 - case 0x30: /* I2C_PSC */  
3957 - s->divider = value;  
3958 - break;  
3959 -  
3960 - case 0x34: /* I2C_SCLL */  
3961 - s->times[0] = value;  
3962 - break;  
3963 -  
3964 - case 0x38: /* I2C_SCLH */  
3965 - s->times[1] = value;  
3966 - break;  
3967 -  
3968 - case 0x3c: /* I2C_SYSTEST */  
3969 - s->test = value & 0xf00f;  
3970 - if (value & (1 << 15)) /* ST_EN */  
3971 - printf("%s: System Test not supported\n", __FUNCTION__);  
3972 - break;  
3973 -  
3974 - default:  
3975 - OMAP_BAD_REG(addr);  
3976 - return;  
3977 - }  
3978 -}  
3979 -  
3980 -static CPUReadMemoryFunc *omap_i2c_readfn[] = {  
3981 - omap_badwidth_read16,  
3982 - omap_i2c_read,  
3983 - omap_badwidth_read16,  
3984 -};  
3985 -  
3986 -static CPUWriteMemoryFunc *omap_i2c_writefn[] = {  
3987 - omap_badwidth_write16,  
3988 - omap_i2c_write,  
3989 - omap_i2c_write, /* TODO: Only the last fifo write can be 8 bit. */  
3990 -};  
3991 -  
3992 -struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,  
3993 - qemu_irq irq, qemu_irq *dma, omap_clk clk)  
3994 -{  
3995 - int iomemtype;  
3996 - struct omap_i2c_s *s = (struct omap_i2c_s *)  
3997 - qemu_mallocz(sizeof(struct omap_i2c_s));  
3998 -  
3999 - s->base = base;  
4000 - s->irq = irq;  
4001 - s->drq[0] = dma[0];  
4002 - s->drq[1] = dma[1];  
4003 - s->slave.event = omap_i2c_event;  
4004 - s->slave.recv = omap_i2c_rx;  
4005 - s->slave.send = omap_i2c_tx;  
4006 - s->bus = i2c_init_bus();  
4007 - omap_i2c_reset(s);  
4008 -  
4009 - iomemtype = cpu_register_io_memory(0, omap_i2c_readfn,  
4010 - omap_i2c_writefn, s);  
4011 - cpu_register_physical_memory(s->base, 0x800, iomemtype);  
4012 -  
4013 - return s;  
4014 -}  
4015 -  
4016 -i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)  
4017 -{  
4018 - return s->bus;  
4019 -}  
4020 -  
4021 /* Real-time Clock module */ 3609 /* Real-time Clock module */
4022 struct omap_rtc_s { 3610 struct omap_rtc_s {
4023 target_phys_addr_t base; 3611 target_phys_addr_t base;
@@ -4607,6 +4195,26 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, @@ -4607,6 +4195,26 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
4607 4195
4608 s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER], 4196 s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER],
4609 omap_findclk(s, "clk32-kHz")); 4197 omap_findclk(s, "clk32-kHz"));
  4198 +
  4199 + /* Register mappings not currenlty implemented:
  4200 + * McBSP2 Comm fffb1000 - fffb17ff
  4201 + * McBSP1 Audio fffb1800 - fffb1fff (not mapped on OMAP310)
  4202 + * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310)
  4203 + * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310)
  4204 + * USB W2FC fffb4000 - fffb47ff
  4205 + * Camera Interface fffb6800 - fffb6fff
  4206 + * McBSP3 fffb7000 - fffb77ff (not mapped on OMAP310)
  4207 + * USB Host fffba000 - fffba7ff
  4208 + * FAC fffba800 - fffbafff
  4209 + * HDQ/1-Wire fffbc000 - fffbc7ff
  4210 + * LED1 fffbd000 - fffbd7ff
  4211 + * LED2 fffbd800 - fffbdfff
  4212 + * Mailbox fffcf000 - fffcf7ff
  4213 + * Local bus IF fffec100 - fffec1ff
  4214 + * Local bus MMU fffec200 - fffec2ff
  4215 + * DSP MMU fffed200 - fffed2ff
  4216 + */
  4217 +
4610 qemu_register_reset(omap_mpu_reset, s); 4218 qemu_register_reset(omap_mpu_reset, s);
4611 4219
4612 return s; 4220 return s;
hw/omap.h
@@ -475,11 +475,6 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, @@ -475,11 +475,6 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
475 void omap_uwire_attach(struct omap_uwire_s *s, 475 void omap_uwire_attach(struct omap_uwire_s *s,
476 struct uwire_slave_s *slave, int chipselect); 476 struct uwire_slave_s *slave, int chipselect);
477 477
478 -struct omap_i2c_s;  
479 -struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,  
480 - qemu_irq irq, qemu_irq *dma, omap_clk clk);  
481 -i2c_bus *omap_i2c_bus(struct omap_i2c_s *s);  
482 -  
483 struct omap_rtc_s; 478 struct omap_rtc_s;
484 struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, 479 struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base,
485 qemu_irq *irq, omap_clk clk); 480 qemu_irq *irq, omap_clk clk);
@@ -498,6 +493,13 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, @@ -498,6 +493,13 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
498 void omap_mmc_reset(struct omap_mmc_s *s); 493 void omap_mmc_reset(struct omap_mmc_s *s);
499 void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover); 494 void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover);
500 495
  496 +/* omap_i2c.c */
  497 +struct omap_i2c_s;
  498 +struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
  499 + qemu_irq irq, qemu_irq *dma, omap_clk clk);
  500 +void omap_i2c_reset(struct omap_i2c_s *s);
  501 +i2c_bus *omap_i2c_bus(struct omap_i2c_s *s);
  502 +
501 # define cpu_is_omap310(cpu) (cpu->mpu_model == omap310) 503 # define cpu_is_omap310(cpu) (cpu->mpu_model == omap310)
502 # define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510) 504 # define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510)
503 # define cpu_is_omap15xx(cpu) \ 505 # define cpu_is_omap15xx(cpu) \
@@ -561,6 +563,8 @@ struct omap_mpu_state_s { @@ -561,6 +563,8 @@ struct omap_mpu_state_s {
561 563
562 struct omap_i2c_s *i2c; 564 struct omap_i2c_s *i2c;
563 565
  566 + struct omap_rtc_s *rtc;
  567 +
564 /* MPU private TIPB peripherals */ 568 /* MPU private TIPB peripherals */
565 struct omap_intr_handler_s *ih[2]; 569 struct omap_intr_handler_s *ih[2];
566 570
hw/omap_i2c.c 0 โ†’ 100644
  1 +/*
  2 + * TI OMAP on-chip I2C controller. Only "new I2C" mode supported.
  3 + *
  4 + * Copyright (C) 2007 Andrzej Zaborowski <balrog@zabor.org>
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public License as
  8 + * published by the Free Software Foundation; either version 2 of
  9 + * the License, or (at your option) any later version.
  10 + *
  11 + * This program is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 + * GNU General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU General Public License
  17 + * along with this program; if not, write to the Free Software
  18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  19 + * MA 02111-1307 USA
  20 + */
  21 +#include "vl.h"
  22 +
  23 +struct omap_i2c_s {
  24 + target_phys_addr_t base;
  25 + qemu_irq irq;
  26 + qemu_irq drq[2];
  27 + i2c_slave slave;
  28 + i2c_bus *bus;
  29 +
  30 + uint8_t mask;
  31 + uint16_t stat;
  32 + uint16_t dma;
  33 + uint16_t count;
  34 + int count_cur;
  35 + uint32_t fifo;
  36 + int rxlen;
  37 + int txlen;
  38 + uint16_t control;
  39 + uint16_t addr[2];
  40 + uint8_t divider;
  41 + uint8_t times[2];
  42 + uint16_t test;
  43 +};
  44 +
  45 +static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
  46 +{
  47 + qemu_set_irq(s->irq, s->stat & s->mask);
  48 + if ((s->dma >> 15) & 1) /* RDMA_EN */
  49 + qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */
  50 + if ((s->dma >> 7) & 1) /* XDMA_EN */
  51 + qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */
  52 +}
  53 +
  54 +/* These are only stubs now. */
  55 +static void omap_i2c_event(i2c_slave *i2c, enum i2c_event event)
  56 +{
  57 + struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
  58 +
  59 + if ((~s->control >> 15) & 1) /* I2C_EN */
  60 + return;
  61 +
  62 + switch (event) {
  63 + case I2C_START_SEND:
  64 + case I2C_START_RECV:
  65 + s->stat |= 1 << 9; /* AAS */
  66 + break;
  67 + case I2C_FINISH:
  68 + s->stat |= 1 << 2; /* ARDY */
  69 + break;
  70 + case I2C_NACK:
  71 + s->stat |= 1 << 1; /* NACK */
  72 + break;
  73 + }
  74 +
  75 + omap_i2c_interrupts_update(s);
  76 +}
  77 +
  78 +static int omap_i2c_rx(i2c_slave *i2c)
  79 +{
  80 + struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
  81 + uint8_t ret = 0;
  82 +
  83 + if ((~s->control >> 15) & 1) /* I2C_EN */
  84 + return -1;
  85 +
  86 + if (s->txlen)
  87 + ret = s->fifo >> ((-- s->txlen) << 3) & 0xff;
  88 + else
  89 + s->stat |= 1 << 10; /* XUDF */
  90 + s->stat |= 1 << 4; /* XRDY */
  91 +
  92 + omap_i2c_interrupts_update(s);
  93 + return ret;
  94 +}
  95 +
  96 +static int omap_i2c_tx(i2c_slave *i2c, uint8_t data)
  97 +{
  98 + struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
  99 +
  100 + if ((~s->control >> 15) & 1) /* I2C_EN */
  101 + return 1;
  102 +
  103 + if (s->rxlen < 4)
  104 + s->fifo |= data << ((s->rxlen ++) << 3);
  105 + else
  106 + s->stat |= 1 << 11; /* ROVR */
  107 + s->stat |= 1 << 3; /* RRDY */
  108 +
  109 + omap_i2c_interrupts_update(s);
  110 + return 1;
  111 +}
  112 +
  113 +static void omap_i2c_fifo_run(struct omap_i2c_s *s)
  114 +{
  115 + int ack = 1;
  116 +
  117 + if (!i2c_bus_busy(s->bus))
  118 + return;
  119 +
  120 + if ((s->control >> 2) & 1) { /* RM */
  121 + if ((s->control >> 1) & 1) { /* STP */
  122 + i2c_end_transfer(s->bus);
  123 + s->control &= ~(1 << 1); /* STP */
  124 + s->count_cur = s->count;
  125 + } else if ((s->control >> 9) & 1) { /* TRX */
  126 + while (ack && s->txlen)
  127 + ack = (i2c_send(s->bus,
  128 + (s->fifo >> ((-- s->txlen) << 3)) &
  129 + 0xff) >= 0);
  130 + s->stat |= 1 << 4; /* XRDY */
  131 + } else {
  132 + while (s->rxlen < 4)
  133 + s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
  134 + s->stat |= 1 << 3; /* RRDY */
  135 + }
  136 + } else {
  137 + if ((s->control >> 9) & 1) { /* TRX */
  138 + while (ack && s->count_cur && s->txlen) {
  139 + ack = (i2c_send(s->bus,
  140 + (s->fifo >> ((-- s->txlen) << 3)) &
  141 + 0xff) >= 0);
  142 + s->count_cur --;
  143 + }
  144 + if (ack && s->count_cur)
  145 + s->stat |= 1 << 4; /* XRDY */
  146 + if (!s->count_cur) {
  147 + s->stat |= 1 << 2; /* ARDY */
  148 + s->control &= ~(1 << 10); /* MST */
  149 + }
  150 + } else {
  151 + while (s->count_cur && s->rxlen < 4) {
  152 + s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
  153 + s->count_cur --;
  154 + }
  155 + if (s->rxlen)
  156 + s->stat |= 1 << 3; /* RRDY */
  157 + }
  158 + if (!s->count_cur) {
  159 + if ((s->control >> 1) & 1) { /* STP */
  160 + i2c_end_transfer(s->bus);
  161 + s->control &= ~(1 << 1); /* STP */
  162 + s->count_cur = s->count;
  163 + } else {
  164 + s->stat |= 1 << 2; /* ARDY */
  165 + s->control &= ~(1 << 10); /* MST */
  166 + }
  167 + }
  168 + }
  169 +
  170 + s->stat |= (!ack) << 1; /* NACK */
  171 + if (!ack)
  172 + s->control &= ~(1 << 1); /* STP */
  173 +}
  174 +
  175 +void omap_i2c_reset(struct omap_i2c_s *s)
  176 +{
  177 + s->mask = 0;
  178 + s->stat = 0;
  179 + s->dma = 0;
  180 + s->count = 0;
  181 + s->count_cur = 0;
  182 + s->fifo = 0;
  183 + s->rxlen = 0;
  184 + s->txlen = 0;
  185 + s->control = 0;
  186 + s->addr[0] = 0;
  187 + s->addr[1] = 0;
  188 + s->divider = 0;
  189 + s->times[0] = 0;
  190 + s->times[1] = 0;
  191 + s->test = 0;
  192 +}
  193 +
  194 +static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
  195 +{
  196 + struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
  197 + int offset = addr - s->base;
  198 + uint16_t ret;
  199 +
  200 + switch (offset) {
  201 + case 0x00: /* I2C_REV */
  202 + /* TODO: set a value greater or equal to real hardware */
  203 + return 0x11; /* REV */
  204 +
  205 + case 0x04: /* I2C_IE */
  206 + return s->mask;
  207 +
  208 + case 0x08: /* I2C_STAT */
  209 + return s->stat | (i2c_bus_busy(s->bus) << 12);
  210 +
  211 + case 0x0c: /* I2C_IV */
  212 + ret = ffs(s->stat & s->mask);
  213 + if (ret)
  214 + s->stat ^= 1 << (ret - 1);
  215 + omap_i2c_interrupts_update(s);
  216 + return ret;
  217 +
  218 + case 0x14: /* I2C_BUF */
  219 + return s->dma;
  220 +
  221 + case 0x18: /* I2C_CNT */
  222 + return s->count_cur; /* DCOUNT */
  223 +
  224 + case 0x1c: /* I2C_DATA */
  225 + ret = 0;
  226 + if (s->control & (1 << 14)) { /* BE */
  227 + ret |= ((s->fifo >> 0) & 0xff) << 8;
  228 + ret |= ((s->fifo >> 8) & 0xff) << 0;
  229 + } else {
  230 + ret |= ((s->fifo >> 8) & 0xff) << 8;
  231 + ret |= ((s->fifo >> 0) & 0xff) << 0;
  232 + }
  233 + if (s->rxlen == 1) {
  234 + s->stat |= 1 << 15; /* SBD */
  235 + s->rxlen = 0;
  236 + } else if (s->rxlen > 1) {
  237 + if (s->rxlen > 2)
  238 + s->fifo >>= 16;
  239 + s->rxlen -= 2;
  240 + } else
  241 + /* XXX: remote access (qualifier) error - what's that? */;
  242 + if (!s->rxlen) {
  243 + s->stat |= ~(1 << 3); /* RRDY */
  244 + if (((s->control >> 10) & 1) && /* MST */
  245 + ((~s->control >> 9) & 1)) { /* TRX */
  246 + s->stat |= 1 << 2; /* ARDY */
  247 + s->control &= ~(1 << 10); /* MST */
  248 + }
  249 + }
  250 + s->stat &= ~(1 << 11); /* ROVR */
  251 + omap_i2c_fifo_run(s);
  252 + omap_i2c_interrupts_update(s);
  253 + return ret;
  254 +
  255 + case 0x24: /* I2C_CON */
  256 + return s->control;
  257 +
  258 + case 0x28: /* I2C_OA */
  259 + return s->addr[0];
  260 +
  261 + case 0x2c: /* I2C_SA */
  262 + return s->addr[1];
  263 +
  264 + case 0x30: /* I2C_PSC */
  265 + return s->divider;
  266 +
  267 + case 0x34: /* I2C_SCLL */
  268 + return s->times[0];
  269 +
  270 + case 0x38: /* I2C_SCLH */
  271 + return s->times[1];
  272 +
  273 + case 0x3c: /* I2C_SYSTEST */
  274 + if (s->test & (1 << 15)) { /* ST_EN */
  275 + s->test ^= 0xa;
  276 + return s->test;
  277 + } else
  278 + return s->test & ~0x300f;
  279 + }
  280 +
  281 + OMAP_BAD_REG(addr);
  282 + return 0;
  283 +}
  284 +
  285 +static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
  286 + uint32_t value)
  287 +{
  288 + struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
  289 + int offset = addr - s->base;
  290 + int nack;
  291 +
  292 + switch (offset) {
  293 + case 0x00: /* I2C_REV */
  294 + case 0x08: /* I2C_STAT */
  295 + case 0x0c: /* I2C_IV */
  296 + OMAP_BAD_REG(addr);
  297 + return;
  298 +
  299 + case 0x04: /* I2C_IE */
  300 + s->mask = value & 0x1f;
  301 + break;
  302 +
  303 + case 0x14: /* I2C_BUF */
  304 + s->dma = value & 0x8080;
  305 + if (value & (1 << 15)) /* RDMA_EN */
  306 + s->mask &= ~(1 << 3); /* RRDY_IE */
  307 + if (value & (1 << 7)) /* XDMA_EN */
  308 + s->mask &= ~(1 << 4); /* XRDY_IE */
  309 + break;
  310 +
  311 + case 0x18: /* I2C_CNT */
  312 + s->count = value; /* DCOUNT */
  313 + break;
  314 +
  315 + case 0x1c: /* I2C_DATA */
  316 + if (s->txlen > 2) {
  317 + /* XXX: remote access (qualifier) error - what's that? */
  318 + break;
  319 + }
  320 + s->fifo <<= 16;
  321 + s->txlen += 2;
  322 + if (s->control & (1 << 14)) { /* BE */
  323 + s->fifo |= ((value >> 8) & 0xff) << 8;
  324 + s->fifo |= ((value >> 0) & 0xff) << 0;
  325 + } else {
  326 + s->fifo |= ((value >> 0) & 0xff) << 8;
  327 + s->fifo |= ((value >> 8) & 0xff) << 0;
  328 + }
  329 + s->stat &= ~(1 << 10); /* XUDF */
  330 + if (s->txlen > 2)
  331 + s->stat &= ~(1 << 4); /* XRDY */
  332 + omap_i2c_fifo_run(s);
  333 + omap_i2c_interrupts_update(s);
  334 + break;
  335 +
  336 + case 0x24: /* I2C_CON */
  337 + s->control = value & 0xcf07;
  338 + if (~value & (1 << 15)) { /* I2C_EN */
  339 + omap_i2c_reset(s);
  340 + break;
  341 + }
  342 + if (~value & (1 << 10)) { /* MST */
  343 + printf("%s: I^2C slave mode not supported\n", __FUNCTION__);
  344 + break;
  345 + }
  346 + if (value & (1 << 9)) { /* XA */
  347 + printf("%s: 10-bit addressing mode not supported\n", __FUNCTION__);
  348 + break;
  349 + }
  350 + if (value & (1 << 0)) { /* STT */
  351 + nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */
  352 + (~value >> 9) & 1); /* TRX */
  353 + s->stat |= nack << 1; /* NACK */
  354 + s->control &= ~(1 << 0); /* STT */
  355 + if (nack)
  356 + s->control &= ~(1 << 1); /* STP */
  357 + else
  358 + omap_i2c_fifo_run(s);
  359 + omap_i2c_interrupts_update(s);
  360 + }
  361 + break;
  362 +
  363 + case 0x28: /* I2C_OA */
  364 + s->addr[0] = value & 0x3ff;
  365 + i2c_set_slave_address(&s->slave, value & 0x7f);
  366 + break;
  367 +
  368 + case 0x2c: /* I2C_SA */
  369 + s->addr[1] = value & 0x3ff;
  370 + break;
  371 +
  372 + case 0x30: /* I2C_PSC */
  373 + s->divider = value;
  374 + break;
  375 +
  376 + case 0x34: /* I2C_SCLL */
  377 + s->times[0] = value;
  378 + break;
  379 +
  380 + case 0x38: /* I2C_SCLH */
  381 + s->times[1] = value;
  382 + break;
  383 +
  384 + case 0x3c: /* I2C_SYSTEST */
  385 + s->test = value & 0xf00f;
  386 + if (value & (1 << 15)) /* ST_EN */
  387 + printf("%s: System Test not supported\n", __FUNCTION__);
  388 + break;
  389 +
  390 + default:
  391 + OMAP_BAD_REG(addr);
  392 + return;
  393 + }
  394 +}
  395 +
  396 +static CPUReadMemoryFunc *omap_i2c_readfn[] = {
  397 + omap_badwidth_read16,
  398 + omap_i2c_read,
  399 + omap_badwidth_read16,
  400 +};
  401 +
  402 +static CPUWriteMemoryFunc *omap_i2c_writefn[] = {
  403 + omap_badwidth_write16,
  404 + omap_i2c_write,
  405 + omap_i2c_write, /* TODO: Only the last fifo write can be 8 bit. */
  406 +};
  407 +
  408 +struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
  409 + qemu_irq irq, qemu_irq *dma, omap_clk clk)
  410 +{
  411 + int iomemtype;
  412 + struct omap_i2c_s *s = (struct omap_i2c_s *)
  413 + qemu_mallocz(sizeof(struct omap_i2c_s));
  414 +
  415 + s->base = base;
  416 + s->irq = irq;
  417 + s->drq[0] = dma[0];
  418 + s->drq[1] = dma[1];
  419 + s->slave.event = omap_i2c_event;
  420 + s->slave.recv = omap_i2c_rx;
  421 + s->slave.send = omap_i2c_tx;
  422 + s->bus = i2c_init_bus();
  423 + omap_i2c_reset(s);
  424 +
  425 + iomemtype = cpu_register_io_memory(0, omap_i2c_readfn,
  426 + omap_i2c_writefn, s);
  427 + cpu_register_physical_memory(s->base, 0x800, iomemtype);
  428 +
  429 + return s;
  430 +}
  431 +
  432 +i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
  433 +{
  434 + return s->bus;
  435 +}
qemu-doc.texi
@@ -83,6 +83,7 @@ For system emulation, the following hardware targets are supported: @@ -83,6 +83,7 @@ For system emulation, the following hardware targets are supported:
83 @item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor) 83 @item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor)
84 @item Freescale MCF5208EVB (ColdFire V2). 84 @item Freescale MCF5208EVB (ColdFire V2).
85 @item Arnewsh MCF5206 evaluation board (ColdFire V2). 85 @item Arnewsh MCF5206 evaluation board (ColdFire V2).
  86 +@item Palm Tungsten|E PDA (OMAP310 processor)
86 @end itemize 87 @end itemize
87 88
88 For user emulation, x86, PowerPC, ARM, MIPS, Sparc32/64 and ColdFire(m68k) CPUs are supported. 89 For user emulation, x86, PowerPC, ARM, MIPS, Sparc32/64 and ColdFire(m68k) CPUs are supported.
@@ -2208,6 +2209,29 @@ Three on-chip UARTs @@ -2208,6 +2209,29 @@ Three on-chip UARTs
2208 WM8750 audio CODEC on I@math{^2}C and I@math{^2}S busses 2209 WM8750 audio CODEC on I@math{^2}C and I@math{^2}S busses
2209 @end itemize 2210 @end itemize
2210 2211
  2212 +The Palm Tungsten|E PDA (codename "Cheetah") emulation includes the
  2213 +following elements:
  2214 +
  2215 +@itemize @minus
  2216 +@item
  2217 +Texas Instruments OMAP310 System-on-chip (ARM 925T core)
  2218 +@item
  2219 +ROM and RAM memories (ROM firmware image can be loaded with -option-rom)
  2220 +@item
  2221 +On-chip LCD controller
  2222 +@item
  2223 +On-chip Real Time Clock
  2224 +@item
  2225 +TI TSC2102i touchscreen controller / analog-digital converter / Audio
  2226 +CODEC, connected through MicroWire and I@math{^2}S busses
  2227 +@item
  2228 +GPIO-connected matrix keypad
  2229 +@item
  2230 +Secure Digital card connected to OMAP MMC/SD host
  2231 +@item
  2232 +Three on-chip UARTs
  2233 +@end itemize
  2234 +
2211 A Linux 2.6 test image is available on the QEMU web site. More 2235 A Linux 2.6 test image is available on the QEMU web site. More
2212 information is available in the QEMU mailing-list archive. 2236 information is available in the QEMU mailing-list archive.
2213 2237