Commit 026459262747819f90a4056292582661294342ce
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
Showing
6 changed files
with
500 additions
and
427 deletions
Changelog
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau) |
6 | 6 | - Several Sparc fixes (Aurelien Jarno, Blue Swirl, Robert Reif) |
7 | 7 | - MIPS 64-bit FPU support (Thiemo Seufer) |
8 | - - Xscale PDA emulation (Andrzei Zaborowski) | |
8 | + - Xscale PDA emulation (Andrzej Zaborowski) | |
9 | 9 | - ColdFire system emulation (Paul Brook) |
10 | 10 | - Improved SH4 support (Magnus Damm) |
11 | 11 | - MIPS64 support (Aurelien Jarno, Thiemo Seufer) |
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | - SPARC32PLUS execution support (Blue Swirl) |
17 | 17 | - MIPS mipssim pequdo machine (Thiemo Seufer) |
18 | 18 | - Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh) |
19 | + - OMAP310 MPU emulation plus Palm T|E machine (Andrzej Zaborowski) | |
19 | 20 | |
20 | 21 | version 0.9.0: |
21 | 22 | ... | ... |
Makefile.target
... | ... | @@ -519,7 +519,8 @@ VL_OBJS+= arm-semi.o |
519 | 519 | VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o |
520 | 520 | VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o |
521 | 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 | 524 | CPPFLAGS += -DHAS_AUDIO |
524 | 525 | endif |
525 | 526 | ifeq ($(TARGET_BASE_ARCH), sh4) | ... | ... |
hw/omap.c
... | ... | @@ -24,8 +24,11 @@ |
24 | 24 | /* Should signal the TCMI */ |
25 | 25 | uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr) |
26 | 26 | { |
27 | + uint8_t ret; | |
28 | + | |
27 | 29 | OMAP_8B_REG(addr); |
28 | - return 0; | |
30 | + cpu_physical_memory_read(addr, &ret, 1); | |
31 | + return ret; | |
29 | 32 | } |
30 | 33 | |
31 | 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 | 3469 | } |
3467 | 3470 | |
3468 | 3471 | static CPUReadMemoryFunc *omap_pwl_readfn[] = { |
3472 | + omap_pwl_read, | |
3469 | 3473 | omap_badwidth_read8, |
3470 | 3474 | omap_badwidth_read8, |
3471 | - omap_pwl_read, | |
3472 | 3475 | }; |
3473 | 3476 | |
3474 | 3477 | static CPUWriteMemoryFunc *omap_pwl_writefn[] = { |
3478 | + omap_pwl_write, | |
3475 | 3479 | omap_badwidth_write8, |
3476 | 3480 | omap_badwidth_write8, |
3477 | - omap_pwl_write, | |
3478 | 3481 | }; |
3479 | 3482 | |
3480 | 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 | 3574 | } |
3572 | 3575 | |
3573 | 3576 | static CPUReadMemoryFunc *omap_pwt_readfn[] = { |
3577 | + omap_pwt_read, | |
3574 | 3578 | omap_badwidth_read8, |
3575 | 3579 | omap_badwidth_read8, |
3576 | - omap_pwt_read, | |
3577 | 3580 | }; |
3578 | 3581 | |
3579 | 3582 | static CPUWriteMemoryFunc *omap_pwt_writefn[] = { |
3583 | + omap_pwt_write, | |
3580 | 3584 | omap_badwidth_write8, |
3581 | 3585 | omap_badwidth_write8, |
3582 | - omap_pwt_write, | |
3583 | 3586 | }; |
3584 | 3587 | |
3585 | 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 | 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 | 3609 | /* Real-time Clock module */ |
4022 | 3610 | struct omap_rtc_s { |
4023 | 3611 | target_phys_addr_t base; |
... | ... | @@ -4607,6 +4195,26 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, |
4607 | 4195 | |
4608 | 4196 | s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER], |
4609 | 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 | 4218 | qemu_register_reset(omap_mpu_reset, s); |
4611 | 4219 | |
4612 | 4220 | return s; | ... | ... |
hw/omap.h
... | ... | @@ -475,11 +475,6 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, |
475 | 475 | void omap_uwire_attach(struct omap_uwire_s *s, |
476 | 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 | 478 | struct omap_rtc_s; |
484 | 479 | struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, |
485 | 480 | qemu_irq *irq, omap_clk clk); |
... | ... | @@ -498,6 +493,13 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, |
498 | 493 | void omap_mmc_reset(struct omap_mmc_s *s); |
499 | 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 | 503 | # define cpu_is_omap310(cpu) (cpu->mpu_model == omap310) |
502 | 504 | # define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510) |
503 | 505 | # define cpu_is_omap15xx(cpu) \ |
... | ... | @@ -561,6 +563,8 @@ struct omap_mpu_state_s { |
561 | 563 | |
562 | 564 | struct omap_i2c_s *i2c; |
563 | 565 | |
566 | + struct omap_rtc_s *rtc; | |
567 | + | |
564 | 568 | /* MPU private TIPB peripherals */ |
565 | 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 | 83 | @item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor) |
84 | 84 | @item Freescale MCF5208EVB (ColdFire V2). |
85 | 85 | @item Arnewsh MCF5206 evaluation board (ColdFire V2). |
86 | +@item Palm Tungsten|E PDA (OMAP310 processor) | |
86 | 87 | @end itemize |
87 | 88 | |
88 | 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 | 2209 | WM8750 audio CODEC on I@math{^2}C and I@math{^2}S busses |
2209 | 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 | 2235 | A Linux 2.6 test image is available on the QEMU web site. More |
2212 | 2236 | information is available in the QEMU mailing-list archive. |
2213 | 2237 | ... | ... |