linux-mips-fnet
[Top] [All Lists]

Timer setup code for DS5000/200

To: linux-mips@fnet.fr
Subject: Timer setup code for DS5000/200
From: Michael Engel <engel@unix-ag.uni-siegen.de>
Date: Sat, 30 Nov 1996 01:51:32 +0100 (MET)
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)

<Prev in Thread] Current Thread [Next in Thread>
  • Timer setup code for DS5000/200, Michael Engel <=