Commit fe71e81aba0f0cc10cd807a1b3f7a2978db255ce

Authored by balrog
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 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 3066 /* General chip reset */
2791 3067 static void omap_mpu_reset(void *opaque)
2792 3068 {
... ... @@ -2814,6 +3090,7 @@ static void omap_mpu_reset(void *opaque)
2814 3090 omap_uart_reset(mpu->uart2);
2815 3091 omap_uart_reset(mpu->uart3);
2816 3092 omap_mmc_reset(mpu->mmc);
  3093 + omap_mpuio_reset(mpu->mpuio);
2817 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 3098 {
2822 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 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 3117  
2840 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 3122 /* Clocks */
2843 3123 omap_clk_init(s);
2844 3124  
... ... @@ -2922,8 +3202,11 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
2922 3202 s->mmc = omap_mmc_init(0xfffb7800, s->irq[1][OMAP_INT_OQN],
2923 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 3209 qemu_register_reset(omap_mpu_reset, s);
2926   - s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0];
2927 3210  
2928 3211 return s;
2929 3212 }
... ...
hw/omap.h
... ... @@ -450,6 +450,14 @@ struct omap_uart_s;
450 450 struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
451 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 461 /* omap_lcdc.c */
454 462 struct omap_lcd_panel_s;
455 463 void omap_lcdc_reset(struct omap_lcd_panel_s *s);
... ... @@ -563,6 +571,8 @@ struct omap_mpu_state_s {
563 571 uint16_t dsp_idlect2;
564 572 uint16_t dsp_rstct2;
565 573 } clkm;
  574 +
  575 + struct omap_mpuio_s *mpuio;
566 576 } *omap310_mpu_init(unsigned long sdram_size,
567 577 DisplayState *ds, const char *core);
568 578  
... ...