Commit fe71e81aba0f0cc10cd807a1b3f7a2978db255ce
1 parent
eed152bb
Implement OMAP1 MPU I/O module.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3469 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
295 additions
and
2 deletions
hw/omap.c
@@ -2787,6 +2787,282 @@ static void omap_clkm_init(target_phys_addr_t mpu_base, | @@ -2787,6 +2787,282 @@ static void omap_clkm_init(target_phys_addr_t mpu_base, | ||
2787 | cpu_register_physical_memory(s->clkm.dsp_base, 0x1000, iomemtype[1]); | 2787 | cpu_register_physical_memory(s->clkm.dsp_base, 0x1000, iomemtype[1]); |
2788 | } | 2788 | } |
2789 | 2789 | ||
2790 | +/* MPU I/O */ | ||
2791 | +struct omap_mpuio_s { | ||
2792 | + target_phys_addr_t base; | ||
2793 | + qemu_irq irq; | ||
2794 | + qemu_irq kbd_irq; | ||
2795 | + qemu_irq *in; | ||
2796 | + qemu_irq handler[16]; | ||
2797 | + qemu_irq wakeup; | ||
2798 | + | ||
2799 | + uint16_t inputs; | ||
2800 | + uint16_t outputs; | ||
2801 | + uint16_t dir; | ||
2802 | + uint16_t edge; | ||
2803 | + uint16_t mask; | ||
2804 | + uint16_t ints; | ||
2805 | + | ||
2806 | + uint16_t debounce; | ||
2807 | + uint16_t latch; | ||
2808 | + uint8_t event; | ||
2809 | + | ||
2810 | + uint8_t buttons[5]; | ||
2811 | + uint8_t row_latch; | ||
2812 | + uint8_t cols; | ||
2813 | + int kbd_mask; | ||
2814 | + int clk; | ||
2815 | +}; | ||
2816 | + | ||
2817 | +static void omap_mpuio_set(void *opaque, int line, int level) | ||
2818 | +{ | ||
2819 | + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; | ||
2820 | + uint16_t prev = s->inputs; | ||
2821 | + | ||
2822 | + if (level) | ||
2823 | + s->inputs |= 1 << line; | ||
2824 | + else | ||
2825 | + s->inputs &= ~(1 << line); | ||
2826 | + | ||
2827 | + if (((1 << line) & s->dir & ~s->mask) && s->clk) { | ||
2828 | + if ((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) { | ||
2829 | + s->ints |= 1 << line; | ||
2830 | + qemu_irq_raise(s->irq); | ||
2831 | + /* TODO: wakeup */ | ||
2832 | + } | ||
2833 | + if ((s->event & (1 << 0)) && /* SET_GPIO_EVENT_MODE */ | ||
2834 | + (s->event >> 1) == line) /* PIN_SELECT */ | ||
2835 | + s->latch = s->inputs; | ||
2836 | + } | ||
2837 | +} | ||
2838 | + | ||
2839 | +static void omap_mpuio_kbd_update(struct omap_mpuio_s *s) | ||
2840 | +{ | ||
2841 | + int i; | ||
2842 | + uint8_t *row, rows = 0, cols = ~s->cols; | ||
2843 | + | ||
2844 | + for (row = s->buttons + 4, i = 1 << 5; i; row --, i >>= 1) | ||
2845 | + if (*row & cols) | ||
2846 | + s->row_latch |= i; | ||
2847 | + | ||
2848 | + if (rows && ~s->kbd_mask && s->clk) | ||
2849 | + qemu_irq_raise(s->kbd_irq); | ||
2850 | + s->row_latch = rows ^ 0x1f; | ||
2851 | +} | ||
2852 | + | ||
2853 | +static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr) | ||
2854 | +{ | ||
2855 | + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; | ||
2856 | + int offset = addr - s->base; | ||
2857 | + uint16_t ret; | ||
2858 | + | ||
2859 | + switch (offset) { | ||
2860 | + case 0x00: /* INPUT_LATCH */ | ||
2861 | + return s->inputs; | ||
2862 | + | ||
2863 | + case 0x04: /* OUTPUT_REG */ | ||
2864 | + return s->outputs; | ||
2865 | + | ||
2866 | + case 0x08: /* IO_CNTL */ | ||
2867 | + return s->dir; | ||
2868 | + | ||
2869 | + case 0x10: /* KBR_LATCH */ | ||
2870 | + return s->row_latch; | ||
2871 | + | ||
2872 | + case 0x14: /* KBC_REG */ | ||
2873 | + return s->cols; | ||
2874 | + | ||
2875 | + case 0x18: /* GPIO_EVENT_MODE_REG */ | ||
2876 | + return s->event; | ||
2877 | + | ||
2878 | + case 0x1c: /* GPIO_INT_EDGE_REG */ | ||
2879 | + return s->edge; | ||
2880 | + | ||
2881 | + case 0x20: /* KBD_INT */ | ||
2882 | + return (s->row_latch != 0x1f) && !s->kbd_mask; | ||
2883 | + | ||
2884 | + case 0x24: /* GPIO_INT */ | ||
2885 | + ret = s->ints; | ||
2886 | + s->ints &= ~s->mask; | ||
2887 | + return ret; | ||
2888 | + | ||
2889 | + case 0x28: /* KBD_MASKIT */ | ||
2890 | + return s->kbd_mask; | ||
2891 | + | ||
2892 | + case 0x2c: /* GPIO_MASKIT */ | ||
2893 | + return s->mask; | ||
2894 | + | ||
2895 | + case 0x30: /* GPIO_DEBOUNCING_REG */ | ||
2896 | + return s->debounce; | ||
2897 | + | ||
2898 | + case 0x34: /* GPIO_LATCH_REG */ | ||
2899 | + return s->latch; | ||
2900 | + } | ||
2901 | + | ||
2902 | + OMAP_BAD_REG(addr); | ||
2903 | + return 0; | ||
2904 | +} | ||
2905 | + | ||
2906 | +static void omap_mpuio_write(void *opaque, target_phys_addr_t addr, | ||
2907 | + uint32_t value) | ||
2908 | +{ | ||
2909 | + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; | ||
2910 | + int offset = addr - s->base; | ||
2911 | + uint16_t diff; | ||
2912 | + int ln; | ||
2913 | + | ||
2914 | + switch (offset) { | ||
2915 | + case 0x04: /* OUTPUT_REG */ | ||
2916 | + diff = s->outputs ^ (value & ~s->dir); | ||
2917 | + s->outputs = value; | ||
2918 | + value &= ~s->dir; | ||
2919 | + while ((ln = ffs(diff))) { | ||
2920 | + ln --; | ||
2921 | + if (s->handler[ln]) | ||
2922 | + qemu_set_irq(s->handler[ln], (value >> ln) & 1); | ||
2923 | + diff &= ~(1 << ln); | ||
2924 | + } | ||
2925 | + break; | ||
2926 | + | ||
2927 | + case 0x08: /* IO_CNTL */ | ||
2928 | + diff = s->outputs & (s->dir ^ value); | ||
2929 | + s->dir = value; | ||
2930 | + | ||
2931 | + value = s->outputs & ~s->dir; | ||
2932 | + while ((ln = ffs(diff))) { | ||
2933 | + ln --; | ||
2934 | + if (s->handler[ln]) | ||
2935 | + qemu_set_irq(s->handler[ln], (value >> ln) & 1); | ||
2936 | + diff &= ~(1 << ln); | ||
2937 | + } | ||
2938 | + break; | ||
2939 | + | ||
2940 | + case 0x14: /* KBC_REG */ | ||
2941 | + s->cols = value; | ||
2942 | + omap_mpuio_kbd_update(s); | ||
2943 | + break; | ||
2944 | + | ||
2945 | + case 0x18: /* GPIO_EVENT_MODE_REG */ | ||
2946 | + s->event = value & 0x1f; | ||
2947 | + break; | ||
2948 | + | ||
2949 | + case 0x1c: /* GPIO_INT_EDGE_REG */ | ||
2950 | + s->edge = value; | ||
2951 | + break; | ||
2952 | + | ||
2953 | + case 0x28: /* KBD_MASKIT */ | ||
2954 | + s->kbd_mask = value & 1; | ||
2955 | + omap_mpuio_kbd_update(s); | ||
2956 | + break; | ||
2957 | + | ||
2958 | + case 0x2c: /* GPIO_MASKIT */ | ||
2959 | + s->mask = value; | ||
2960 | + break; | ||
2961 | + | ||
2962 | + case 0x30: /* GPIO_DEBOUNCING_REG */ | ||
2963 | + s->debounce = value & 0x1ff; | ||
2964 | + break; | ||
2965 | + | ||
2966 | + case 0x00: /* INPUT_LATCH */ | ||
2967 | + case 0x10: /* KBR_LATCH */ | ||
2968 | + case 0x20: /* KBD_INT */ | ||
2969 | + case 0x24: /* GPIO_INT */ | ||
2970 | + case 0x34: /* GPIO_LATCH_REG */ | ||
2971 | + OMAP_RO_REG(addr); | ||
2972 | + return; | ||
2973 | + | ||
2974 | + default: | ||
2975 | + OMAP_BAD_REG(addr); | ||
2976 | + return; | ||
2977 | + } | ||
2978 | +} | ||
2979 | + | ||
2980 | +static CPUReadMemoryFunc *omap_mpuio_readfn[] = { | ||
2981 | + omap_badwidth_read16, | ||
2982 | + omap_mpuio_read, | ||
2983 | + omap_badwidth_read16, | ||
2984 | +}; | ||
2985 | + | ||
2986 | +static CPUWriteMemoryFunc *omap_mpuio_writefn[] = { | ||
2987 | + omap_badwidth_write16, | ||
2988 | + omap_mpuio_write, | ||
2989 | + omap_badwidth_write16, | ||
2990 | +}; | ||
2991 | + | ||
2992 | +void omap_mpuio_reset(struct omap_mpuio_s *s) | ||
2993 | +{ | ||
2994 | + s->inputs = 0; | ||
2995 | + s->outputs = 0; | ||
2996 | + s->dir = ~0; | ||
2997 | + s->event = 0; | ||
2998 | + s->edge = 0; | ||
2999 | + s->kbd_mask = 0; | ||
3000 | + s->mask = 0; | ||
3001 | + s->debounce = 0; | ||
3002 | + s->latch = 0; | ||
3003 | + s->ints = 0; | ||
3004 | + s->row_latch = 0x1f; | ||
3005 | +} | ||
3006 | + | ||
3007 | +static void omap_mpuio_onoff(void *opaque, int line, int on) | ||
3008 | +{ | ||
3009 | + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; | ||
3010 | + | ||
3011 | + s->clk = on; | ||
3012 | + if (on) | ||
3013 | + omap_mpuio_kbd_update(s); | ||
3014 | +} | ||
3015 | + | ||
3016 | +struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base, | ||
3017 | + qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup, | ||
3018 | + omap_clk clk) | ||
3019 | +{ | ||
3020 | + int iomemtype; | ||
3021 | + struct omap_mpuio_s *s = (struct omap_mpuio_s *) | ||
3022 | + qemu_mallocz(sizeof(struct omap_mpuio_s)); | ||
3023 | + | ||
3024 | + s->base = base; | ||
3025 | + s->irq = gpio_int; | ||
3026 | + s->kbd_irq = kbd_int; | ||
3027 | + s->wakeup = wakeup; | ||
3028 | + s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16); | ||
3029 | + omap_mpuio_reset(s); | ||
3030 | + | ||
3031 | + iomemtype = cpu_register_io_memory(0, omap_mpuio_readfn, | ||
3032 | + omap_mpuio_writefn, s); | ||
3033 | + cpu_register_physical_memory(s->base, 0x800, iomemtype); | ||
3034 | + | ||
3035 | + omap_clk_adduser(clk, qemu_allocate_irqs(omap_mpuio_onoff, s, 1)[0]); | ||
3036 | + | ||
3037 | + return s; | ||
3038 | +} | ||
3039 | + | ||
3040 | +qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s) | ||
3041 | +{ | ||
3042 | + return s->in; | ||
3043 | +} | ||
3044 | + | ||
3045 | +void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler) | ||
3046 | +{ | ||
3047 | + if (line >= 16 || line < 0) | ||
3048 | + cpu_abort(cpu_single_env, "%s: No GPIO line %i\n", __FUNCTION__, line); | ||
3049 | + s->handler[line] = handler; | ||
3050 | +} | ||
3051 | + | ||
3052 | +void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down) | ||
3053 | +{ | ||
3054 | + if (row >= 5 || row < 0) | ||
3055 | + cpu_abort(cpu_single_env, "%s: No key %i-%i\n", | ||
3056 | + __FUNCTION__, col, row); | ||
3057 | + | ||
3058 | + if (down) | ||
3059 | + s->buttons[row] = 1 << col; | ||
3060 | + else | ||
3061 | + s->buttons[row] = ~(1 << col); | ||
3062 | + | ||
3063 | + omap_mpuio_kbd_update(s); | ||
3064 | +} | ||
3065 | + | ||
2790 | /* General chip reset */ | 3066 | /* General chip reset */ |
2791 | static void omap_mpu_reset(void *opaque) | 3067 | static void omap_mpu_reset(void *opaque) |
2792 | { | 3068 | { |
@@ -2814,6 +3090,7 @@ static void omap_mpu_reset(void *opaque) | @@ -2814,6 +3090,7 @@ static void omap_mpu_reset(void *opaque) | ||
2814 | omap_uart_reset(mpu->uart2); | 3090 | omap_uart_reset(mpu->uart2); |
2815 | omap_uart_reset(mpu->uart3); | 3091 | omap_uart_reset(mpu->uart3); |
2816 | omap_mmc_reset(mpu->mmc); | 3092 | omap_mmc_reset(mpu->mmc); |
3093 | + omap_mpuio_reset(mpu->mpuio); | ||
2817 | cpu_reset(mpu->env); | 3094 | cpu_reset(mpu->env); |
2818 | } | 3095 | } |
2819 | 3096 | ||
@@ -2821,7 +3098,8 @@ static void omap_mpu_wakeup(void *opaque, int irq, int req) | @@ -2821,7 +3098,8 @@ static void omap_mpu_wakeup(void *opaque, int irq, int req) | ||
2821 | { | 3098 | { |
2822 | struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; | 3099 | struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; |
2823 | 3100 | ||
2824 | - cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB); | 3101 | + if (mpu->env->halted) |
3102 | + cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB); | ||
2825 | } | 3103 | } |
2826 | 3104 | ||
2827 | struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, | 3105 | struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, |
@@ -2839,6 +3117,8 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, | @@ -2839,6 +3117,8 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, | ||
2839 | 3117 | ||
2840 | cpu_arm_set_model(s->env, core ?: "ti925t"); | 3118 | cpu_arm_set_model(s->env, core ?: "ti925t"); |
2841 | 3119 | ||
3120 | + s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; | ||
3121 | + | ||
2842 | /* Clocks */ | 3122 | /* Clocks */ |
2843 | omap_clk_init(s); | 3123 | omap_clk_init(s); |
2844 | 3124 | ||
@@ -2922,8 +3202,11 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, | @@ -2922,8 +3202,11 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, | ||
2922 | s->mmc = omap_mmc_init(0xfffb7800, s->irq[1][OMAP_INT_OQN], | 3202 | s->mmc = omap_mmc_init(0xfffb7800, s->irq[1][OMAP_INT_OQN], |
2923 | &s->drq[OMAP_DMA_MMC_TX], omap_findclk(s, "mmc_ck")); | 3203 | &s->drq[OMAP_DMA_MMC_TX], omap_findclk(s, "mmc_ck")); |
2924 | 3204 | ||
3205 | + s->mpuio = omap_mpuio_init(0xfffb5000, | ||
3206 | + s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO], | ||
3207 | + s->wakeup, omap_findclk(s, "clk32-kHz")); | ||
3208 | + | ||
2925 | qemu_register_reset(omap_mpu_reset, s); | 3209 | qemu_register_reset(omap_mpu_reset, s); |
2926 | - s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; | ||
2927 | 3210 | ||
2928 | return s; | 3211 | return s; |
2929 | } | 3212 | } |
hw/omap.h
@@ -450,6 +450,14 @@ struct omap_uart_s; | @@ -450,6 +450,14 @@ struct omap_uart_s; | ||
450 | struct omap_uart_s *omap_uart_init(target_phys_addr_t base, | 450 | struct omap_uart_s *omap_uart_init(target_phys_addr_t base, |
451 | qemu_irq irq, omap_clk clk, CharDriverState *chr); | 451 | qemu_irq irq, omap_clk clk, CharDriverState *chr); |
452 | 452 | ||
453 | +struct omap_mpuio_s; | ||
454 | +struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base, | ||
455 | + qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup, | ||
456 | + omap_clk clk); | ||
457 | +qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s); | ||
458 | +void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler); | ||
459 | +void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down); | ||
460 | + | ||
453 | /* omap_lcdc.c */ | 461 | /* omap_lcdc.c */ |
454 | struct omap_lcd_panel_s; | 462 | struct omap_lcd_panel_s; |
455 | void omap_lcdc_reset(struct omap_lcd_panel_s *s); | 463 | void omap_lcdc_reset(struct omap_lcd_panel_s *s); |
@@ -563,6 +571,8 @@ struct omap_mpu_state_s { | @@ -563,6 +571,8 @@ struct omap_mpu_state_s { | ||
563 | uint16_t dsp_idlect2; | 571 | uint16_t dsp_idlect2; |
564 | uint16_t dsp_rstct2; | 572 | uint16_t dsp_rstct2; |
565 | } clkm; | 573 | } clkm; |
574 | + | ||
575 | + struct omap_mpuio_s *mpuio; | ||
566 | } *omap310_mpu_init(unsigned long sdram_size, | 576 | } *omap310_mpu_init(unsigned long sdram_size, |
567 | DisplayState *ds, const char *core); | 577 | DisplayState *ds, const char *core); |
568 | 578 |