Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/arm/generic_timer.c
Show First 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | |||||
#define GT_CNTKCTL_PL0PTEN (1 << 9) /* PL0 Physical timer reg access */ | #define GT_CNTKCTL_PL0PTEN (1 << 9) /* PL0 Physical timer reg access */ | ||||
#define GT_CNTKCTL_PL0VTEN (1 << 8) /* PL0 Virtual timer reg access */ | #define GT_CNTKCTL_PL0VTEN (1 << 8) /* PL0 Virtual timer reg access */ | ||||
#define GT_CNTKCTL_EVNTI (0xf << 4) /* Virtual counter event bits */ | #define GT_CNTKCTL_EVNTI (0xf << 4) /* Virtual counter event bits */ | ||||
#define GT_CNTKCTL_EVNTDIR (1 << 3) /* Virtual counter event transition */ | #define GT_CNTKCTL_EVNTDIR (1 << 3) /* Virtual counter event transition */ | ||||
#define GT_CNTKCTL_EVNTEN (1 << 2) /* Enables virtual counter events */ | #define GT_CNTKCTL_EVNTEN (1 << 2) /* Enables virtual counter events */ | ||||
#define GT_CNTKCTL_PL0VCTEN (1 << 1) /* PL0 CNTVCT and CNTFRQ access */ | #define GT_CNTKCTL_PL0VCTEN (1 << 1) /* PL0 CNTVCT and CNTFRQ access */ | ||||
#define GT_CNTKCTL_PL0PCTEN (1 << 0) /* PL0 CNTPCT and CNTFRQ access */ | #define GT_CNTKCTL_PL0PCTEN (1 << 0) /* PL0 CNTPCT and CNTFRQ access */ | ||||
#define GT_PHYS_SECURE 0 | |||||
#define GT_PHYS_NONSECURE 1 | |||||
#define GT_VIRT 2 | |||||
#define GT_HYP 3 | |||||
extern char hypmode_enabled[]; | |||||
struct arm_tmr_softc { | struct arm_tmr_softc { | ||||
struct resource *res[4]; | struct resource *res[4]; | ||||
void *ihl[4]; | void *ihl[4]; | ||||
uint32_t clkfreq; | uint32_t clkfreq; | ||||
struct eventtimer et; | struct eventtimer et; | ||||
bool physical; | bool physical; | ||||
}; | }; | ||||
static struct arm_tmr_softc *arm_tmr_sc = NULL; | static struct arm_tmr_softc *arm_tmr_sc = NULL; | ||||
static struct resource_spec timer_spec[] = { | static struct resource_spec timer_spec[] = { | ||||
{ SYS_RES_IRQ, 0, RF_ACTIVE }, /* Secure */ | { SYS_RES_IRQ, GT_PHYS_SECURE, RF_ACTIVE }, /* Secure */ | ||||
{ SYS_RES_IRQ, 1, RF_ACTIVE }, /* Non-secure */ | { SYS_RES_IRQ, GT_PHYS_NONSECURE, RF_ACTIVE }, /* Non-secure */ | ||||
{ SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL }, /* Virt */ | { SYS_RES_IRQ, GT_VIRT, RF_ACTIVE | RF_OPTIONAL }, /* Virt */ | ||||
{ SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, /* Hyp */ | { SYS_RES_IRQ, GT_HYP, RF_ACTIVE | RF_OPTIONAL }, /* Hyp */ | ||||
{ -1, 0 } | { -1, 0 } | ||||
}; | }; | ||||
static uint32_t arm_tmr_fill_vdso_timehands(struct vdso_timehands *vdso_th, | static uint32_t arm_tmr_fill_vdso_timehands(struct vdso_timehands *vdso_th, | ||||
struct timecounter *tc); | struct timecounter *tc); | ||||
static void arm_tmr_do_delay(int usec, void *); | static void arm_tmr_do_delay(int usec, void *); | ||||
static uint64_t get_cntxct(bool physical); | |||||
static timecounter_get_t arm_tmr_get_timecount; | static timecounter_get_t arm_tmr_get_timecount; | ||||
static struct timecounter arm_tmr_timecount = { | struct timecounter arm_tmr_timecount = { | ||||
.tc_name = "ARM MPCore Timecounter", | .tc_name = "ARM MPCore Timecounter", | ||||
.tc_get_timecount = arm_tmr_get_timecount, | .tc_get_timecount = arm_tmr_get_timecount, | ||||
.tc_poll_pps = NULL, | .tc_poll_pps = NULL, | ||||
.tc_counter_mask = ~0u, | .tc_counter_mask = ~0u, | ||||
.tc_frequency = 0, | .tc_frequency = 0, | ||||
.tc_quality = 1000, | .tc_quality = 1000, | ||||
.tc_fill_vdso_timehands = arm_tmr_fill_vdso_timehands, | .tc_fill_vdso_timehands = arm_tmr_fill_vdso_timehands, | ||||
.tc_priv = get_cntxct, | |||||
}; | }; | ||||
#ifdef __arm__ | #ifdef __arm__ | ||||
#define get_el0(x) cp15_## x ##_get() | #define get_el0(x) cp15_## x ##_get() | ||||
#define get_el1(x) cp15_## x ##_get() | #define get_el1(x) cp15_## x ##_get() | ||||
#define set_el0(x, val) cp15_## x ##_set(val) | #define set_el0(x, val) cp15_## x ##_set(val) | ||||
#define set_el1(x, val) cp15_## x ##_set(val) | #define set_el1(x, val) cp15_## x ##_set(val) | ||||
#else /* __aarch64__ */ | #else /* __aarch64__ */ | ||||
#define get_el0(x) READ_SPECIALREG(x ##_el0) | #define get_el0(x) READ_SPECIALREG(x ##_el0) | ||||
#define get_el1(x) READ_SPECIALREG(x ##_el1) | #define get_el1(x) READ_SPECIALREG(x ##_el1) | ||||
#define set_el0(x, val) WRITE_SPECIALREG(x ##_el0, val) | #define set_el0(x, val) WRITE_SPECIALREG(x ##_el0, val) | ||||
#define set_el1(x, val) WRITE_SPECIALREG(x ##_el1, val) | #define set_el1(x, val) WRITE_SPECIALREG(x ##_el1, val) | ||||
#endif | #endif | ||||
static int | static int | ||||
get_freq(void) | get_freq(void) | ||||
{ | { | ||||
return (get_el0(cntfrq)); | return (get_el0(cntfrq)); | ||||
} | } | ||||
static long | static uint64_t | ||||
get_cntxct(bool physical) | get_cntxct(bool physical) | ||||
{ | { | ||||
uint64_t val; | uint64_t val; | ||||
isb(); | isb(); | ||||
if (physical) | if (physical) | ||||
val = get_el0(cntpct); | val = get_el0(cntpct); | ||||
else | else | ||||
▲ Show 20 Lines • Show All 152 Lines • ▼ Show 20 Lines | arm_tmr_fdt_probe(device_t dev) | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef DEV_ACPI | #ifdef DEV_ACPI | ||||
static void | static void | ||||
arm_tmr_acpi_identify(driver_t *driver, device_t parent) | arm_tmr_acpi_identify(driver_t *driver, device_t parent) | ||||
{ | { | ||||
struct arm_tmr_softc *sc; | |||||
ACPI_TABLE_GTDT *gtdt; | ACPI_TABLE_GTDT *gtdt; | ||||
vm_paddr_t physaddr; | vm_paddr_t physaddr; | ||||
device_t dev; | device_t dev; | ||||
physaddr = acpi_find_table(ACPI_SIG_GTDT); | physaddr = acpi_find_table(ACPI_SIG_GTDT); | ||||
if (physaddr == 0) | if (physaddr == 0) | ||||
return; | return; | ||||
gtdt = acpi_map_table(physaddr, ACPI_SIG_GTDT); | gtdt = acpi_map_table(physaddr, ACPI_SIG_GTDT); | ||||
if (gtdt == NULL) { | if (gtdt == NULL) { | ||||
device_printf(parent, "gic: Unable to map the GTDT\n"); | device_printf(parent, "gic: Unable to map the GTDT\n"); | ||||
return; | return; | ||||
} | } | ||||
dev = BUS_ADD_CHILD(parent, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE, | dev = BUS_ADD_CHILD(parent, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE, | ||||
"generic_timer", -1); | "generic_timer", -1); | ||||
if (dev == NULL) { | if (dev == NULL) { | ||||
device_printf(parent, "add gic child failed\n"); | device_printf(parent, "add gic child failed\n"); | ||||
goto out; | goto out; | ||||
} | } | ||||
BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 0, | sc = device_get_softc(dev); | ||||
if (sc->physical) { | |||||
BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, GT_PHYS_SECURE, | |||||
gtdt->SecureEl1Interrupt, 1); | gtdt->SecureEl1Interrupt, 1); | ||||
BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 1, | BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, GT_PHYS_NONSECURE, | ||||
gtdt->NonSecureEl1Interrupt, 1); | gtdt->NonSecureEl1Interrupt, 1); | ||||
BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 2, | } else { | ||||
BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, GT_VIRT, | |||||
gtdt->VirtualTimerInterrupt, 1); | gtdt->VirtualTimerInterrupt, 1); | ||||
} | |||||
out: | out: | ||||
acpi_unmap_table(gtdt); | acpi_unmap_table(gtdt); | ||||
} | } | ||||
static int | static int | ||||
arm_tmr_acpi_probe(device_t dev) | arm_tmr_acpi_probe(device_t dev) | ||||
{ | { | ||||
Show All 40 Lines | if (sc->clkfreq == 0) { | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
if (bus_alloc_resources(dev, timer_spec, sc->res)) { | if (bus_alloc_resources(dev, timer_spec, sc->res)) { | ||||
device_printf(dev, "could not allocate resources\n"); | device_printf(dev, "could not allocate resources\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
#ifdef __arm__ | |||||
sc->physical = true; | |||||
#else /* __aarch64__ */ | |||||
/* If we do not have a virtual timer use the physical. */ | |||||
sc->physical = (sc->res[2] == NULL) ? true : false; | |||||
#endif | |||||
arm_tmr_sc = sc; | arm_tmr_sc = sc; | ||||
/* Setup secure, non-secure and virtual IRQs handler */ | sc->physical = (sc->res[GT_VIRT] == NULL) || (hypmode_enabled[0] == 0); | ||||
for (i = 0; i < 3; i++) { | |||||
if (sc->physical) { | |||||
for (i = GT_PHYS_SECURE; i <= GT_PHYS_NONSECURE; i++) { | |||||
/* If we do not have the interrupt, skip it. */ | /* If we do not have the interrupt, skip it. */ | ||||
if (sc->res[i] == NULL) | if (sc->res[i] == NULL) | ||||
continue; | continue; | ||||
error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK, | error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK, | ||||
arm_tmr_intr, NULL, sc, &sc->ihl[i]); | arm_tmr_intr, NULL, sc, &sc->ihl[i]); | ||||
if (error) { | |||||
device_printf(dev, "Unable to alloc int resource.\n"); | |||||
return (ENXIO); | |||||
} | |||||
} | |||||
} else { | |||||
error = bus_setup_intr(dev, sc->res[GT_VIRT], INTR_TYPE_CLK, | |||||
arm_tmr_intr, NULL, sc, &sc->ihl[GT_VIRT]); | |||||
if (error) { | if (error) { | ||||
device_printf(dev, "Unable to alloc int resource.\n"); | device_printf(dev, "Unable to alloc int resource.\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
} | } | ||||
arm_tmr_timecount.tc_frequency = sc->clkfreq; | arm_tmr_timecount.tc_frequency = sc->clkfreq; | ||||
tc_init(&arm_tmr_timecount); | tc_init(&arm_tmr_timecount); | ||||
▲ Show 20 Lines • Show All 124 Lines • Show Last 20 Lines |