int __init ra_systick_clockevent_init(void) { unsigned int cpu = smp_processor_id(); struct clock_event_device *cd; unsigned int irq, i __maybe_unused; unsigned long _gic_base __maybe_unused; /* * With vectored interrupts things are getting platform specific. * get_c0_compare_int is a hook to allow a platform to return the * interrupt number of it's liking. */ irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; cd = &ra_systick; cd->features = CLOCK_EVT_FEAT_ONESHOT; cd->name = "Ralink System Tick Counter"; clockevent_set_clock(cd, 50000); cd->max_delta_ns = clockevent_delta2ns(0x7fff, cd); cd->min_delta_ns = clockevent_delta2ns(0x3, cd); #ifdef CONFIG_RALINK_MT7621 /* must be lower than MIPS original cd rating(300) to activate "broadcast mode" */ cd->rating = 250; #else /* must be higher than MIPS original cd rating(300). */ cd->rating = 350; #endif cd->irq = irq; cd->cpumask = cpumask_of(cpu); cd->set_next_event = ra_systick_next_event; cd->set_mode = ra_systick_set_clock_mode; cd->event_handler = ra_systick_event_handler; #ifdef CONFIG_RALINK_MT7621 /* Program MIPS GIC to turn off(mask) each VPE's local timer interrupt. * "_gic_base" is for GIC read/write macro. */ _gic_base = (unsigned long) ioremap_nocache(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ); for (i = 0; i < NR_CPUS /* numvpes */; i++) { GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), GIC_VPE_SMASK_TIMER_MSK); } #endif /* install timer irq handler before MIPS BSP code. */ if (!cp0_timer_irq_installed){ cp0_timer_irq_installed = 1; setup_irq(irq, &ra_c0_compare_irqaction); } clockevents_register_device(cd); /* Enable ralink system count register */ (*((volatile u32 *)(RALINK_MCNT_CFG))) = 0x3; return 0; }
cycle_t gic_read_count(void) { unsigned int hi, hi2, lo; do { GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi); GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), lo); GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi2); } while (hi2 != hi); return (((cycle_t) hi) << 32) + lo; }
void gic_send_ipi(unsigned int intr) { #if gic_wedgeb2bok == 0 unsigned long flags; #endif pr_debug("CPU%d: %s status %08x\n", smp_processor_id(), __func__, read_c0_status()); if (!gic_wedgeb2bok) spin_lock_irqsave(&gic_wedgeb2b_lock, flags); GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr); if (!gic_wedgeb2bok) { (void) GIC_REG(SHARED, GIC_SH_CONFIG); spin_unlock_irqrestore(&gic_wedgeb2b_lock, flags); } }
/* * Estimate CPU and GIC frequencies. */ static void __init estimate_frequencies(void) { unsigned long flags; unsigned int count, start; #ifdef CONFIG_IRQ_GIC unsigned int giccount = 0, gicstart = 0; #endif #if defined(CONFIG_KVM_GUEST) && CONFIG_KVM_GUEST_TIMER_FREQ mips_hpt_frequency = CONFIG_KVM_GUEST_TIMER_FREQ * 1000000; return; #endif local_irq_save(flags); /* Start counter exactly on falling edge of update flag. */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); /* Initialize counters. */ start = read_c0_count(); #ifdef CONFIG_IRQ_GIC if (gic_present) GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), gicstart); #endif /* Read counter exactly on falling edge of update flag. */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); count = read_c0_count(); #ifdef CONFIG_IRQ_GIC if (gic_present) GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), giccount); #endif local_irq_restore(flags); count -= start; mips_hpt_frequency = count; #ifdef CONFIG_IRQ_GIC if (gic_present) { giccount -= gicstart; gic_frequency = giccount; } #endif }
void __init gic_init(unsigned long gic_base_addr, unsigned long gic_addrspace_size, struct gic_intr_map *intr_map, unsigned int intr_map_size, unsigned int irqbase) { unsigned int gicconfig; _gic_base = (unsigned long) ioremap_nocache(gic_base_addr, gic_addrspace_size); _irqbase = irqbase; _intrmap = intr_map; _mapsize = intr_map_size; GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >> GIC_SH_CONFIG_NUMINTRS_SHF; numintrs = ((numintrs + 1) * 8); numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >> GIC_SH_CONFIG_NUMVPES_SHF; pr_debug("%s called\n", __func__); gic_basic_init(); }
void __init gic_init(unsigned long gic_base_addr, unsigned long gic_addrspace_size, struct gic_intr_map *intr_map, unsigned int intr_map_size, unsigned int irqbase) { unsigned int gicconfig; int numvpes, numintrs; _gic_base = (unsigned long) ioremap_nocache(gic_base_addr, gic_addrspace_size); _irqbase = irqbase; GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >> GIC_SH_CONFIG_NUMINTRS_SHF; numintrs = ((numintrs + 1) * 8); numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >> GIC_SH_CONFIG_NUMVPES_SHF; #ifdef CONFIG_RALINK_SOC numvpes = numvpes + 1; #endif pr_debug("%s called\n", __func__); gic_basic_init(numintrs, numvpes, intr_map, intr_map_size); }
void gic_irq_ack(struct irq_data *d) { int irq = (d->irq - gic_irq_base); GIC_CLR_INTR_MASK(irq); if (gic_irq_flags[irq] & GIC_TRIG_EDGE) GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); }
/* This is Malta specific and needs to be exported */ static void __init vpe_local_setup(unsigned int numvpes) { int i; #ifdef CONFIG_RALINK_SOC unsigned long timer_interrupt = GIC_INT_TMR, perf_interrupt = GIC_INT_PERFCTR; #else unsigned long timer_interrupt = 5, perf_interrupt = 5; #endif unsigned int vpe_ctl; #ifdef CONFIG_RALINK_SOC if (cpu_has_veic) { /* GIC timer interrupt -> CPU HW Int X (vector X+2) -> map to pin X+2-1 (since GIC adds 1) */ timer_interrupt += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET); /* GIC perfcnt interrupt -> CPU HW Int X (vector X+2) -> map to pin X+2-1 (since GIC adds 1) */ perf_interrupt += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET); } #endif /* * Setup the default performance counter timer interrupts * for all VPEs */ for (i = 0; i < numvpes; i++) { GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); /* Are Interrupts locally routable? */ GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl); if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK) GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), GIC_MAP_TO_PIN_MSK | timer_interrupt); #ifdef CONFIG_RALINK_SOC if (cpu_has_veic) { set_vi_handler(timer_interrupt+GIC_PIN_TO_VEC_OFFSET, gic_eic_tmr_irq_dispatch); } #endif if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK) GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), GIC_MAP_TO_PIN_MSK | perf_interrupt); #ifdef CONFIG_RALINK_SOC if (cpu_has_veic) { set_vi_handler(perf_interrupt+GIC_PIN_TO_VEC_OFFSET, gic_eic_tmr_irq_dispatch); } #endif } }
void __init arch_init_irq(void) { int i; unsigned int gic_rev; mips_cpu_irq_init(); if (cpu_has_vint) set_vi_handler(cp0_compare_irq, mips_timer_dispatch); if (gcmp_present) { GCMPGCB(GICBA) = GIC_BASE_ADDR | GCMP_GCB_GICBA_EN_MSK; gic_present = 1; } if (gic_present) { #if defined (CONFIG_MIPS_GIC_IPI) gic_call_int_base = GIC_IPI_CALL_VPE0; gic_resched_int_base = GIC_IPI_RESCHED_VPE0; fill_ipi_map(); #endif gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE); GICREAD(GIC_REG(SHARED, GIC_SH_REVISIONID), gic_rev); printk("MIPS GIC RevID: %d.%d\n", (gic_rev >> 8) & 0xff, gic_rev & 0xff); if (cpu_has_vint) { pr_info("Setting up vectored interrupts\n"); set_vi_handler(2 + GIC_CPU_INT0, gic_irq_dispatch); // CPU #if defined (CONFIG_MIPS_GIC_IPI) set_vi_handler(2 + GIC_CPU_INT1, gic_irq_dispatch); // IPI resched set_vi_handler(2 + GIC_CPU_INT2, gic_irq_dispatch); // IPI call #endif set_vi_handler(2 + GIC_CPU_INT3, gic_irq_dispatch); // FE set_vi_handler(2 + GIC_CPU_INT4, gic_irq_dispatch); // PCIe } #if defined (CONFIG_MIPS_GIC_IPI) set_c0_status(STATUSF_IP7 | STATUSF_IP6 | STATUSF_IP5 | STATUSF_IP2 | STATUSF_IP4 | STATUSF_IP3); /* setup ipi interrupts */ for (i = 0; i < nr_cpu_ids; i++) { arch_init_ipiirq(MIPS_GIC_IRQ_BASE + GIC_RESCHED_INT(i), &irq_resched); arch_init_ipiirq(MIPS_GIC_IRQ_BASE + GIC_CALL_INT(i), &irq_call); } #else set_c0_status(STATUSF_IP7 | STATUSF_IP6 | STATUSF_IP5 | STATUSF_IP2); #endif /* set hardware irq, mapped to GIC shared (skip 0, 1, 2, 5, 7) */ for (i = 3; i <= 31; i++) { if (i != 5 && i != 7) irq_set_handler(MIPS_GIC_IRQ_BASE + i, handle_level_irq); } } else {
static void gic_irq_ack(unsigned int irq) { irq -= _irqbase; pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); GIC_CLR_INTR_MASK(irq); if (gic_irq_flags[irq] & GIC_IRQ_FLAG_EDGE) GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); }
int __cpuinit gic_clockevent_init(void) { unsigned int cpu = smp_processor_id(); struct clock_event_device *cd; unsigned int irq; if (!cpu_has_counter || !gic_frequency) return -ENXIO; irq = MIPS_GIC_IRQ_BASE; cd = &per_cpu(gic_clockevent_device, cpu); cd->name = "MIPS GIC"; cd->features = CLOCK_EVT_FEAT_ONESHOT; clockevent_set_clock(cd, gic_frequency); /* Calculate the min / max delta */ cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); cd->min_delta_ns = clockevent_delta2ns(0x300, cd); cd->rating = 300; cd->irq = irq; cd->cpumask = cpumask_of(cpu); cd->set_next_event = gic_next_event; cd->set_mode = gic_set_clock_mode; cd->event_handler = gic_event_handler; clockevents_register_device(cd); GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP), 0x80000002); GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), GIC_VPE_SMASK_CMP_MSK); if (gic_timer_irq_installed) return 0; gic_timer_irq_installed = 1; setup_irq(irq, &gic_compare_irqaction); irq_set_handler(irq, handle_percpu_irq); return 0; }
static void gic_irq_ack(unsigned int irq) { #if gic_wedgeb2bok == 0 unsigned long flags; #endif pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); irq -= _irqbase; GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))), 1 << (irq % 32)); if (_intrmap[irq].trigtype == GIC_TRIG_EDGE) { if (!gic_wedgeb2bok) spin_lock_irqsave(&gic_wedgeb2b_lock, flags); GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); if (!gic_wedgeb2bok) { (void) GIC_REG(SHARED, GIC_SH_CONFIG); spin_unlock_irqrestore(&gic_wedgeb2b_lock, flags); } } }
/* This is Malta specific and needs to be exported */ static void vpe_local_setup(unsigned int numvpes) { int i; unsigned long timer_interrupt = 5, perf_interrupt = 5; unsigned int vpe_ctl; /* * Setup the default performance counter timer interrupts * for all VPEs */ for (i = 0; i < numvpes; i++) { GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); /* Are Interrupts locally routable? */ GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl); if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK) GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), GIC_MAP_TO_PIN_MSK | timer_interrupt); if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK) GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), GIC_MAP_TO_PIN_MSK | perf_interrupt); } }
void gic_send_ipi(unsigned int intr) { pr_debug("CPU%d: %s status %08x\n", smp_processor_id(), __func__, read_c0_status()); GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr); }
static int __init of_gic_init(struct device_node *node, struct device_node *parent) { struct irq_domain *domain; struct resource gcmp = { 0 }, gic = { 0 }; unsigned int gic_rev; int i; if (of_address_to_resource(node, 0, &gic)) panic("Failed to get gic memory range"); if (request_mem_region(gic.start, resource_size(&gic), gic.name) < 0) panic("Failed to request gic memory"); if (of_address_to_resource(node, 2, &gcmp)) panic("Failed to get gic memory range"); if (request_mem_region(gcmp.start, resource_size(&gcmp), gcmp.name) < 0) panic("Failed to request gcmp memory"); _gcmp_base = (unsigned long) ioremap_nocache(gcmp.start, resource_size(&gcmp)); if (!_gcmp_base) panic("Failed to remap gcmp memory\n"); if ((GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) != gcmp.start) panic("Failed to find gcmp core\n"); /* tell the gcmp where to find the gic */ GCMPGCB(GICBA) = gic.start | GCMP_GCB_GICBA_EN_MSK; gic_present = 1; if (cpu_has_vint) { set_vi_handler(2, gic_irqdispatch); set_vi_handler(3, gic_irqdispatch); set_vi_handler(4, gic_irqdispatch); set_vi_handler(7, vi_timer_irqdispatch); } gic_fill_map(); gic_init(gic.start, resource_size(&gic), gic_intr_map, ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE); GICREAD(GIC_REG(SHARED, GIC_SH_REVISIONID), gic_rev); pr_info("gic: revision %d.%d\n", (gic_rev >> 8) & 0xff, gic_rev & 0xff); domain = irq_domain_add_legacy(node, GIC_NUM_INTRS, MIPS_GIC_IRQ_BASE, 0, &irq_domain_ops, NULL); if (!domain) panic("Failed to add irqdomain"); #if defined(CONFIG_MIPS_MT_SMP) for (i = 0; i < nr_cpu_ids; i++) { setup_irq(MIPS_GIC_IRQ_BASE + GIC_RESCHED_INT(i), &irq_resched); setup_irq(MIPS_GIC_IRQ_BASE + GIC_CALL_INT(i), &irq_call); } #endif change_c0_status(ST0_IM, STATUSF_IP7 | STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2); return 0; }
cycle_t gic_read_count(void) { unsigned int hi, hi2, lo; do { GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi); GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), lo); GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi2); } while (hi2 != hi); return (((cycle_t) hi) << 32) + lo; } void gic_write_compare(cycle_t cnt) { GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), (int)(cnt >> 32)); GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), (int)(cnt & 0xffffffff)); } cycle_t gic_read_compare(void) { unsigned int hi, lo; GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), hi); GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), lo); return (((cycle_t) hi) << 32) + lo; } #endif