/** * \b archIntEnable * * Enable/unmask an interrupt in the interrupt controller. * @param[in] int_vector Interrupt vector to enable/disable * @param[in] enable TRUE=enable, FALSE=disable * * @retval ATOM_OK Success * @retval ATOM_ERROR Error */ int archIntEnable (int int_vector, int enable) { CRITICAL_STORE; int status; /* Check vector is valid */ if ((int_vector < 0) || (int_vector > DM36X_INTC_MAX_VEC)) { /* Invalid vector number */ status = ATOM_ERROR; } else { /* Valid vector, mask or unmask it using RMW */ CRITICAL_START(); if (enable) { /* Enable/unmask the interrupt */ INTC_REG(((int_vector >= 32) ? DM36X_INTC_EINT1 : DM36X_INTC_EINT0)) |= (1 << ((int_vector >= 32) ? (int_vector - 32) : int_vector)); } else { /* Disable/mask the interrupt */ INTC_REG(((int_vector >= 32) ? DM36X_INTC_EINT1 : DM36X_INTC_EINT0)) &= ~(1 << ((int_vector >= 32) ? (int_vector - 32) : int_vector)); } CRITICAL_END(); status = ATOM_OK; } return (status); }
static void intc_mask_ack(struct irq_data *data) { unsigned int irq = data->irq; struct intc_desc_int *d = get_intc_desc(irq); unsigned long handle = intc_get_ack_handle(irq); unsigned long addr; intc_disable(data); /* read register and write zero only to the associated bit */ if (handle) { unsigned int value; addr = INTC_REG(d, _INTC_ADDR_D(handle), 0); value = intc_set_field_from_handle(0, 1, handle); switch (_INTC_FN(handle)) { case REG_FN_MODIFY_BASE + 0: /* 8bit */ __raw_readb(addr); __raw_writeb(0xff ^ value, addr); break; case REG_FN_MODIFY_BASE + 1: /* 16bit */ __raw_readw(addr); __raw_writew(0xffff ^ value, addr); break; case REG_FN_MODIFY_BASE + 3: /* 32bit */ __raw_readl(addr); __raw_writel(0xffffffff ^ value, addr); break; default: BUG(); break; } } }
static int intc_set_type(struct irq_data *data, unsigned int type) { unsigned int irq = data->irq; struct intc_desc_int *d = get_intc_desc(irq); unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK]; struct intc_handle_int *ihp; unsigned long addr; if (!value) return -EINVAL; value &= ~SENSE_VALID_FLAG; ihp = intc_find_irq(d->sense, d->nr_sense, irq); if (ihp) { /* PINT has 2-bit sense registers, should fail on EDGE_BOTH */ if (value >= (1 << _INTC_WIDTH(ihp->handle))) return -EINVAL; addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0); intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value); } return 0; }
/** * \b __interrupt_dispatcher * * Interrupt dispatcher: determines the source of the IRQ and calls * the appropriate ISR. * * Note that any ISRs which call Atomthreads OS routines that can * cause rescheduling of threads must be surrounded by calls to * atomIntEnter() and atomIntExit(). * */ void __interrupt_dispatcher (void) { uint32_t vector; uint32_t irqentry; /* Read IRQENTRY register to determine the source of the interrupt */ irqentry = INTC_REG(DM36X_INTC_IRQENTRY); /* Check for spurious interrupt */ if (irqentry == 0) { /* Spurious interrupt */ uart_write_halt ("Spurious IRQ\n"); } else { /* Translate from vector address to vector number */ vector = (INTC_REG(DM36X_INTC_IRQENTRY) / 4) - 1; /* Check vector number is valid */ if ((vector > 0) && (vector <= DM36X_INTC_MAX_VEC) && (isr_handlers[vector] != NULL)) { /* Ack the interrupt immediately, could get scheduled out below */ INTC_REG(((vector >= 32) ? DM36X_INTC_IRQ1 : DM36X_INTC_IRQ0)) = (1 << ((vector >= 32) ? (vector - 32) : vector)); /* * Let the Atomthreads kernel know we're about to enter an OS-aware * interrupt handler which could cause scheduling of threads. */ atomIntEnter(); /* Call the registered ISR */ isr_handlers[vector](vector); /* Call the interrupt exit routine */ atomIntExit(TRUE); } else { /* Unexpected vector */ uart_write_halt ("Unexpected IRQ vector\n"); } } }
void intc_balancing_disable(unsigned int irq) { struct intc_desc_int *d = get_intc_desc(irq); unsigned long handle = dist_handle[irq]; unsigned long addr; if (irq_balancing_disabled(irq) || !handle) return; addr = INTC_REG(d, _INTC_ADDR_D(handle), 0); intc_reg_fns[_INTC_FN(handle)](addr, handle, 0); }
static void intc_enable_disable(struct intc_desc_int *d, unsigned long handle, int do_enable) { unsigned long addr; unsigned int cpu; unsigned long (*fn)(unsigned long, unsigned long, unsigned long (*)(unsigned long, unsigned long, unsigned long), unsigned int); if (do_enable) { for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) { addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu); fn = intc_enable_noprio_fns[_INTC_MODE(handle)]; fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0); } } else { for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu); fn = intc_disable_fns[_INTC_MODE(handle)]; fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0); } } }
void _intc_enable(struct irq_data *data, unsigned long handle) { unsigned int irq = data->irq; struct intc_desc_int *d = get_intc_desc(irq); unsigned long addr; unsigned int cpu; for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) { #ifdef CONFIG_SMP if (!cpumask_test_cpu(cpu, data->affinity)) continue; #endif addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu); intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\ [_INTC_FN(handle)], irq); } intc_balancing_enable(irq); }
static int intc_set_type(struct irq_data *data, unsigned int type) { unsigned int irq = data->irq; struct intc_desc_int *d = get_intc_desc(irq); unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK]; struct intc_handle_int *ihp; unsigned long addr; if (!value) return -EINVAL; ihp = intc_find_irq(d->sense, d->nr_sense, irq); if (ihp) { addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0); intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value); } return 0; }
/** * \b low_level_init * * Initializes the PIC and starts the system timer tick interrupt. * */ int low_level_init (void) { /* Initialise TIMER0 registers for interrupt 100 times per second */ /* Reset & disable all TIMER0 timers */ TIMER0_REG(DM36X_TIMER_INTCTL_STAT) = 0; /* Disable interrupts */ TIMER0_REG(DM36X_TIMER_TCR) = 0; /* Disable all TIMER0 timers */ TIMER0_REG(DM36X_TIMER_TGCR) = 0; /* Put all TIMER0 timers in reset */ TIMER0_REG(DM36X_TIMER_TIM12) = 0; /* Clear Timer 1:2 */ /* Set up Timer 1:2 in 32-bit unchained mode */ TIMER0_REG(DM36X_TIMER_TGCR) = (1 << 2); /* Select 32-bit unchained mode (TIMMODE) */ TIMER0_REG(DM36X_TIMER_TGCR) |= (1 << 0); /* Remove Timer 1:2 from reset (TIM12RS) */ TIMER0_REG(DM36X_TIMER_PRD12) = (TIMER_CLK / SYSTEM_TICKS_PER_SEC) - 1; /* Set period to 100 ticks per second (PRD12) */ TIMER0_REG(DM36X_TIMER_TCR) |= (0 << 8); /* Select external clock source for Timer 1:2 (CLKSRC12) */ /* Enable interrupts */ TIMER0_REG(DM36X_TIMER_INTCTL_STAT) = (1 << 1) | (1 << 0); /* Enable/ack Compare/Match interrupt for Timer 1:2 */ /* Enable timer */ TIMER0_REG(DM36X_TIMER_TCR) |= (2 << 6); /* Enable Timer 1:2 continuous (ENAMODE12) */ /* Initialise INTC interrupt controller (all at lowest priority 7) */ INTC_REG(DM36X_INTC_PRI0) = 0x77777777; INTC_REG(DM36X_INTC_PRI1) = 0x77777777; INTC_REG(DM36X_INTC_PRI2) = 0x77777777; INTC_REG(DM36X_INTC_PRI3) = 0x77777777; INTC_REG(DM36X_INTC_PRI4) = 0x77777777; INTC_REG(DM36X_INTC_PRI5) = 0x77777777; INTC_REG(DM36X_INTC_PRI6) = 0x77777777; INTC_REG(DM36X_INTC_PRI7) = 0x77777777; INTC_REG(DM36X_INTC_INTCTL) = 0; INTC_REG(DM36X_INTC_EABASE) = 0; INTC_REG(DM36X_INTC_EINT0) = 0; INTC_REG(DM36X_INTC_EINT1) = 0; /* Ack TINT0 IRQ in INTC interrupt controller */ INTC_REG(DM36X_INTC_IRQ1) = (1 << (DM36X_INTC_VEC_TINT0 - 32)); /* Enable TINT0 IRQ in INTC interrupt controller */ INTC_REG(DM36X_INTC_EINT1) |= (1 << (DM36X_INTC_VEC_TINT0 - 32)); return 0 ; }