[arch][mips] configure the timer more generically

This commit is contained in:
Travis Geiselbrecht
2015-12-04 18:53:24 -08:00
parent a36b8f928a
commit a0e342dbbd
6 changed files with 97 additions and 32 deletions

View File

@@ -23,6 +23,7 @@
#include <trace.h>
#include <debug.h>
#include <stdint.h>
#include <bits.h>
#include <arch/mips.h>
#include <platform.h>
@@ -32,32 +33,31 @@ void arch_early_init(void)
{
LTRACE;
#if 0
/* enable i/d cache */
uint32_t val = mb_read_msr();
val |= (1 << (31 - 26)) | (1 << (31 - 24));
mb_write_msr(val);
#endif
/* configure the vector table */
uint32_t temp = mips_read_c0_status();
temp &= ~(1<<22); /* unset BEV, which moves vectors to 0x80000000 */
temp &= ~(1<<2); /* clear ERL */
/* unmask all of the irq handlers */
temp |= (1<<8); // IM0
temp |= (1<<9); // IM1
temp |= (1<<10); // IM2
temp |= (1<<11); // IM3
temp |= (1<<12); // IM4
temp |= (1<<13); // IM5
temp |= (1<<14); // IM6
temp |= (1<<15); // IM7
temp |= (1<<16); // IM8
temp |= (1<<18); // IM9 (note the bit gap)
/* mask all of the irq handlers */
temp &= ~(1<<8); // IM0
temp &= ~(1<<9); // IM1
temp &= ~(1<<10); // IM2
temp &= ~(1<<11); // IM3
temp &= ~(1<<12); // IM4
temp &= ~(1<<13); // IM5
temp &= ~(1<<14); // IM6
temp &= ~(1<<15); // IM7
temp &= ~(1<<16); // IM8
temp &= ~(1<<18); // IM9 (note the bit gap)
mips_write_c0_status(temp);
/* set ebase */
mips_write_c0_ebase(MEMBASE);
/* make sure we take exceptions in 32bit mips mode */
mips_write_c0_config3(mips_read_c0_config3() & ~(1<<16));
/* set vectored mode */
temp = mips_read_c0_intctl();
temp &= ~(0b1111 << 5);
@@ -86,8 +86,13 @@ void arch_init(void)
printf("\tconfig6 0x%x\n", mips_read_c0_config6());
printf("\tconfig7 0x%x\n", mips_read_c0_config7());
printf("\tstatus 0x%x\n", mips_read_c0_status());
printf("\tintctl 0x%x\n", mips_read_c0_intctl());
uint32_t intctl = mips_read_c0_intctl();
printf("\tintctl 0x%x\n", intctl);
printf("\t\tIPTI 0x%lx\n", BITS_SHIFT(intctl, 31, 29));
printf("\t\tIPPCI 0x%lx\n", BITS_SHIFT(intctl, 28, 26));
printf("\t\tIPFDC 0x%lx\n", BITS_SHIFT(intctl, 25, 23));
printf("\tsrsctl 0x%x\n", mips_read_c0_srsctl());
printf("\tebase 0x%x\n", mips_read_c0_ebase());
printf("\tcount 0x%x\n", mips_read_c0_count());
printf("\tcompare 0x%x\n", mips_read_c0_compare());
@@ -106,6 +111,28 @@ void arch_chain_load(void *entry, ulong arg0, ulong arg1, ulong arg2, ulong arg3
PANIC_UNIMPLEMENTED;
}
void mips_enable_irq(uint num)
{
uint32_t temp = mips_read_c0_status();
if (num < 9) {
temp |= (1 << (num + 8));
} else if (num == 9) {
temp |= (1 << 18);
}
mips_write_c0_status(temp);
}
void mips_disable_irq(uint num)
{
uint32_t temp = mips_read_c0_status();
if (num < 9) {
temp &= ~(1 << (num + 8));
} else if (num == 9) {
temp &= ~(1 << 18);
}
mips_write_c0_status(temp);
}
/* unimplemented cache operations */
void arch_disable_cache(uint flags) { PANIC_UNIMPLEMENTED; }
void arch_enable_cache(uint flags) { PANIC_UNIMPLEMENTED; }

View File

@@ -60,13 +60,18 @@ void mips_irq(struct mips_iframe *iframe, uint num)
num, iframe->epc, iframe->status, mips_read_c0_status());
enum handler_return ret = INT_NO_RESCHEDULE;
switch (num) {
case 2: // XXX qemu specific
ret = platform_irq(iframe, num);
break;
case 7: // builtin timer
ret = mips_timer_irq();
break;
// figure out which interrupt the timer is set to
uint32_t ipti = BITS_SHIFT(mips_read_c0_intctl(), 31, 29);
if (ipti >= 2 && ipti == num) {
// builtin timer
ret = mips_timer_irq();
#if PLATFORM_QEMU_MIPS
} else if (num == 2) {
ret = platform_irq(iframe, num);
#endif
} else {
panic("mips: unhandled irq\n");
}
KEVLOG_IRQ_EXIT(num);

View File

@@ -59,6 +59,8 @@ GEN_CP_REG_FUNCS(c0_srsmap2, 12, 5)
GEN_CP_REG_FUNCS(c0_cause, 13, 0)
GEN_CP_REG_FUNCS(c0_epc, 14, 0)
GEN_CP_REG_FUNCS(c0_prid, 15, 0)
GEN_CP_REG_FUNCS(c0_ebase, 15, 1)
GEN_CP_REG_FUNCS(c0_cdmmbase, 15, 2)
GEN_CP_REG_FUNCS(c0_config, 16, 0)
GEN_CP_REG_FUNCS(c0_config1, 16, 1)
GEN_CP_REG_FUNCS(c0_config2, 16, 2)
@@ -93,9 +95,14 @@ struct mips_iframe {
uint32_t cause;
uint32_t epc;
};
STATIC_ASSERT(sizeof(struct mips_iframe) == 88);
void mips_init_timer(uint32_t freq);
enum handler_return mips_timer_irq(void);
void mips_enable_irq(uint num);
void mips_disable_irq(uint num);
#endif // !ASSEMBLY
#define VECTORED_OFFSET_SHIFT 32

View File

@@ -30,7 +30,8 @@ WITH_LINKER_GC ?= 0
LITTLE_ENDIAN ?= 0
ifneq ($(LITTLE_ENDIAN),0)
GLOBAL_COMPILEFLAGS += -mlittle-endian
GLOBAL_COMPILEFLAGS += -EL
GLOBAL_ASFLAGS += -EL
GLOBAL_LDFLAGS += -EL
GLOBAL_MODULE_LDFLAGS += -EL
endif

View File

@@ -26,6 +26,7 @@
#include <debug.h>
#include <assert.h>
#include <stdint.h>
#include <bits.h>
#include <arch/ops.h>
#include <platform.h>
#include <platform/timer.h>
@@ -35,8 +36,8 @@
static volatile uint64_t ticks;
static volatile uint32_t last_compare_set;
static const uint32_t tick_rate = 100000000; // XXX qemu specific
static const uint32_t tick_rate_mhz = 100;
static uint32_t tick_rate;
static uint32_t tick_rate_mhz;
static lk_time_t tick_interval_ms;
static lk_bigtime_t tick_interval_us;
@@ -51,13 +52,15 @@ enum handler_return mips_timer_irq(void)
LTRACEF("compare 0x%x\n", mips_read_c0_compare());
/* reset it for the next interval */
retry:
ticks++;
last_compare_set += tick_interval;
uint32_t count = mips_read_c0_count();
if (unlikely(TIME_GT(count, last_compare_set))) {
/* if it took us too long to get to this irq, make sure it fires immediately */
printf("took too long to service timer irq! %u %u\n", count, last_compare_set);
mips_write_c0_compare(mips_read_c0_count() + tick_rate_mhz);
//printf("took too long to service timer irq! %u %u\n", count, last_compare_set);
goto retry;
//mips_write_c0_compare(mips_read_c0_count() + tick_rate_mhz);
} else {
mips_write_c0_compare(last_compare_set);
}
@@ -89,6 +92,9 @@ status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg
last_compare_set = now + tick_interval;
mips_write_c0_compare(last_compare_set);
// enable the counter
mips_write_c0_cause(mips_read_c0_cause() & ~(1<<27));
return NO_ERROR;
}
@@ -132,3 +138,18 @@ lk_bigtime_t current_time_hires(void)
return res;
}
void mips_init_timer(uint32_t freq)
{
tick_rate = freq;
tick_rate_mhz = freq / 1000000;
// disable the counter
mips_write_c0_cause(mips_read_c0_cause() | (1<<27));
// figure out which interrupt the timer is set to
uint32_t ipti = BITS_SHIFT(mips_read_c0_intctl(), 31, 29);
if (ipti >= 2) {
mips_enable_irq(ipti);
}
}

View File

@@ -21,13 +21,14 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <reg.h>
#include <sys/types.h>
#include <kernel/thread.h>
#include <platform.h>
#include <platform/interrupts.h>
#include <platform/debug.h>
#include <platform/timer.h>
#include <platform/qemu-mips.h>
#include <sys/types.h>
#include <arch/mips.h>
extern void platform_init_interrupts(void);
extern void platform_init_uart(void);
@@ -37,6 +38,9 @@ void platform_early_init(void)
{
platform_init_interrupts();
platform_init_uart();
mips_init_timer(100000000);
mips_enable_irq(2);
}
void platform_init(void)