target-arm: Implement AArch64 generic timers

Implement the AArch64 view of the generic timer system registers.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2014-02-26 17:20:05 +00:00
parent 4b7fff2fab
commit a7adc4b779
2 changed files with 75 additions and 14 deletions

View File

@ -104,7 +104,7 @@ struct arm_boot_info;
/* CPU state for each instance of a generic timer (in cp15 c14) */ /* CPU state for each instance of a generic timer (in cp15 c14) */
typedef struct ARMGenericTimer { typedef struct ARMGenericTimer {
uint64_t cval; /* Timer CompareValue register */ uint64_t cval; /* Timer CompareValue register */
uint32_t ctl; /* Timer Control register */ uint64_t ctl; /* Timer Control register */
} ARMGenericTimer; } ARMGenericTimer;
#define GTIMER_PHYS 0 #define GTIMER_PHYS 0
@ -204,8 +204,8 @@ typedef struct CPUARMState {
uint64_t tpidr_el0; /* User RW Thread register. */ uint64_t tpidr_el0; /* User RW Thread register. */
uint64_t tpidrro_el0; /* User RO Thread register. */ uint64_t tpidrro_el0; /* User RO Thread register. */
uint64_t tpidr_el1; /* Privileged Thread register. */ uint64_t tpidr_el1; /* Privileged Thread register. */
uint32_t c14_cntfrq; /* Counter Frequency register */ uint64_t c14_cntfrq; /* Counter Frequency register */
uint32_t c14_cntkctl; /* Timer Control register */ uint64_t c14_cntkctl; /* Timer Control register */
ARMGenericTimer c14_timer[NUM_GTIMERS]; ARMGenericTimer c14_timer[NUM_GTIMERS];
uint32_t c15_cpar; /* XScale Coprocessor Access Register */ uint32_t c15_cpar; /* XScale Coprocessor Access Register */
uint32_t c15_ticonfig; /* TI925T configuration byte. */ uint32_t c15_ticonfig; /* TI925T configuration byte. */

View File

@ -901,30 +901,55 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
* Our reset value matches the fixed frequency we implement the timer at. * Our reset value matches the fixed frequency we implement the timer at.
*/ */
{ .name = "CNTFRQ", .cp = 15, .crn = 14, .crm = 0, .opc1 = 0, .opc2 = 0, { .name = "CNTFRQ", .cp = 15, .crn = 14, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL1_RW | PL0_R, .type = ARM_CP_NO_MIGRATE,
.access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access,
.fieldoffset = offsetoflow32(CPUARMState, cp15.c14_cntfrq),
.resetfn = arm_cp_reset_ignore,
},
{ .name = "CNTFRQ_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 0,
.access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access,
.fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq), .fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq),
.resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE, .resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE,
.accessfn = gt_cntfrq_access,
}, },
/* overall control: mostly access permissions */ /* overall control: mostly access permissions */
{ .name = "CNTKCTL", .cp = 15, .crn = 14, .crm = 1, .opc1 = 0, .opc2 = 0, { .name = "CNTKCTL", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 14, .crm = 1, .opc2 = 0,
.access = PL1_RW, .access = PL1_RW,
.fieldoffset = offsetof(CPUARMState, cp15.c14_cntkctl), .fieldoffset = offsetof(CPUARMState, cp15.c14_cntkctl),
.resetvalue = 0, .resetvalue = 0,
}, },
/* per-timer control */ /* per-timer control */
{ .name = "CNTP_CTL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1, { .name = "CNTP_CTL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1,
.type = ARM_CP_IO | ARM_CP_NO_MIGRATE, .access = PL1_RW | PL0_R,
.accessfn = gt_ptimer_access,
.fieldoffset = offsetoflow32(CPUARMState,
cp15.c14_timer[GTIMER_PHYS].ctl),
.resetfn = arm_cp_reset_ignore,
.writefn = gt_ctl_write, .raw_writefn = raw_write,
},
{ .name = "CNTP_CTL_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 1,
.type = ARM_CP_IO, .access = PL1_RW | PL0_R, .type = ARM_CP_IO, .access = PL1_RW | PL0_R,
.accessfn = gt_ptimer_access,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl), .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl),
.resetvalue = 0, .resetvalue = 0,
.accessfn = gt_ptimer_access,
.writefn = gt_ctl_write, .raw_writefn = raw_write, .writefn = gt_ctl_write, .raw_writefn = raw_write,
}, },
{ .name = "CNTV_CTL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 1, { .name = "CNTV_CTL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 1,
.type = ARM_CP_IO | ARM_CP_NO_MIGRATE, .access = PL1_RW | PL0_R,
.accessfn = gt_vtimer_access,
.fieldoffset = offsetoflow32(CPUARMState,
cp15.c14_timer[GTIMER_VIRT].ctl),
.resetfn = arm_cp_reset_ignore,
.writefn = gt_ctl_write, .raw_writefn = raw_write,
},
{ .name = "CNTV_CTL_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 1,
.type = ARM_CP_IO, .access = PL1_RW | PL0_R, .type = ARM_CP_IO, .access = PL1_RW | PL0_R,
.accessfn = gt_vtimer_access,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl), .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl),
.resetvalue = 0, .resetvalue = 0,
.accessfn = gt_vtimer_access,
.writefn = gt_ctl_write, .raw_writefn = raw_write, .writefn = gt_ctl_write, .raw_writefn = raw_write,
}, },
/* TimerValue views: a 32 bit downcounting view of the underlying state */ /* TimerValue views: a 32 bit downcounting view of the underlying state */
@ -933,37 +958,73 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
.accessfn = gt_ptimer_access, .accessfn = gt_ptimer_access,
.readfn = gt_tval_read, .writefn = gt_tval_write, .readfn = gt_tval_read, .writefn = gt_tval_write,
}, },
{ .name = "CNTP_TVAL_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 0,
.type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R,
.readfn = gt_tval_read, .writefn = gt_tval_write,
},
{ .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0, { .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0,
.type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R, .type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R,
.accessfn = gt_vtimer_access, .accessfn = gt_vtimer_access,
.readfn = gt_tval_read, .writefn = gt_tval_write, .readfn = gt_tval_read, .writefn = gt_tval_write,
}, },
{ .name = "CNTV_TVAL_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 0,
.type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R,
.readfn = gt_tval_read, .writefn = gt_tval_write,
},
/* The counter itself */ /* The counter itself */
{ .name = "CNTPCT", .cp = 15, .crm = 14, .opc1 = 0, { .name = "CNTPCT", .cp = 15, .crm = 14, .opc1 = 0,
.access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO,
.accessfn = gt_pct_access, .accessfn = gt_pct_access,
.readfn = gt_cnt_read, .resetfn = arm_cp_reset_ignore,
},
{ .name = "CNTPCT_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 1,
.access = PL0_R, .type = ARM_CP_NO_MIGRATE | ARM_CP_IO,
.accessfn = gt_pct_access,
.readfn = gt_cnt_read, .resetfn = gt_cnt_reset, .readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
}, },
{ .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1, { .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1,
.access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO,
.accessfn = gt_vct_access, .accessfn = gt_vct_access,
.readfn = gt_cnt_read, .resetfn = arm_cp_reset_ignore,
},
{ .name = "CNTVCT_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 2,
.access = PL0_R, .type = ARM_CP_NO_MIGRATE | ARM_CP_IO,
.accessfn = gt_vct_access,
.readfn = gt_cnt_read, .resetfn = gt_cnt_reset, .readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
}, },
/* Comparison value, indicating when the timer goes off */ /* Comparison value, indicating when the timer goes off */
{ .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2, { .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2,
.access = PL1_RW | PL0_R, .access = PL1_RW | PL0_R,
.type = ARM_CP_64BIT | ARM_CP_IO, .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_MIGRATE,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval), .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
.resetvalue = 0, .accessfn = gt_ptimer_access, .resetfn = arm_cp_reset_ignore,
.accessfn = gt_ptimer_access, .writefn = gt_cval_write, .raw_writefn = raw_write,
},
{ .name = "CNTP_CVAL_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 2,
.access = PL1_RW | PL0_R,
.type = ARM_CP_IO,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
.resetvalue = 0, .accessfn = gt_vtimer_access,
.writefn = gt_cval_write, .raw_writefn = raw_write, .writefn = gt_cval_write, .raw_writefn = raw_write,
}, },
{ .name = "CNTV_CVAL", .cp = 15, .crm = 14, .opc1 = 3, { .name = "CNTV_CVAL", .cp = 15, .crm = 14, .opc1 = 3,
.access = PL1_RW | PL0_R, .access = PL1_RW | PL0_R,
.type = ARM_CP_64BIT | ARM_CP_IO, .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_MIGRATE,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval), .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
.resetvalue = 0, .accessfn = gt_vtimer_access, .resetfn = arm_cp_reset_ignore,
.accessfn = gt_vtimer_access, .writefn = gt_cval_write, .raw_writefn = raw_write,
},
{ .name = "CNTV_CVAL_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 2,
.access = PL1_RW | PL0_R,
.type = ARM_CP_IO,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
.resetvalue = 0, .accessfn = gt_vtimer_access,
.writefn = gt_cval_write, .raw_writefn = raw_write, .writefn = gt_cval_write, .raw_writefn = raw_write,
}, },
REGINFO_SENTINEL REGINFO_SENTINEL