Hello all,
well, this is the promised timer setup code that obviously works on my
DS5000/200 and produces interrupts ... I still haven't got the interrupt
handler to return where it should, maybe Paul can help out with that.
I still know far too less about the R3000. Btw., I had the idea of trying
the interrupt stuff in SimOS, but I wasn't able to find it. Any hints ?
[Paul, I managed to find a DS5000/25 for Linux development, so I now have a
5000/200, a 5000/120 and the 5000/25 - nice :). Do you have any docs for the
Personal Decstation ?]
Warning: This code is ugly, probably doesn't belong in that place and
isn't a diff against Paul's 2.0.7 kernel :-( ... sorry, this is
all I was able to produce so far.
[arch/mips/setup.c]
dec_irq_setup(void)
{
long *interrupt=0;
volatile unsigned char *loc;
volatile unsigned long *lloc;
unsigned char leds;
printk("Initialising timer ...\n");
/* these obviously should go into some header file ... */
#define RTC_base (0xa0000000+0x1fc00000+0x280000)
#define RTC_sec RTC_base + 0x00 /* seconds, 00..59 */
#define RTC_alms RTC_base + 0x04 /* alarm seconds, 00..59 */
#define RTC_min RTC_base + 0x08 /* minutes, 00..59 */
#define RTC_almm RTC_base + 0x0c /* alarm minutes, 00..59 */
#define RTC_hour RTC_base + 0x10 /* hours, 00..23 */
#define RTC_almh RTC_base + 0x14 /* alarm hours, 00..23 */
#define RTC_dow RTC_base + 0x18 /* day of week, 1..7 */
#define RTC_day RTC_base + 0x1c /* day of month, 1..31 */
#define RTC_mon RTC_base + 0x20 /* month, 1..12 */
#define RTC_year RTC_base + 0x24 /* year, 00.99 */
/* make sure years >=0 and */
/* < 70 are mapped to 20xx !! */
#define RTC_rega RTC_base + 0x28 /* Register A */
#define RTC_regb RTC_base + 0x2c /* Register B */
#define RTC_regc RTC_base + 0x30 /* Register C */
#define RTC_regd RTC_base + 0x34 /* Register D */
#define RTC_ram RTC_base + 0x38 /* Base of BBU RAM */
/* RTC Control Register A */
#define RTC_REGA_UIP 0x80 /* RTC Update in Progress */
#define RTC_REGA_DVX 0x70 /* RTC Timebase Divisor */
/* MUST BE 010 */
#define RTC_REGA_DSX 0x07 /* Rate select */
/* Divisors for RTC_REGA_DSX --- add more on demand ... */
#define DSX_none 0x00 /* none */
#define DSX_1ms 0x07 /* ca. 1 ms */
#define DSX_2ms 0x08 /* ca. 2 ms */
#define DSX_500ms 0x0F /* ca. 500 ms */
/* INIT REGA TO %00100111 */
#define REGA_INIT ((0x20) + DSX_500ms)
/* RTC Control Register B */
#define RTC_REGB_SET 0x80 /* set time */
#define RTC_REGB_PIE 0x40 /* periodic irq enable ! */
#define RTC_REGB_AIE 0x20 /* not used, must be zero */
#define RTC_REGB_UIE 0x10 /* update irq enable */
#define RTC_REGB_SQWE 0x08 /* not used, must be zero */
#define RTC_REGB_DM 0x04 /* date mode binary[1]/bcd[0] */
#define RTC_REGB_2412 0x02 /* Hours Format 24[1]/12[0] */
#define RTC_REGB_DSE 0x01 /* daylight svgs enable, =0 */
printk("Setting up timer interrupt ... reg a\n");
/* Set Reg A to 1ms */
loc=(unsigned char *)RTC_rega;
*loc=(unsigned char)REGA_INIT;
printk("Setting up timer interrupt ... reg b\n");
/* Set Reg B to enable IRQs */
loc=(unsigned char *)RTC_regb;
*loc=(unsigned char)(RTC_REGB_PIE|RTC_REGB_UIE);
/* You can insert code to spin diag LEDs here ! */
/* - see below - */
/* WARNING :
This actually reads out time and date information, but manages
to mess up somehow with the RTC so that I get a ?RTC error on next
reboot and time/date information is reset to 0.0h 1.1.1972 (?) !! */
printk("Getting date and time information ...\n");
loc=(unsigned char *)RTC_day;
printk("Day : %d\n", (int)(*loc));
loc=(unsigned char *)RTC_mon;
printk("Month : %d\n", (int)(*loc));
loc=(unsigned char *)RTC_year;
printk("Year : %d\n", (int)(*loc));
loc=(unsigned char *)RTC_hour;
printk("Hour : %d\n", (int)(*loc));
loc=(unsigned char *)RTC_min;
printk("Min : %d\n", (int)(*loc));
printk("Initialising IRQ's ...\n");
decstation_setup_int();
/* decstation_setup_int resides in dec_setup.S --- I wasn't able
to initialise IRQ's via the __asm__ directive ... why ? */
}
-----
I'm enabling interrupts via the following code sequence :
[decstation_setup.S]
decstation_setup_int:
NESTED(decstation_setup_int, FR_SIZE, ra)
.set noat
mfc0 k0, CP0_STATUS
ori k0,0x0f15
mtc0 k0, CP0_STATUS
END(decstation_setup_int)
-----
I inserted lots of pmax_printf calls in the interrupt handling code, and it
never seems to call an interrupt routine (which should printk some panic
message ...). Basically, it runs up to
lw t0, (t1)
jr t0
nop
in dec_entry.S which is supposed to call the interrupt handler, right ?
Failing that, I simply tried to increment the jiffies counter in
head.S in except_vec3 via
NESTED(except_vec3, 0, sp)
.set noat
SAVE_ALL
lw t0, jiffies
add t0, 1
sw t0, jiffies
just to get a BogoMips number :-) and return via
mfc0 k0, CP0_EPC
nop
jr k0
rfe
as Ralf proposed in a previous mail.
Well, this code doesn't return where is should. I get periodic interrupts,
but the kernel code refuses to run any further.
There seem to be two errors in my code :
1. I used the t0 register. I'm not sure if I should ...
2. SAVE_ALL obviously saves all registers, but I don't restore them.
I tried a RESTORE_ALL just before the mfc0 k0, CP0_EPC , but that didn't
work either. The stack seems to get corrupted, as after some minutes the
video memory of my CX board is overwritten with regular patterns :-)
Btw., I also managed to get the diag LED's light as I want. This might be
a debugging aid. After setting up the timer to count every 500ms, I got a
nice running light on the diag LEDs : (see comment in dec_irq_setup)
while (1) {
long i=0;
lloc=(unsigned long *)0xbff00000;
loc=(unsigned char *)RTC_regc;
*lloc=(unsigned long)0x00ff0000+(0xff-(leds));
while ((*loc&0xc0) == 0);
leds *= 2;
if (leds == 0) leds =1;
};
regards,
Michael Engel (engel@unix-ag.uni-siegen.de)
|