/* * Map the local APIC and setup necessary interrupt vectors. */ void lapic_init(vm_paddr_t addr) { u_int regs[4]; int i, arat; /* Map the local APIC and setup the spurious interrupt handler. */ KASSERT(trunc_page(addr) == addr, ("local APIC not aligned on a page boundary")); lapic_paddr = addr; lapic = pmap_mapdev(addr, sizeof(lapic_t)); setidt(APIC_SPURIOUS_INT, IDTVEC(spuriousint), SDT_APIC, SEL_KPL, GSEL_APIC); /* Perform basic initialization of the BSP's local APIC. */ lapic_enable(); /* Set BSP's per-CPU local APIC ID. */ PCPU_SET(apic_id, lapic_id()); /* Local APIC timer interrupt. */ setidt(APIC_TIMER_INT, IDTVEC(timerint), SDT_APIC, SEL_KPL, GSEL_APIC); /* Local APIC error interrupt. */ setidt(APIC_ERROR_INT, IDTVEC(errorint), SDT_APIC, SEL_KPL, GSEL_APIC); /* XXX: Thermal interrupt */ /* Local APIC CMCI. */ setidt(APIC_CMC_INT, IDTVEC(cmcint), SDT_APICT, SEL_KPL, GSEL_APIC); if ((resource_int_value("apic", 0, "clock", &i) != 0 || i != 0)) { arat = 0; /* Intel CPUID 0x06 EAX[2] set if APIC timer runs in C3. */ if (cpu_vendor_id == CPU_VENDOR_INTEL && cpu_high >= 6) { do_cpuid(0x06, regs); if ((regs[0] & CPUTPM1_ARAT) != 0) arat = 1; } bzero(&lapic_et, sizeof(lapic_et)); lapic_et.et_name = "LAPIC"; lapic_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; lapic_et.et_quality = 600; if (!arat) { lapic_et.et_flags |= ET_FLAGS_C3STOP; lapic_et.et_quality -= 200; } lapic_et.et_frequency = 0; /* We don't know frequency yet, so trying to guess. */ lapic_et.et_min_period.sec = 0; lapic_et.et_min_period.frac = 0x00001000LL << 32; lapic_et.et_max_period.sec = 1; lapic_et.et_max_period.frac = 0; lapic_et.et_start = lapic_et_start; lapic_et.et_stop = lapic_et_stop; lapic_et.et_priv = NULL; et_register(&lapic_et); } }
void hv_et_init(void) { et.et_name = "HyperV"; et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU | ET_FLAGS_PERIODIC; et.et_quality = 1000; et.et_frequency = HV_TIMER_FREQUENCY; et.et_min_period = (1LL << 32) / HV_TIMER_FREQUENCY; et.et_max_period = HV_MAX_DELTA_TICKS * ((1LL << 32) / HV_TIMER_FREQUENCY); et.et_start = hv_et_start; et.et_stop = hv_et_stop; et.et_priv = &et; et_register(&et); }
/* * Map the local APIC and setup necessary interrupt vectors. */ static void native_lapic_init(vm_paddr_t addr) { uint32_t ver; u_int regs[4]; int i, arat; /* * Enable x2APIC mode if possible. Map the local APIC * registers page. * * Keep the LAPIC registers page mapped uncached for x2APIC * mode too, to have direct map page attribute set to * uncached. This is needed to work around CPU errata present * on all Intel processors. */ KASSERT(trunc_page(addr) == addr, ("local APIC not aligned on a page boundary")); lapic_paddr = addr; lapic_map = pmap_mapdev(addr, PAGE_SIZE); if (x2apic_mode) { native_lapic_enable_x2apic(); lapic_map = NULL; } /* Setup the spurious interrupt handler. */ setidt(APIC_SPURIOUS_INT, IDTVEC(spuriousint), SDT_APIC, SEL_KPL, GSEL_APIC); /* Perform basic initialization of the BSP's local APIC. */ lapic_enable(); /* Set BSP's per-CPU local APIC ID. */ PCPU_SET(apic_id, lapic_id()); /* Local APIC timer interrupt. */ setidt(APIC_TIMER_INT, IDTVEC(timerint), SDT_APIC, SEL_KPL, GSEL_APIC); /* Local APIC error interrupt. */ setidt(APIC_ERROR_INT, IDTVEC(errorint), SDT_APIC, SEL_KPL, GSEL_APIC); /* XXX: Thermal interrupt */ /* Local APIC CMCI. */ setidt(APIC_CMC_INT, IDTVEC(cmcint), SDT_APICT, SEL_KPL, GSEL_APIC); if ((resource_int_value("apic", 0, "clock", &i) != 0 || i != 0)) { arat = 0; /* Intel CPUID 0x06 EAX[2] set if APIC timer runs in C3. */ if (cpu_vendor_id == CPU_VENDOR_INTEL && cpu_high >= 6) { do_cpuid(0x06, regs); if ((regs[0] & CPUTPM1_ARAT) != 0) arat = 1; } bzero(&lapic_et, sizeof(lapic_et)); lapic_et.et_name = "LAPIC"; lapic_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; lapic_et.et_quality = 600; if (!arat) { lapic_et.et_flags |= ET_FLAGS_C3STOP; lapic_et.et_quality -= 200; } lapic_et.et_frequency = 0; /* We don't know frequency yet, so trying to guess. */ lapic_et.et_min_period = 0x00001000LL; lapic_et.et_max_period = SBT_1S; lapic_et.et_start = lapic_et_start; lapic_et.et_stop = lapic_et_stop; lapic_et.et_priv = NULL; et_register(&lapic_et); } /* * Set lapic_eoi_suppression after lapic_enable(), to not * enable suppression in the hardware prematurely. Note that * we by default enable suppression even when system only has * one IO-APIC, since EOI is broadcasted to all APIC agents, * including CPUs, otherwise. */ ver = lapic_read32(LAPIC_VERSION); if ((ver & APIC_VER_EOI_SUPPRESSION) != 0) { lapic_eoi_suppression = 1; TUNABLE_INT_FETCH("hw.lapic_eoi_suppression", &lapic_eoi_suppression); } }
static int imx_gpt_attach(device_t dev) { struct imx_gpt_softc *sc; int err; sc = device_get_softc(dev); if (bus_alloc_resources(dev, imx_gpt_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } sc->sc_dev = dev; sc->sc_clksrc = GPT_CR_CLKSRC_IPG; sc->sc_iot = rman_get_bustag(sc->res[0]); sc->sc_ioh = rman_get_bushandle(sc->res[0]); switch (sc->sc_clksrc) { case GPT_CR_CLKSRC_NONE: device_printf(dev, "can't run timer without clock source\n"); return (EINVAL); case GPT_CR_CLKSRC_EXT: device_printf(dev, "Not implemented. Geve me the way to get " "external clock source frequency\n"); return (EINVAL); case GPT_CR_CLKSRC_32K: sc->clkfreq = 32768; break; case GPT_CR_CLKSRC_IPG_HIGH: sc->clkfreq = imx51_get_clock(IMX51CLK_IPG_CLK_ROOT) * 2; break; default: sc->clkfreq = imx51_get_clock(IMX51CLK_IPG_CLK_ROOT); } device_printf(dev, "Run on %dKHz clock.\n", sc->clkfreq / 1000); /* Reset */ WRITE4(sc, IMX_GPT_CR, GPT_CR_SWR); /* Enable and setup counters */ WRITE4(sc, IMX_GPT_CR, GPT_CR_CLKSRC_IPG | /* Use IPG clock */ GPT_CR_FRR | /* Just count (FreeRunner mode) */ GPT_CR_STOPEN | /* Run in STOP mode */ GPT_CR_WAITEN | /* Run in WAIT mode */ GPT_CR_DBGEN); /* Run in DEBUG mode */ /* Disable interrupts */ WRITE4(sc, IMX_GPT_IR, 0); /* Tick every 10us */ /* XXX: must be calculated from clock source frequency */ WRITE4(sc, IMX_GPT_PR, 665); /* Use 100 KHz */ sc->clkfreq = 100000; /* Setup and enable the timer interrupt */ err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_CLK, imx_gpt_intr, NULL, sc, &sc->sc_ih); if (err != 0) { bus_release_resources(dev, imx_gpt_spec, sc->res); device_printf(dev, "Unable to setup the clock irq handler, " "err = %d\n", err); return (ENXIO); } sc->et.et_name = "i.MXxxx GPT Eventtimer"; sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC; sc->et.et_quality = 1000; sc->et.et_frequency = sc->clkfreq; sc->et.et_min_period = (MIN_PERIOD << 32) / sc->et.et_frequency; sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = imx_gpt_timer_start; sc->et.et_stop = imx_gpt_timer_stop; sc->et.et_priv = sc; et_register(&sc->et); /* Disable interrupts */ WRITE4(sc, IMX_GPT_IR, 0); /* ACK any panding interrupts */ WRITE4(sc, IMX_GPT_SR, (GPT_IR_ROV << 1) - 1); if (device_get_unit(dev) == 0) imx_gpt_sc = sc; imx_gpt_timecounter.tc_frequency = sc->clkfreq; tc_init(&imx_gpt_timecounter); printf("clock: hz=%d stathz = %d\n", hz, stathz); device_printf(sc->sc_dev, "timer clock frequency %d\n", sc->clkfreq); imx_gpt_delay_count = imx51_get_clock(IMX51CLK_ARM_ROOT) / 4000000; SET4(sc, IMX_GPT_CR, GPT_CR_EN); return (0); }
static int imx_gpt_attach(device_t dev) { struct imx_gpt_softc *sc; int ctlreg, err; uint32_t basefreq, prescale; sc = device_get_softc(dev); if (bus_alloc_resources(dev, imx_gpt_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } sc->sc_dev = dev; sc->sc_iot = rman_get_bustag(sc->res[0]); sc->sc_ioh = rman_get_bushandle(sc->res[0]); /* * For now, just automatically choose a good clock for the hardware * we're running on. Eventually we could allow selection from the fdt; * the code in this driver will cope with any clock frequency. */ sc->sc_clksrc = GPT_CR_CLKSRC_IPG; ctlreg = 0; switch (sc->sc_clksrc) { case GPT_CR_CLKSRC_32K: basefreq = 32768; break; case GPT_CR_CLKSRC_IPG: basefreq = imx_ccm_ipg_hz(); break; case GPT_CR_CLKSRC_IPG_HIGH: basefreq = imx_ccm_ipg_hz() * 2; break; case GPT_CR_CLKSRC_24M: ctlreg |= GPT_CR_24MEN; basefreq = 24000000; break; case GPT_CR_CLKSRC_NONE:/* Can't run without a clock. */ case GPT_CR_CLKSRC_EXT: /* No way to get the freq of an ext clock. */ default: device_printf(dev, "Unsupported clock source '%d'\n", sc->sc_clksrc); return (EINVAL); } /* * The following setup sequence is from the I.MX6 reference manual, * "Selecting the clock source". First, disable the clock and * interrupts. This also clears input and output mode bits and in * general completes several of the early steps in the procedure. */ WRITE4(sc, IMX_GPT_CR, 0); WRITE4(sc, IMX_GPT_IR, 0); /* Choose the clock and the power-saving behaviors. */ ctlreg |= sc->sc_clksrc | /* Use selected clock */ GPT_CR_FRR | /* Just count (FreeRunner mode) */ GPT_CR_STOPEN | /* Run in STOP mode */ GPT_CR_DOZEEN | /* Run in DOZE mode */ GPT_CR_WAITEN | /* Run in WAIT mode */ GPT_CR_DBGEN; /* Run in DEBUG mode */ WRITE4(sc, IMX_GPT_CR, ctlreg); /* * The datasheet says to do the software reset after choosing the clock * source. It says nothing about needing to wait for the reset to * complete, but the register description does document the fact that * the reset isn't complete until the SWR bit reads 0, so let's be safe. * The reset also clears all registers except for a few of the bits in * CR, but we'll rewrite all the CR bits when we start the counter. */ WRITE4(sc, IMX_GPT_CR, ctlreg | GPT_CR_SWR); while (READ4(sc, IMX_GPT_CR) & GPT_CR_SWR) continue; /* Set a prescaler value that gets us near the target frequency. */ if (basefreq < TARGET_FREQUENCY) { prescale = 0; sc->clkfreq = basefreq; } else { prescale = basefreq / TARGET_FREQUENCY; sc->clkfreq = basefreq / prescale; prescale -= 1; /* 1..n range is 0..n-1 in hardware. */ } WRITE4(sc, IMX_GPT_PR, prescale); /* Clear the status register. */ WRITE4(sc, IMX_GPT_SR, GPT_IR_ALL); /* Start the counter. */ WRITE4(sc, IMX_GPT_CR, ctlreg | GPT_CR_EN); if (bootverbose) device_printf(dev, "Running on %dKHz clock, base freq %uHz CR=0x%08x, PR=0x%08x\n", sc->clkfreq / 1000, basefreq, READ4(sc, IMX_GPT_CR), READ4(sc, IMX_GPT_PR)); /* Setup the timer interrupt. */ err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_CLK, imx_gpt_intr, NULL, sc, &sc->sc_ih); if (err != 0) { bus_release_resources(dev, imx_gpt_spec, sc->res); device_printf(dev, "Unable to setup the clock irq handler, " "err = %d\n", err); return (ENXIO); } /* Register as an eventtimer. */ sc->et.et_name = "iMXGPT"; sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC; sc->et.et_quality = 800; sc->et.et_frequency = sc->clkfreq; sc->et.et_min_period = (MIN_ET_PERIOD << 32) / sc->et.et_frequency; sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = imx_gpt_timer_start; sc->et.et_stop = imx_gpt_timer_stop; sc->et.et_priv = sc; et_register(&sc->et); /* Register as a timecounter. */ imx_gpt_timecounter.tc_frequency = sc->clkfreq; tc_init(&imx_gpt_timecounter); /* If this is the first unit, store the softc for use in DELAY. */ if (device_get_unit(dev) == 0) imx_gpt_sc = sc; return (0); }
static int jz4780_timer_attach(device_t dev) { struct jz4780_timer_softc *sc = device_get_softc(dev); pcell_t counter_freq; clk_t clk; /* There should be exactly one instance. */ if (jz4780_timer_sc != NULL) return (ENXIO); sc->dev = dev; if (bus_alloc_resources(dev, jz4780_timer_spec, sc->res)) { device_printf(dev, "can not allocate resources for device\n"); return (ENXIO); } counter_freq = 0; if (clk_get_by_name(dev, "ext", &clk) == 0) { uint64_t clk_freq; if (clk_get_freq(clk, &clk_freq) == 0) counter_freq = (uint32_t)clk_freq / 16; clk_release(clk); } if (counter_freq == 0) { device_printf(dev, "unable to determine ext clock frequency\n"); /* Hardcode value we 'know' is correct */ counter_freq = 48000000 / 16; } /* * Disable the timers, select the input for each timer, * clear and then start OST. */ /* Stop OST, if it happens to be running */ CSR_WRITE_4(sc, JZ_TC_TECR, TESR_OST); /* Stop all other channels as well */ CSR_WRITE_4(sc, JZ_TC_TECR, TESR_TCST0 | TESR_TCST1 | TESR_TCST2 | TESR_TCST3 | TESR_TCST4 | TESR_TCST5 | TESR_TCST6 | TESR_TCST3); /* Clear detect mask flags */ CSR_WRITE_4(sc, JZ_TC_TFCR, 0xFFFFFFFF); /* Mask all interrupts */ CSR_WRITE_4(sc, JZ_TC_TMSR, 0xFFFFFFFF); /* Init counter with known data */ CSR_WRITE_4(sc, JZ_OST_CTRL, 0); CSR_WRITE_4(sc, JZ_OST_CNT_LO, 0); CSR_WRITE_4(sc, JZ_OST_CNT_HI, 0); CSR_WRITE_4(sc, JZ_OST_DATA, 0xffffffff); /* Configure counter for external clock */ CSR_WRITE_4(sc, JZ_OST_CTRL, OSTC_EXT_EN | OSTC_MODE | OSTC_DIV_16); /* Start the counter again */ CSR_WRITE_4(sc, JZ_TC_TESR, TESR_OST); /* Configure TCU channel 5 similarly to OST and leave it disabled */ CSR_WRITE_4(sc, JZ_TC_TCSR(5), TCSR_EXT_EN | TCSR_DIV_16); CSR_WRITE_4(sc, JZ_TC_TMCR, TMR_FMASK(5)); if (bus_setup_intr(dev, sc->res[2], INTR_TYPE_CLK, jz4780_hardclock, NULL, sc, &sc->ih_cookie)) { device_printf(dev, "could not setup interrupt handler\n"); bus_release_resources(dev, jz4780_timer_spec, sc->res); return (ENXIO); } sc->et.et_name = "JZ4780 TCU5"; sc->et.et_flags = ET_FLAGS_ONESHOT; sc->et.et_frequency = counter_freq; sc->et.et_quality = 1000; sc->et.et_min_period = (0x00000002LLU * SBT_1S) / sc->et.et_frequency; sc->et.et_max_period = (0x0000fffeLLU * SBT_1S) / sc->et.et_frequency; sc->et.et_start = jz4780_timer_start; sc->et.et_stop = jz4780_timer_stop; sc->et.et_priv = sc; et_register(&sc->et); sc->tc.tc_get_timecount = jz4780_get_timecount; sc->tc.tc_name = "JZ4780 OST"; sc->tc.tc_frequency = counter_freq; sc->tc.tc_counter_mask = ~0u; sc->tc.tc_quality = 1000; sc->tc.tc_priv = sc; tc_init(&sc->tc); /* Now when tc is initialized, allow DELAY to find it */ jz4780_timer_sc = sc; return (0); }