18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * ARM Generic/Distributed Interrupt Controller 38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 2006-2007 CodeSourcery. 58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Written by Paul Brook 68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * This code is licenced under the GPL. 88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* This file contains implementation code for the RealView EB interrupt 118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project controller, MPCore distributed interrupt controller and ARMv7-M 128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project Nested Vectored Interrupt Controller. */ 138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project//#define DEBUG_GIC 158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_GIC 175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define DPRINTF(fmt, ...) \ 185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerdo { printf("arm_gic: " fmt , ## __VA_ARGS__); } while (0) 198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else 205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define DPRINTF(fmt, ...) do {} while(0) 218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC 248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic const uint8_t gic_id[] = 258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 }; 268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* The NVIC has 16 internal vectors. However these are not exposed 278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project through the normal GIC interface. */ 288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_BASE_IRQ 32 298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else 308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic const uint8_t gic_id[] = 318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; 328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_BASE_IRQ 0 338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define FROM_SYSBUSGIC(type, dev) \ 365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DO_UPCAST(type, gic, FROM_SYSBUS(gic_state, dev)) 375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct gic_irq_state 398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* ??? The documentation seems to imply the enable bits are global, even 418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for per-cpu interrupts. This seems strange. */ 428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project unsigned enabled:1; 438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project unsigned pending:NCPU; 448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project unsigned active:NCPU; 455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned level:NCPU; 468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project unsigned model:1; /* 0 = N:N, 1 = 1:N */ 478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project unsigned trigger:1; /* nonzero = edge triggered. */ 488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} gic_irq_state; 498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ALL_CPU_MASK ((1 << NCPU) - 1) 518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1 538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0 548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled 558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm) 568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm) 578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0) 588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm) 598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm) 608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0) 618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1 628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0 638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TEST_MODEL(irq) s->irq_state[irq].model 648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm) 658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm) 668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0) 678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1 688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0 698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger 708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_GET_PRIORITY(irq, cpu) \ 718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (((irq) < 32) ? s->priority1[irq][cpu] : s->priority2[(irq) - 32]) 728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC 738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TARGET(irq) 1 748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else 758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TARGET(irq) s->irq_target[irq] 768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct gic_state 798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SysBusDevice busdev; 818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_irq parent_irq[NCPU]; 828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int enabled; 838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cpu_enabled[NCPU]; 848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_irq_state irq_state[GIC_NIRQ]; 868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC 878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int irq_target[GIC_NIRQ]; 888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int priority1[32][NCPU]; 908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int priority2[GIC_NIRQ - 32]; 918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int last_active[GIC_NIRQ][NCPU]; 928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int priority_mask[NCPU]; 948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int running_irq[NCPU]; 958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int running_priority[NCPU]; 968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int current_pending[NCPU]; 978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int iomemtype; 998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} gic_state; 1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TODO: Many places that call this routine could be optimized. */ 1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Update interrupt status after enabled or pending bits have been changed. */ 1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_update(gic_state *s) 1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int best_irq; 1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int best_prio; 1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int irq; 1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int level; 1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cpu; 1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cm; 1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (cpu = 0; cpu < NCPU; cpu++) { 1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cm = 1 << cpu; 1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->current_pending[cpu] = 1023; 1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!s->enabled || !s->cpu_enabled[cpu]) { 1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_irq_lower(s->parent_irq[cpu]); 1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project best_prio = 0x100; 1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project best_irq = 1023; 1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (irq = 0; irq < GIC_NIRQ; irq++) { 1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq, cm)) { 1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { 1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project best_prio = GIC_GET_PRIORITY(irq, cpu); 1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project best_irq = irq; 1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project level = 0; 1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (best_prio <= s->priority_mask[cpu]) { 1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->current_pending[cpu] = best_irq; 1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (best_prio < s->running_priority[cpu]) { 1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Raised pending IRQ %d\n", best_irq); 1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project level = 1; 1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_set_irq(s->parent_irq[cpu], level); 1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void __attribute__((unused)) 1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectgic_set_pending_private(gic_state *s, int cpu, int irq) 1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cm = 1 << cpu; 1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (GIC_TEST_PENDING(irq, cm)) 1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Set %d pending cpu %d\n", irq, cpu); 1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_SET_PENDING(irq, cm); 1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_update(s); 1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Process a change in an external IRQ input. */ 1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_set_irq(void *opaque, int irq, int level) 1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_state *s = (gic_state *)opaque; 1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* The first external input line is internal interrupt 32. */ 1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq += 32; 1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (level == GIC_TEST_LEVEL(irq, ALL_CPU_MASK)) 1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (level) { 1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_SET_LEVEL(irq, ALL_CPU_MASK); 1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) { 1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq)); 1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_SET_PENDING(irq, GIC_TARGET(irq)); 1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_CLEAR_LEVEL(irq, ALL_CPU_MASK); 1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_update(s); 1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_set_running_irq(gic_state *s, int cpu, int irq) 1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->running_irq[cpu] = irq; 1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq == 1023) { 1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->running_priority[cpu] = 0x100; 1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu); 1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_update(s); 1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t gic_acknowledge_irq(gic_state *s, int cpu) 1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int new_irq; 1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cm = 1 << cpu; 1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project new_irq = s->current_pending[cpu]; 1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (new_irq == 1023 1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) { 1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("ACK no pending IRQ\n"); 1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 1023; 1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->last_active[new_irq][cpu] = s->running_irq[cpu]; 1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Clear pending flags for both level and edge triggered interrupts. 1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project Level triggered IRQs will be reasserted once they become inactive. */ 1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm); 2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_set_running_irq(s, cpu, new_irq); 2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("ACK %d\n", new_irq); 2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return new_irq; 2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_complete_irq(gic_state * s, int cpu, int irq) 2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int update = 0; 2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cm = 1 << cpu; 2098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("EOI %d\n", irq); 2108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (s->running_irq[cpu] == 1023) 2118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; /* No active IRQ. */ 2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq != 1023) { 2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Mark level triggered interrupts as pending if they are still 2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project raised. */ 2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq) 2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) { 2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Set %d pending mask %x\n", irq, cm); 2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_SET_PENDING(irq, cm); 2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project update = 1; 2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq != s->running_irq[cpu]) { 2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Complete an IRQ that is not currently running. */ 2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int tmp = s->running_irq[cpu]; 2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while (s->last_active[tmp][cpu] != 1023) { 2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (s->last_active[tmp][cpu] == irq) { 2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->last_active[tmp][cpu] = s->last_active[irq][cpu]; 2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project tmp = s->last_active[tmp][cpu]; 2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (update) { 2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_update(s); 2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Complete the current running IRQ. */ 2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]); 2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 241bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic uint32_t gic_dist_readb(void *opaque, hwaddr offset) 2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_state *s = (gic_state *)opaque; 2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t res; 2458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int irq; 2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i; 2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cpu; 2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cm; 2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int mask; 2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu = gic_get_current_cpu(); 2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cm = 1 << cpu; 2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (offset < 0x100) { 2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC 2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (offset == 0) 2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return s->enabled; 2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (offset == 4) 2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return ((GIC_NIRQ / 32) - 1) | ((NCPU - 1) << 5); 2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (offset < 0x08) 2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0x200) { 2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt Set/Clear Enable. */ 2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (offset < 0x180) 2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0x100) * 8; 2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else 2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0x180) * 8; 2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq += GIC_BASE_IRQ; 2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= GIC_NIRQ) 2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res = 0; 2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < 8; i++) { 2748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (GIC_TEST_ENABLED(irq + i)) { 2758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res |= (1 << i); 2768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0x300) { 2798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt Set/Clear Pending. */ 2808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (offset < 0x280) 2818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0x200) * 8; 2828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else 2838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0x280) * 8; 2848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq += GIC_BASE_IRQ; 2858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= GIC_NIRQ) 2868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 2878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res = 0; 2888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mask = (irq < 32) ? cm : ALL_CPU_MASK; 2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < 8; i++) { 2908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (GIC_TEST_PENDING(irq + i, mask)) { 2918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res |= (1 << i); 2928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0x400) { 2958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt Active. */ 2968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; 2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= GIC_NIRQ) 2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res = 0; 3008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mask = (irq < 32) ? cm : ALL_CPU_MASK; 3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < 8; i++) { 3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (GIC_TEST_ACTIVE(irq + i, mask)) { 3038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res |= (1 << i); 3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0x800) { 3078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt Priority. */ 3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0x400) + GIC_BASE_IRQ; 3098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= GIC_NIRQ) 3108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res = GIC_GET_PRIORITY(irq, cpu); 3128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC 3138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0xc00) { 3148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt CPU Target. */ 3158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0x800) + GIC_BASE_IRQ; 3168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= GIC_NIRQ) 3178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 3188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= 29 && irq <= 31) { 3198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res = cm; 3208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 3218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res = GIC_TARGET(irq); 3228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0xf00) { 3248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt Configuration. */ 3258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ; 3268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= GIC_NIRQ) 3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res = 0; 3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < 4; i++) { 3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (GIC_TEST_MODEL(irq + i)) 3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res |= (1 << (i * 2)); 3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (GIC_TEST_TRIGGER(irq + i)) 3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res |= (2 << (i * 2)); 3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 3368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0xfe0) { 3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else /* offset >= 0xfe0 */ { 3398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (offset & 3) { 3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res = 0; 3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project res = gic_id[(offset - 0xfe0) >> 2]; 3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return res; 3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectbad_reg: 3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hw_error("gic_dist_readb: Bad offset %x\n", (int)offset); 3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 3508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 351bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic uint32_t gic_dist_readw(void *opaque, hwaddr offset) 3528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t val; 3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val = gic_dist_readb(opaque, offset); 3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val |= gic_dist_readb(opaque, offset + 1) << 8; 3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return val; 3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 3588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 359bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic uint32_t gic_dist_readl(void *opaque, hwaddr offset) 3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t val; 3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC 3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_state *s = (gic_state *)opaque; 3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t addr; 3655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner addr = offset; 3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (addr < 0x100 || addr > 0xd00) 3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return nvic_readl(s, addr); 3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val = gic_dist_readw(opaque, offset); 3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val |= gic_dist_readw(opaque, offset + 2) << 16; 3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return val; 3728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 3738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 374bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic void gic_dist_writeb(void *opaque, hwaddr offset, 3758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t value) 3768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 3778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_state *s = (gic_state *)opaque; 3788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int irq; 3798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i; 3808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cpu; 3818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu = gic_get_current_cpu(); 3838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (offset < 0x100) { 3848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC 3858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 3868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else 3878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (offset == 0) { 3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->enabled = (value & 1); 3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis"); 3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 4) { 3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* ignored. */ 3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0x180) { 3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt Set Enable. */ 3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; 3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= GIC_NIRQ) 4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq < 16) 4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project value = 0xff; 4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < 8; i++) { 4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (value & (1 << i)) { 4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int mask = (irq < 32) ? (1 << cpu) : GIC_TARGET(irq); 4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!GIC_TEST_ENABLED(irq + i)) 4078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Enabled IRQ %d\n", irq + i); 4088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_SET_ENABLED(irq + i); 4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* If a raised level triggered IRQ enabled then mark 4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project is as pending. */ 4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (GIC_TEST_LEVEL(irq + i, mask) 4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project && !GIC_TEST_TRIGGER(irq + i)) { 4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Set %d pending mask %x\n", irq + i, mask); 4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_SET_PENDING(irq + i, mask); 4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0x200) { 4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt Clear Enable. */ 4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; 4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= GIC_NIRQ) 4228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq < 16) 4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project value = 0; 4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < 8; i++) { 4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (value & (1 << i)) { 4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (GIC_TEST_ENABLED(irq + i)) 4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Disabled IRQ %d\n", irq + i); 4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_CLEAR_ENABLED(irq + i); 4308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0x280) { 4338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt Set Pending. */ 4348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; 4358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= GIC_NIRQ) 4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 4378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq < 16) 4388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = 0; 4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < 8; i++) { 4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (value & (1 << i)) { 4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_SET_PENDING(irq + i, GIC_TARGET(irq)); 4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0x300) { 4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt Clear Pending. */ 4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; 4488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= GIC_NIRQ) 4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < 8; i++) { 4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* ??? This currently clears the pending bit for all CPUs, even 4528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for per-CPU interrupts. It's unclear whether this is the 4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project corect behavior. */ 4548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (value & (1 << i)) { 4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK); 4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0x400) { 4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt Active. */ 4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0x800) { 4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt Priority. */ 4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0x400) + GIC_BASE_IRQ; 4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= GIC_NIRQ) 4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 4668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq < 32) { 4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->priority1[irq][cpu] = value; 4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->priority2[irq - 32] = value; 4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC 4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0xc00) { 4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt CPU Target. */ 4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0x800) + GIC_BASE_IRQ; 4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= GIC_NIRQ) 4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq < 29) 4788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project value = 0; 4798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else if (irq < 32) 4808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project value = ALL_CPU_MASK; 4818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->irq_target[irq] = value & ALL_CPU_MASK; 4828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (offset < 0xf00) { 4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Interrupt Configuration. */ 4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 4858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq >= GIC_NIRQ) 4868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (irq < 32) 4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project value |= 0xaa; 4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < 4; i++) { 4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (value & (1 << (i * 2))) { 4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_SET_MODEL(irq + i); 4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_CLEAR_MODEL(irq + i); 4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (value & (2 << (i * 2))) { 4968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_SET_TRIGGER(irq + i); 4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 4988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_CLEAR_TRIGGER(irq + i); 4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 5028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 0xf00 is only handled for 32-bit writes. */ 5048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad_reg; 5058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_update(s); 5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectbad_reg: 5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hw_error("gic_dist_writeb: Bad offset %x\n", (int)offset); 5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 5118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 512bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic void gic_dist_writew(void *opaque, hwaddr offset, 5138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t value) 5148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 5158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_dist_writeb(opaque, offset, value & 0xff); 5168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_dist_writeb(opaque, offset + 1, value >> 8); 5178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 519bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic void gic_dist_writel(void *opaque, hwaddr offset, 5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t value) 5218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 5228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_state *s = (gic_state *)opaque; 5238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC 5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t addr; 5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner addr = offset; 5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) { 5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nvic_writel(s, addr, value); 5288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 5298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (offset == 0xf00) { 5328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cpu; 5338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int irq; 5348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int mask; 5358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu = gic_get_current_cpu(); 5378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq = value & 0x3ff; 5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch ((value >> 24) & 3) { 5398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0: 5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mask = (value >> 16) & ALL_CPU_MASK; 5418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 1: 5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mask = 1 << cpu; 5448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 2: 5468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mask = ALL_CPU_MASK ^ (1 << cpu); 5478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 5498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Bad Soft Int target filter\n"); 5508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mask = ALL_CPU_MASK; 5518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_SET_PENDING(irq, mask); 5548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_update(s); 5558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 5568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_dist_writew(opaque, offset, value & 0xffff); 5588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_dist_writew(opaque, offset + 2, value >> 16); 5598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 5608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic CPUReadMemoryFunc *gic_dist_readfn[] = { 5628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_dist_readb, 5638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_dist_readw, 5648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_dist_readl 5658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}; 5668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic CPUWriteMemoryFunc *gic_dist_writefn[] = { 5688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_dist_writeb, 5698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_dist_writew, 5708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_dist_writel 5718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}; 5728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC 5748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t gic_cpu_read(gic_state *s, int cpu, int offset) 5758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 5768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (offset) { 5778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x00: /* Control */ 5788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return s->cpu_enabled[cpu]; 5798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x04: /* Priority mask */ 5808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return s->priority_mask[cpu]; 5818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x08: /* Binary Point */ 5828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* ??? Not implemented. */ 5838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 5848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x0c: /* Acknowledge */ 5858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return gic_acknowledge_irq(s, cpu); 5868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x14: /* Runing Priority */ 5878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return s->running_priority[cpu]; 5888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x18: /* Highest Pending Interrupt */ 5898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return s->current_pending[cpu]; 5908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 5915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hw_error("gic_cpu_read: Bad offset %x\n", (int)offset); 5928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 5938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 5958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value) 5978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 5988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (offset) { 5998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x00: /* Control */ 6008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->cpu_enabled[cpu] = (value & 1); 6018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis"); 6028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x04: /* Priority mask */ 6048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->priority_mask[cpu] = (value & 0xff); 6058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x08: /* Binary Point */ 6078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* ??? Not implemented. */ 6088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x10: /* End Of Interrupt */ 6108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return gic_complete_irq(s, cpu, value & 0x3ff); 6118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 6125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hw_error("gic_cpu_write: Bad offset %x\n", (int)offset); 6138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 6148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_update(s); 6168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 6178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 6188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_reset(gic_state *s) 6208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 6218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i; 6228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state)); 6238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0 ; i < NCPU; i++) { 6248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->priority_mask[i] = 0xf0; 6258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->current_pending[i] = 1023; 6268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->running_irq[i] = 1023; 6278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->running_priority[i] = 0x100; 6288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC 6298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* The NVIC doesn't have per-cpu interfaces, so enable by default. */ 6308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->cpu_enabled[i] = 1; 6318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else 6328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->cpu_enabled[i] = 0; 6338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 6348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < 16; i++) { 6368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_SET_ENABLED(i); 6378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project GIC_SET_TRIGGER(i); 6388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC 6408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* The NVIC is always enabled. */ 6418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->enabled = 1; 6428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else 6438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->enabled = 0; 6448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 6458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 6468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_save(QEMUFile *f, void *opaque) 6488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 6498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_state *s = (gic_state *)opaque; 6508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i; 6518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int j; 6528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, s->enabled); 6548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < NCPU; i++) { 6558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, s->cpu_enabled[i]); 6568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC 6578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, s->irq_target[i]); 6588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 6598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (j = 0; j < 32; j++) 6608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, s->priority1[j][i]); 6618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (j = 0; j < GIC_NIRQ; j++) 6628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, s->last_active[j][i]); 6638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, s->priority_mask[i]); 6648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, s->running_irq[i]); 6658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, s->running_priority[i]); 6668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, s->current_pending[i]); 6678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < GIC_NIRQ - 32; i++) { 6698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, s->priority2[i]); 6708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < GIC_NIRQ; i++) { 6728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_byte(f, s->irq_state[i].enabled); 6738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_byte(f, s->irq_state[i].pending); 6748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_byte(f, s->irq_state[i].active); 6758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_byte(f, s->irq_state[i].level); 6768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_byte(f, s->irq_state[i].model); 6778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_byte(f, s->irq_state[i].trigger); 6788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 6808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int gic_load(QEMUFile *f, void *opaque, int version_id) 6828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 6838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_state *s = (gic_state *)opaque; 6848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i; 6858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int j; 6868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (version_id != 1) 6888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -EINVAL; 6898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->enabled = qemu_get_be32(f); 6918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < NCPU; i++) { 6928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->cpu_enabled[i] = qemu_get_be32(f); 6938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC 6948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->irq_target[i] = qemu_get_be32(f); 6958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 6968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (j = 0; j < 32; j++) 6978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->priority1[j][i] = qemu_get_be32(f); 6988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (j = 0; j < GIC_NIRQ; j++) 6998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->last_active[j][i] = qemu_get_be32(f); 7008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->priority_mask[i] = qemu_get_be32(f); 7018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->running_irq[i] = qemu_get_be32(f); 7028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->running_priority[i] = qemu_get_be32(f); 7038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->current_pending[i] = qemu_get_be32(f); 7048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < GIC_NIRQ - 32; i++) { 7068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->priority2[i] = qemu_get_be32(f); 7078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < GIC_NIRQ; i++) { 7098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->irq_state[i].enabled = qemu_get_byte(f); 7108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->irq_state[i].pending = qemu_get_byte(f); 7118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->irq_state[i].active = qemu_get_byte(f); 7128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->irq_state[i].level = qemu_get_byte(f); 7138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->irq_state[i].model = qemu_get_byte(f); 7148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->irq_state[i].trigger = qemu_get_byte(f); 7158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 7188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 7198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void gic_init(gic_state *s) 7218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 7228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i; 7238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32); 7258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < NCPU; i++) { 7265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sysbus_init_irq(&s->busdev, &s->parent_irq[i]); 7278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->iomemtype = cpu_register_io_memory(gic_dist_readfn, 7295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner gic_dist_writefn, s); 7308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project gic_reset(s); 7315cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner register_savevm(NULL, 7325cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner "arm_gic", 7335cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner -1, 7345cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner 1, 7355cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner gic_save, 7365cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner gic_load, 7375cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner s); 7388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 739