[arch][mips] configure the timer more generically
This commit is contained in:
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user