void gic_init(vaddr_t gicc_base, vaddr_t gicd_base) { size_t n; gic.gicc_base = gicc_base; gic.gicd_base = gicd_base; gic.max_it = probe_max_it(); for (n = 0; n <= gic.max_it / NUM_INTS_PER_REG; n++) { /* Disable interrupts */ write32(0xffffffff, gic.gicd_base + GICD_ICENABLER(n)); /* Make interrupts non-pending */ write32(0xffffffff, gic.gicd_base + GICD_ICPENDR(n)); /* Mark interrupts non-secure */ if (n == 0) { /* per-CPU inerrupts config: * ID0-ID7(SGI) for Non-secure interrupts * ID8-ID15(SGI) for Secure interrupts. * All PPI config as Non-secure interrupts. */ write32(0xffff00ff, gic.gicd_base + GICD_IGROUPR(n)); } else { write32(0xffffffff, gic.gicd_base + GICD_IGROUPR(n)); } } /* Enable GIC */ write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN, gic.gicc_base + GICC_CTLR); write32(GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1, gic.gicd_base + GICD_CTLR); }
static void gic_it_add(struct gic_data *gd, size_t it) { size_t idx = it / NUM_INTS_PER_REG; uint32_t mask = 1 << (it % NUM_INTS_PER_REG); /* Disable the interrupt */ write32(mask, gd->gicd_base + GICD_ICENABLER(idx)); /* Make it non-pending */ write32(mask, gd->gicd_base + GICD_ICPENDR(idx)); /* Assign it to group0 */ write32(read32(gd->gicd_base + GICD_IGROUPR(idx)) & ~mask, gd->gicd_base + GICD_IGROUPR(idx)); }
void gic_it_add(size_t it) { size_t idx = it / NUM_INTS_PER_REG; uint32_t mask = 1 << (it % NUM_INTS_PER_REG); assert(it <= gic.max_it); /* Not too large */ /* Disable the interrupt */ write32(mask, gic.gicd_base + GICD_ICENABLER(idx)); /* Make it non-pending */ write32(mask, gic.gicd_base + GICD_ICPENDR(idx)); /* Assign it to group0 */ write32(read32(gic.gicd_base + GICD_IGROUPR(idx)) & ~mask, gic.gicd_base + GICD_IGROUPR(idx)); }
void gic_init(vaddr_t gicc_base, vaddr_t gicd_base) { size_t n; gic.gicc_base = gicc_base; gic.gicd_base = gicd_base; gic.max_it = probe_max_it(); for (n = 0; n <= gic.max_it / 32; n++) { /* Disable interrupts */ write32(0xffffffff, gic.gicd_base + GICD_ICENABLER(n)); /* Make interrupts non-pending */ write32(0xffffffff, gic.gicd_base + GICD_ICPENDR(n)); /* Mark interrupts non-secure */ write32(0xffffffff, gic.gicd_base + GICD_IGROUPR(n)); } /* Enable GIC */ write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN, gic.gicc_base + GICC_CTLR); write32(GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1, gic.gicd_base + GICD_CTLR); }
/** * \fn init_gic_distributor * * Initialise GIC Dirstributor. * * Configure all IRQs to be active low, level sensitive, target cpu0, * priority 0xa0 and disable all interrupts. */ void init_gic_distributor() { GICD[GICD_CTLR] = 0x0; // disable GIC unsigned int typer = GICD[GICD_TYPER]; unsigned int lines = 32 * ((typer & 0x1F) + 1); unsigned int i; /* set global interrupts to active low, level sensitive */ for (i = 32; i < lines; i += 16) { GICD[GICD_ICFGR(i / 16)] = 0x0; } for (i = 32; i < lines; i += 4) { GICD[GICD_ITARGETSR(i / 4)] = 0x01010101; } for (i = 32; i < lines; i += 4) { GICD[GICD_IPRIORITYR(i / 4)] = 0xa0a0a0a0; } for (i = 32; i < lines; i += 32) { GICD[GICD_ICENABLER(i / 32)] = 0xFFFFFFFF; } for (i = 32; i < lines; i += 32) { GICD[GICD_IGROUPR(i / 32)] = 0x0; } GICD[GICD_CTLR] = 0x0; }
static void gic_it_disable(struct gic_data *gd, size_t it) { size_t idx = it / NUM_INTS_PER_REG; uint32_t mask = 1 << (it % NUM_INTS_PER_REG); /* Assigned to group0 */ assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); /* Disable the interrupt */ write32(mask, gd->gicd_base + GICD_ICENABLER(idx)); }
void gic_it_disable(size_t it) { size_t idx = it / NUM_INTS_PER_REG; uint32_t mask = 1 << (it % NUM_INTS_PER_REG); assert(it <= gic.max_it); /* Not too large */ /* Assigned to group0 */ assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask)); /* Disable the interrupt */ write32(mask, gic.gicd_base + GICD_ICENABLER(idx)); }
static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio) { size_t idx __maybe_unused = it / NUM_INTS_PER_REG; uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); /* Assigned to group0 */ assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); /* Set prio it to selected CPUs */ DMSG("prio: writing 0x%x to 0x%" PRIxVA, prio, gd->gicd_base + GICD_IPRIORITYR(0) + it); write8(prio, gd->gicd_base + GICD_IPRIORITYR(0) + it); }
void gic_cpu_init(void) { /* per-CPU inerrupts config: * ID0-ID7(SGI) for Non-secure interrupts * ID8-ID15(SGI) for Secure interrupts. * All PPI config as Non-secure interrupts. */ write32(0xffff00ff, gic.gicd_base + GICD_IGROUPR(0)); /* Enable GIC */ write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN, gic.gicc_base + GICC_CTLR); }
void gic_it_enable(size_t it) { size_t idx = it / 32; uint32_t mask = 1 << (it % 32); assert(it <= gic.max_it); /* Not too large */ /* Assigned to group0 */ assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask)); /* Not enabled yet */ assert(!(read32(gic.gicd_base + GICD_ISENABLER(idx)) & mask)); /* Enable the interrupt */ write32(mask, gic.gicd_base + GICD_ISENABLER(idx)); }
void gic_it_set_prio(size_t it, uint8_t prio) { size_t idx = it / NUM_INTS_PER_REG; uint32_t mask = 1 << (it % NUM_INTS_PER_REG); assert(it <= gic.max_it); /* Not too large */ /* Assigned to group0 */ assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask)); /* Set prio it to selected CPUs */ DMSG("prio: writing 0x%x to 0x%" PRIxVA, prio, gic.gicd_base + GICD_IPRIORITYR(0) + it); write8(prio, gic.gicd_base + GICD_IPRIORITYR(0) + it); }
void gic_init(struct gic_data *gd, vaddr_t gicc_base, vaddr_t gicd_base) { size_t n; gic_init_base_addr(gd, gicc_base, gicd_base); for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) { /* Disable interrupts */ write32(0xffffffff, gd->gicd_base + GICD_ICENABLER(n)); /* Make interrupts non-pending */ write32(0xffffffff, gd->gicd_base + GICD_ICPENDR(n)); /* Mark interrupts non-secure */ if (n == 0) { /* per-CPU inerrupts config: * ID0-ID7(SGI) for Non-secure interrupts * ID8-ID15(SGI) for Secure interrupts. * All PPI config as Non-secure interrupts. */ write32(0xffff00ff, gd->gicd_base + GICD_IGROUPR(n)); } else { write32(0xffffffff, gd->gicd_base + GICD_IGROUPR(n)); } } /* Set the priority mask to permit Non-secure interrupts, and to * allow the Non-secure world to adjust the priority mask itself */ write32(0x80, gd->gicc_base + GICC_PMR); /* Enable GIC */ write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN, gd->gicc_base + GICC_CTLR); write32(GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1, gd->gicd_base + GICD_CTLR); }
void gic_cpu_init(struct gic_data *gd) { /* per-CPU interrupts config: * ID0-ID7(SGI) for Non-secure interrupts * ID8-ID15(SGI) for Secure interrupts. * All PPI config as Non-secure interrupts. */ write32(0xffff00ff, gd->gicd_base + GICD_IGROUPR(0)); /* Set the priority mask to permit Non-secure interrupts, and to * allow the Non-secure world to adjust the priority mask itself */ write32(0x80, gd->gicc_base + GICC_PMR); /* Enable GIC */ write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN, gd->gicc_base + GICC_CTLR); }
void gic_it_set_cpu_mask(size_t it, uint8_t cpu_mask) { size_t idx = it / 32; uint32_t mask = 1 << (it % 32); uint32_t target; assert(it <= gic.max_it); /* Not too large */ /* Assigned to group0 */ assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask)); /* Route it to selected CPUs */ target = read32(gic.gicd_base + GICD_ITARGETSR(it / 4)); target &= ~(0xff << ((it % 4) * 8)); target |= cpu_mask << ((it % 4) * 8); DMSG("cpu_mask: writing 0x%x to 0x%x\n", target, gic.gicd_base + GICD_ITARGETSR(it / 4)); write32(target, gic.gicd_base + GICD_ITARGETSR(it / 4)); DMSG("cpu_mask: 0x%x\n", read32(gic.gicd_base + GICD_ITARGETSR(it / 4))); }
void gic_it_set_cpu_mask(size_t it, uint8_t cpu_mask) { size_t idx = it / NUM_INTS_PER_REG; uint32_t mask = 1 << (it % NUM_INTS_PER_REG); uint32_t target, target_shift; assert(it <= gic.max_it); /* Not too large */ /* Assigned to group0 */ assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask)); /* Route it to selected CPUs */ target = read32(gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG)); target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS; target &= ~(ITARGETSR_FIELD_MASK << target_shift); target |= cpu_mask << target_shift; DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG)); write32(target, gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG)); DMSG("cpu_mask: 0x%x\n", read32(gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG))); }
static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it, uint8_t cpu_mask) { size_t idx __maybe_unused = it / NUM_INTS_PER_REG; uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); uint32_t target, target_shift; /* Assigned to group0 */ assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); /* Route it to selected CPUs */ target = read32(gd->gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG)); target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS; target &= ~(ITARGETSR_FIELD_MASK << target_shift); target |= cpu_mask << target_shift; DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, gd->gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG)); write32(target, gd->gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG)); DMSG("cpu_mask: 0x%x\n", read32(gd->gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG))); }
static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it) { size_t idx = it / NUM_INTS_PER_REG; uint32_t mask = 1 << (it % NUM_INTS_PER_REG); return !!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask); }
/* * ディストリビュータの初期化 */ void gicd_initialize(void) { int i; /* * ディストリビュータをディスエーブル */ sil_wrw_mem(GICD_CTLR, GICD_CTLR_DISABLE); #ifdef TOPPERS_SAFEG_SECURE /* * すべての割込みをグループ1(IRQ)に設定 */ for (i = 0; i < (GIC_TNUM_INTNO + 31) / 32; i++) { sil_wrw_mem(GICD_IGROUPR(i), 0xffffffffU); } #endif /* TOPPERS_SAFEG_SECURE */ /* * すべての割込みを禁止 */ for (i = 0; i < (GIC_TNUM_INTNO + 31) / 32; i++) { sil_wrw_mem(GICD_ICENABLER(i), 0xffffffffU); } /* * すべての割込みペンディングをクリア */ for (i = 0; i < (GIC_TNUM_INTNO + 31) / 32; i++) { sil_wrw_mem(GICD_ICPENDR(i), 0xffffffffU); } /* * すべての割込みを最低優先度に設定 */ for (i = 0; i < (GIC_TNUM_INTNO + 3) / 4; i++){ sil_wrw_mem(GICD_IPRIORITYR(i), 0xffffffffU); } /* * すべての共有ペリフェラル割込みのターゲットをプロセッサ0に設定 */ for (i = GIC_INTNO_SPI0 / 4; i < (GIC_TNUM_INTNO + 3) / 4; i++) { sil_wrw_mem(GICD_ITARGETSR(i), 0x01010101U); } /* * すべてのペリフェラル割込みをレベルトリガに設定 */ for (i = GIC_INTNO_PPI0 / 16; i < (GIC_TNUM_INTNO + 15) / 16; i++) { #ifdef GIC_ARM11MPCORE sil_wrw_mem(GICD_ICFGR(i), 0x55555555U); #else /* GIC_ARM11MPCORE */ sil_wrw_mem(GICD_ICFGR(i), 0x00000000U); #endif /* GIC_ARM11MPCORE */ } /* * ディストリビュータをイネーブル */ sil_wrw_mem(GICD_CTLR, GICD_CTLR_ENABLE); }
bool gic_it_get_group(size_t it) { size_t idx = it / NUM_INTS_PER_REG; uint32_t mask = 1 << (it % NUM_INTS_PER_REG); return !!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask); }