symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/pxa2xx_pic.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * Intel XScale PXA Programmable Interrupt Controller.
       
     3  *
       
     4  * Copyright (c) 2006 Openedhand Ltd.
       
     5  * Copyright (c) 2006 Thorsten Zitterell
       
     6  * Written by Andrzej Zaborowski <balrog@zabor.org>
       
     7  *
       
     8  * This code is licenced under the GPL.
       
     9  */
       
    10 
       
    11 #include "hw.h"
       
    12 #include "pxa.h"
       
    13 
       
    14 #define ICIP	0x00	/* Interrupt Controller IRQ Pending register */
       
    15 #define ICMR	0x04	/* Interrupt Controller Mask register */
       
    16 #define ICLR	0x08	/* Interrupt Controller Level register */
       
    17 #define ICFP	0x0c	/* Interrupt Controller FIQ Pending register */
       
    18 #define ICPR	0x10	/* Interrupt Controller Pending register */
       
    19 #define ICCR	0x14	/* Interrupt Controller Control register */
       
    20 #define ICHP	0x18	/* Interrupt Controller Highest Priority register */
       
    21 #define IPR0	0x1c	/* Interrupt Controller Priority register 0 */
       
    22 #define IPR31	0x98	/* Interrupt Controller Priority register 31 */
       
    23 #define ICIP2	0x9c	/* Interrupt Controller IRQ Pending register 2 */
       
    24 #define ICMR2	0xa0	/* Interrupt Controller Mask register 2 */
       
    25 #define ICLR2	0xa4	/* Interrupt Controller Level register 2 */
       
    26 #define ICFP2	0xa8	/* Interrupt Controller FIQ Pending register 2 */
       
    27 #define ICPR2	0xac	/* Interrupt Controller Pending register 2 */
       
    28 #define IPR32	0xb0	/* Interrupt Controller Priority register 32 */
       
    29 #define IPR39	0xcc	/* Interrupt Controller Priority register 39 */
       
    30 
       
    31 #define PXA2XX_PIC_SRCS	40
       
    32 
       
    33 struct pxa2xx_pic_state_s {
       
    34     CPUState *cpu_env;
       
    35     uint32_t int_enabled[2];
       
    36     uint32_t int_pending[2];
       
    37     uint32_t is_fiq[2];
       
    38     uint32_t int_idle;
       
    39     uint32_t priority[PXA2XX_PIC_SRCS];
       
    40 };
       
    41 
       
    42 static void pxa2xx_pic_update(void *opaque)
       
    43 {
       
    44     uint32_t mask[2];
       
    45     struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
       
    46 
       
    47     if (s->cpu_env->halted) {
       
    48         mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle);
       
    49         mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle);
       
    50         if (mask[0] || mask[1])
       
    51             cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB);
       
    52     }
       
    53 
       
    54     mask[0] = s->int_pending[0] & s->int_enabled[0];
       
    55     mask[1] = s->int_pending[1] & s->int_enabled[1];
       
    56 
       
    57     if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1]))
       
    58         cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
       
    59     else
       
    60         cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
       
    61 
       
    62     if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1]))
       
    63         cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
       
    64     else
       
    65         cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
       
    66 }
       
    67 
       
    68 /* Note: Here level means state of the signal on a pin, not
       
    69  * IRQ/FIQ distinction as in PXA Developer Manual.  */
       
    70 static void pxa2xx_pic_set_irq(void *opaque, int irq, int level)
       
    71 {
       
    72     struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
       
    73     int int_set = (irq >= 32);
       
    74     irq &= 31;
       
    75 
       
    76     if (level)
       
    77         s->int_pending[int_set] |= 1 << irq;
       
    78     else
       
    79         s->int_pending[int_set] &= ~(1 << irq);
       
    80 
       
    81     pxa2xx_pic_update(opaque);
       
    82 }
       
    83 
       
    84 static inline uint32_t pxa2xx_pic_highest(struct pxa2xx_pic_state_s *s) {
       
    85     int i, int_set, irq;
       
    86     uint32_t bit, mask[2];
       
    87     uint32_t ichp = 0x003f003f;	/* Both IDs invalid */
       
    88 
       
    89     mask[0] = s->int_pending[0] & s->int_enabled[0];
       
    90     mask[1] = s->int_pending[1] & s->int_enabled[1];
       
    91 
       
    92     for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) {
       
    93         irq = s->priority[i] & 0x3f;
       
    94         if ((s->priority[i] & (1 << 31)) && irq < PXA2XX_PIC_SRCS) {
       
    95             /* Source peripheral ID is valid.  */
       
    96             bit = 1 << (irq & 31);
       
    97             int_set = (irq >= 32);
       
    98 
       
    99             if (mask[int_set] & bit & s->is_fiq[int_set]) {
       
   100                 /* FIQ asserted */
       
   101                 ichp &= 0xffff0000;
       
   102                 ichp |= (1 << 15) | irq;
       
   103             }
       
   104 
       
   105             if (mask[int_set] & bit & ~s->is_fiq[int_set]) {
       
   106                 /* IRQ asserted */
       
   107                 ichp &= 0x0000ffff;
       
   108                 ichp |= (1 << 31) | (irq << 16);
       
   109             }
       
   110         }
       
   111     }
       
   112 
       
   113     return ichp;
       
   114 }
       
   115 
       
   116 static uint32_t pxa2xx_pic_mem_read(void *opaque, target_phys_addr_t offset)
       
   117 {
       
   118     struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
       
   119 
       
   120     switch (offset) {
       
   121     case ICIP:	/* IRQ Pending register */
       
   122         return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0];
       
   123     case ICIP2:	/* IRQ Pending register 2 */
       
   124         return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1];
       
   125     case ICMR:	/* Mask register */
       
   126         return s->int_enabled[0];
       
   127     case ICMR2:	/* Mask register 2 */
       
   128         return s->int_enabled[1];
       
   129     case ICLR:	/* Level register */
       
   130         return s->is_fiq[0];
       
   131     case ICLR2:	/* Level register 2 */
       
   132         return s->is_fiq[1];
       
   133     case ICCR:	/* Idle mask */
       
   134         return (s->int_idle == 0);
       
   135     case ICFP:	/* FIQ Pending register */
       
   136         return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0];
       
   137     case ICFP2:	/* FIQ Pending register 2 */
       
   138         return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1];
       
   139     case ICPR:	/* Pending register */
       
   140         return s->int_pending[0];
       
   141     case ICPR2:	/* Pending register 2 */
       
   142         return s->int_pending[1];
       
   143     case IPR0  ... IPR31:
       
   144         return s->priority[0  + ((offset - IPR0 ) >> 2)];
       
   145     case IPR32 ... IPR39:
       
   146         return s->priority[32 + ((offset - IPR32) >> 2)];
       
   147     case ICHP:	/* Highest Priority register */
       
   148         return pxa2xx_pic_highest(s);
       
   149     default:
       
   150         printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
       
   151         return 0;
       
   152     }
       
   153 }
       
   154 
       
   155 static void pxa2xx_pic_mem_write(void *opaque, target_phys_addr_t offset,
       
   156                 uint32_t value)
       
   157 {
       
   158     struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
       
   159 
       
   160     switch (offset) {
       
   161     case ICMR:	/* Mask register */
       
   162         s->int_enabled[0] = value;
       
   163         break;
       
   164     case ICMR2:	/* Mask register 2 */
       
   165         s->int_enabled[1] = value;
       
   166         break;
       
   167     case ICLR:	/* Level register */
       
   168         s->is_fiq[0] = value;
       
   169         break;
       
   170     case ICLR2:	/* Level register 2 */
       
   171         s->is_fiq[1] = value;
       
   172         break;
       
   173     case ICCR:	/* Idle mask */
       
   174         s->int_idle = (value & 1) ? 0 : ~0;
       
   175         break;
       
   176     case IPR0  ... IPR31:
       
   177         s->priority[0  + ((offset - IPR0 ) >> 2)] = value & 0x8000003f;
       
   178         break;
       
   179     case IPR32 ... IPR39:
       
   180         s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f;
       
   181         break;
       
   182     default:
       
   183         printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
       
   184         return;
       
   185     }
       
   186     pxa2xx_pic_update(opaque);
       
   187 }
       
   188 
       
   189 /* Interrupt Controller Coprocessor Space Register Mapping */
       
   190 static const int pxa2xx_cp_reg_map[0x10] = {
       
   191     [0x0 ... 0xf] = -1,
       
   192     [0x0] = ICIP,
       
   193     [0x1] = ICMR,
       
   194     [0x2] = ICLR,
       
   195     [0x3] = ICFP,
       
   196     [0x4] = ICPR,
       
   197     [0x5] = ICHP,
       
   198     [0x6] = ICIP2,
       
   199     [0x7] = ICMR2,
       
   200     [0x8] = ICLR2,
       
   201     [0x9] = ICFP2,
       
   202     [0xa] = ICPR2,
       
   203 };
       
   204 
       
   205 static uint32_t pxa2xx_pic_cp_read(void *opaque, int op2, int reg, int crm)
       
   206 {
       
   207     target_phys_addr_t offset;
       
   208 
       
   209     if (pxa2xx_cp_reg_map[reg] == -1) {
       
   210         printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
       
   211         return 0;
       
   212     }
       
   213 
       
   214     offset = pxa2xx_cp_reg_map[reg];
       
   215     return pxa2xx_pic_mem_read(opaque, offset);
       
   216 }
       
   217 
       
   218 static void pxa2xx_pic_cp_write(void *opaque, int op2, int reg, int crm,
       
   219                 uint32_t value)
       
   220 {
       
   221     target_phys_addr_t offset;
       
   222 
       
   223     if (pxa2xx_cp_reg_map[reg] == -1) {
       
   224         printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
       
   225         return;
       
   226     }
       
   227 
       
   228     offset = pxa2xx_cp_reg_map[reg];
       
   229     pxa2xx_pic_mem_write(opaque, offset, value);
       
   230 }
       
   231 
       
   232 static CPUReadMemoryFunc *pxa2xx_pic_readfn[] = {
       
   233     pxa2xx_pic_mem_read,
       
   234     pxa2xx_pic_mem_read,
       
   235     pxa2xx_pic_mem_read,
       
   236 };
       
   237 
       
   238 static CPUWriteMemoryFunc *pxa2xx_pic_writefn[] = {
       
   239     pxa2xx_pic_mem_write,
       
   240     pxa2xx_pic_mem_write,
       
   241     pxa2xx_pic_mem_write,
       
   242 };
       
   243 
       
   244 static void pxa2xx_pic_save(QEMUFile *f, void *opaque)
       
   245 {
       
   246     struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
       
   247     int i;
       
   248 
       
   249     for (i = 0; i < 2; i ++)
       
   250         qemu_put_be32s(f, &s->int_enabled[i]);
       
   251     for (i = 0; i < 2; i ++)
       
   252         qemu_put_be32s(f, &s->int_pending[i]);
       
   253     for (i = 0; i < 2; i ++)
       
   254         qemu_put_be32s(f, &s->is_fiq[i]);
       
   255     qemu_put_be32s(f, &s->int_idle);
       
   256     for (i = 0; i < PXA2XX_PIC_SRCS; i ++)
       
   257         qemu_put_be32s(f, &s->priority[i]);
       
   258 }
       
   259 
       
   260 static int pxa2xx_pic_load(QEMUFile *f, void *opaque, int version_id)
       
   261 {
       
   262     struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
       
   263     int i;
       
   264 
       
   265     for (i = 0; i < 2; i ++)
       
   266         qemu_get_be32s(f, &s->int_enabled[i]);
       
   267     for (i = 0; i < 2; i ++)
       
   268         qemu_get_be32s(f, &s->int_pending[i]);
       
   269     for (i = 0; i < 2; i ++)
       
   270         qemu_get_be32s(f, &s->is_fiq[i]);
       
   271     qemu_get_be32s(f, &s->int_idle);
       
   272     for (i = 0; i < PXA2XX_PIC_SRCS; i ++)
       
   273         qemu_get_be32s(f, &s->priority[i]);
       
   274 
       
   275     pxa2xx_pic_update(opaque);
       
   276     return 0;
       
   277 }
       
   278 
       
   279 qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env)
       
   280 {
       
   281     struct pxa2xx_pic_state_s *s;
       
   282     int iomemtype;
       
   283     qemu_irq *qi;
       
   284 
       
   285     s = (struct pxa2xx_pic_state_s *)
       
   286             qemu_mallocz(sizeof(struct pxa2xx_pic_state_s));
       
   287     if (!s)
       
   288         return NULL;
       
   289 
       
   290     s->cpu_env = env;
       
   291 
       
   292     s->int_pending[0] = 0;
       
   293     s->int_pending[1] = 0;
       
   294     s->int_enabled[0] = 0;
       
   295     s->int_enabled[1] = 0;
       
   296     s->is_fiq[0] = 0;
       
   297     s->is_fiq[1] = 0;
       
   298 
       
   299     qi = qemu_allocate_irqs(pxa2xx_pic_set_irq, s, PXA2XX_PIC_SRCS);
       
   300 
       
   301     /* Enable IC memory-mapped registers access.  */
       
   302     iomemtype = cpu_register_io_memory(0, pxa2xx_pic_readfn,
       
   303                     pxa2xx_pic_writefn, s);
       
   304     cpu_register_physical_memory(base, 0x00100000, iomemtype);
       
   305 
       
   306     /* Enable IC coprocessor access.  */
       
   307     cpu_arm_set_cp_io(env, 6, pxa2xx_pic_cp_read, pxa2xx_pic_cp_write, s);
       
   308 
       
   309     register_savevm("pxa2xx_pic", 0, 0, pxa2xx_pic_save, pxa2xx_pic_load, s);
       
   310 
       
   311     return qi;
       
   312 }