rtc: robust interrupt handling and SH3 compatibility

This commit changes the interrupt handler arrangement to support the PRI
interrupt on SH3 (a gap is needed between 0xaa0 and its helper).

It also introduces the use of the _gint_inth_callback function for the
callback, which provides dynamic TLB during the interrupt, and revealed
a bug about IMASK not being set automatically on SH3.

Finally, it sets the interrupt settings of the RTC more conservatively,
by wiping RCR1 and the carry, alarm and periodic interrupt flags during
initialization and context restoration.
This commit is contained in:
Lephe 2020-07-19 20:06:50 +02:00
parent a06213ca11
commit 0622928f22
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
4 changed files with 30 additions and 17 deletions

View file

@ -156,13 +156,13 @@ _gint_inth_7705:
The VBR interrupt space on SH3 is laid out as follows:
VBR offset SH3 events Description
----------------------------------------------------------------
-------------------------------------------------------------------
0x200 400 420 440 --- TMU0, TMU1, TMU2 and a helper
0x280 f00 --- --- --- ETMU0, ETMU1, ETMU2 and a helper
0x300 4a0 --- RTC Periodic Interrupt and a helper
----------------------------------------------------------------
0x300 4a0 [ ] --- RTC Periodic Interrupt, gap and helper
-------------------------------------------------------------------
0x600 --- --- Entry gate
----------------------------------------------------------------
-------------------------------------------------------------------
There is space for 16 gates at VBR + 0x200 so the VBR currently ends after
the interrupt entry gate at VBR + 0x640. */

View file

@ -155,6 +155,7 @@ static const uint16_t sh3_vbr_map[] = {
0xc40, /* ETMU2 underflow (used as helper on SH3) */
0xc60, /* (gint custom: ETMU helper) */
0xaa0, /* RTC Periodic Interrupt */
1, /* (Filler to maintain the gap between 0xaa0 and 0xae0) */
0xae0, /* (gint custom: RTC helper) */
0
};

View file

@ -14,17 +14,15 @@
_inth_rtc_pri:
/* Invoke the callback function with its argument */
sts.l pr, @-r15
mov.l 1f, r0
mov.l 2f, r4
mov.l .gint_inth_callback, r0
mov.l 1f, r4
mov.l 2f, r5
jsr @r0
nop
/* Save the return value */
mov r0, r3
/* Prepare to clear the interrupt flag */
mov.l 3f, r1
/* Jump to another gate to finish the work:
- 0xc is the size of storage below
- 0x20 is the size of the gap before next gate (alarm interrupt) */
@ -34,12 +32,15 @@ _inth_rtc_pri:
1: .long 0 /* Callback function: edited dynamically */
2: .long 0 /* Argument to callback function */
3: .long 0xa413fede /* RCR2 address, edited at startup on SH3 */
.gint_inth_callback:
.long _gint_inth_callback
_inth_rtc_pri_helper:
.clear:
/* Clear the interrupt flag */
mov.l .RCR2, r1
mov.b @r1, r0
tst #0x80, r0
and #0x7f, r0
@ -56,5 +57,6 @@ _inth_rtc_pri_helper:
lds.l @r15+, pr
rts
nop
nop
.zero 8
.RCR2: .long 0xa413fede /* RCR2 address, edited at startup on SH3 */

View file

@ -25,7 +25,6 @@ static rtc_t *RTC = &SH7305_RTC;
GBSS static struct {
void *function;
uint32_t arg;
volatile uint8_t *RCR2;
} GPACKED(4) *timer_params;
//---
@ -144,6 +143,12 @@ static void driver_sh3(void)
static void init(void)
{
/* Disable the carry and alarm interrupts (they share their IPR bits
with the periodic interrupt, which we want to enable) */
RTC->RCR1.byte = 0;
/* Clear the periodic interrupt flag */
RTC->RCR2.PEF = 0;
/* Interrupt handlers provided by rtc/inth.s */
extern void inth_rtc_pri(void);
extern void inth_rtc_pri_helper(void);
@ -154,11 +159,15 @@ static void init(void)
h1 = gint_inthandler(0xae0, inth_rtc_pri_helper, 32);
timer_params = h0 + 20;
timer_params->RCR2 = &RTC->RCR2.byte;
/* Disable the periodic interrupt for now, but give it priority 5 */
volatile uint8_t **RCR2_pointer = h1 + 28;
*RCR2_pointer = &RTC->RCR2.byte;
/* Disable the RTC interrupts for now. Give them priority 1; higher
priorities cause freezes when going back to the system on SH3
(TODO: Find out about the RTC interrupt problem on SH3) */
RTC->RCR2.PES = RTC_NONE;
intc_priority(INTC_RTC_PRI, 5);
intc_priority(INTC_RTC_PRI, 1);
}
//---
@ -183,8 +192,9 @@ static void ctx_save(void *buf)
static void ctx_restore(void *buf)
{
ctx_t *ctx = buf;
RTC->RCR1.byte = ctx->RCR1;
RTC->RCR2.byte = ctx->RCR2;
RTC->RCR1.byte = ctx->RCR1 & 0x18;
RTC->RCR2.byte = ctx->RCR2 & 0x7f;
}
//---