# HG changeset patch # User Paul Boddie # Date 1435093699 -7200 # Node ID beb796ba8f2995ea79834f5ef936971b4cf39825 # Parent 5151ff3c7a768b74df545dfaaa9f552bd700eb8b Attempted to add support for interrupts, although this does not currently work. Some handlers have been added, and minimal handlers to branch to them should be installed in the appropriate addresses utilised by the CPU. The program itself should gradually plot the test pattern but be interrupted and configured to draw clear regions periodically. diff -r 5151ff3c7a76 -r beb796ba8f29 stage2/Makefile --- a/stage2/Makefile Tue Jun 23 23:05:00 2015 +0200 +++ b/stage2/Makefile Tue Jun 23 23:08:19 2015 +0200 @@ -30,7 +30,7 @@ CFLAGS = -O2 -Wall \ -fno-unit-at-a-time -fno-zero-initialized-in-bss \ - -ffreestanding -fno-hosted -fno-builtin \ + -ffreestanding -fno-hosted -fno-builtin -fno-pic \ -march=mips32 \ -I../include LDFLAGS = -nostdlib -EL @@ -62,8 +62,8 @@ # Ordering of objects is important and cannot be left to replacement rules. -SRC = head2.S stage2.c cpu.c lcd.c jzlcd.c board.c $(BOARD_SRC) -OBJ = head2.o stage2.o cpu.o lcd.o jzlcd.o board.o $(BOARD_OBJ) +SRC = head2.S entry.S handlers.S stage2.c cpu.c lcd.c jzlcd.c board.c irq.c $(BOARD_SRC) +OBJ = head2.o entry.o handlers.o stage2.o cpu.o lcd.o jzlcd.o board.o irq.o $(BOARD_OBJ) .PHONY: all clean distclean diff -r 5151ff3c7a76 -r beb796ba8f29 stage2/board-minipc.c --- a/stage2/board-minipc.c Tue Jun 23 23:05:00 2015 +0200 +++ b/stage2/board-minipc.c Tue Jun 23 23:08:19 2015 +0200 @@ -62,7 +62,7 @@ unsigned long lastdec; /* - * timer without interrupts + * Timer without interrupts. */ int timer_init(void) @@ -72,12 +72,25 @@ __ost_set_count(TIMER_CHAN, TIMER_FDATA); __ost_enable_channel(TIMER_CHAN); + __cpm_start_ost(); + lastdec = TIMER_FDATA; timestamp = 0; return 0; } +/* Timer interrupt activation. */ + +void timer_init_irq(void) +{ + __ost_enable_interrupt(TIMER_CHAN); + /* NOTE: Need flag clearing? */ + __intc_unmask_irq(TIMER_CHAN_IRQ); +} + +/* Board startup detection. */ + int is_started(void) { return REG_CPM_MSCR != 0; diff -r 5151ff3c7a76 -r beb796ba8f29 stage2/board-nanonote.c --- a/stage2/board-nanonote.c Tue Jun 23 23:05:00 2015 +0200 +++ b/stage2/board-nanonote.c Tue Jun 23 23:08:19 2015 +0200 @@ -112,11 +112,12 @@ unsigned long lastdec; /* - * timer without interrupts + * Timer without interrupts. */ void timer_init(void) { + __tcu_disable_pwm_output(TIMER_CHAN); __tcu_select_extalclk(TIMER_CHAN); __tcu_select_clk_div256(TIMER_CHAN); __tcu_set_count(TIMER_CHAN, 0); @@ -128,10 +129,23 @@ __tcu_start_timer_clock(TIMER_CHAN); __tcu_start_counter(TIMER_CHAN); + __cpm_start_tcu(); + lastdec = 0; timestamp = 0; } +/* Timer interrupt activation. */ + +void timer_init_irq(void) +{ + __tcu_unmask_full_match_irq(TIMER_CHAN); + __tcu_clear_full_match_flag(TIMER_CHAN); + __intc_unmask_irq(TIMER_CHAN_IRQ); +} + +/* Board startup detection. */ + int is_started(void) { return REG_CPM_CLKGR != 0; diff -r 5151ff3c7a76 -r beb796ba8f29 stage2/board-specific.h --- a/stage2/board-specific.h Tue Jun 23 23:05:00 2015 +0200 +++ b/stage2/board-specific.h Tue Jun 23 23:08:19 2015 +0200 @@ -7,6 +7,7 @@ void cpm_init(void); void rtc_init(void); void timer_init(void); +void timer_init_irq(void); int is_started(void); #endif /* __BOARD_SPECIFIC_H__ */ diff -r 5151ff3c7a76 -r beb796ba8f29 stage2/board.h --- a/stage2/board.h Tue Jun 23 23:05:00 2015 +0200 +++ b/stage2/board.h Tue Jun 23 23:08:19 2015 +0200 @@ -6,17 +6,18 @@ void udelay(unsigned long usec); unsigned long get_memory_size(void); +#define TIMER_HZ CONFIG_SYS_HZ +#define TIMER_CHAN 0 +#define TIMER_FDATA 0xffff /* timer full data value, limited to 16 bits */ + #ifdef CONFIG_CPU_JZ4730 #include "jz4730.h" -#define READ_TIMER __ost_get_count(TIMER_CHAN) /* macro to read the 32 bit timer */ -#define TIMER_FDATA 0xffffffff /* timer full data value */ +#define READ_TIMER __ost_get_count(TIMER_CHAN) /* macro to read the 32 bit timer */ +#define TIMER_CHAN_IRQ IRQ_OST0 #else #include "jz4740.h" -#define READ_TIMER REG_TCU_TCNT(TIMER_CHAN) /* macro to read the 16 bit timer */ -#define TIMER_FDATA 0xffff /* timer full data value */ +#define READ_TIMER REG_TCU_TCNT(TIMER_CHAN) /* macro to read the 16 bit timer */ +#define TIMER_CHAN_IRQ IRQ_TCU0 #endif -#define TIMER_HZ CONFIG_SYS_HZ -#define TIMER_CHAN 0 - #endif /* __BOARD_H__ */ diff -r 5151ff3c7a76 -r beb796ba8f29 stage2/entry.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage2/entry.S Tue Jun 23 23:08:19 2015 +0200 @@ -0,0 +1,48 @@ +/* + * Interrupt handling support. + * + * Copyright (C) 2015 Paul Boddie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +.text +.extern real_exception_handler +.globl _tlb_entry +.globl _exc_entry +.globl _irq_entry +.globl _end_entries +.set noreorder + +_tlb_entry: + lui $k0, %hi(real_exception_handler) + ori $k0, $k0, %lo(real_exception_handler) + jr $k0 + nop + +_exc_entry: + lui $k0, %hi(real_exception_handler) + ori $k0, $k0, %lo(real_exception_handler) + jr $k0 + nop + +_irq_entry: + lui $k0, %hi(real_exception_handler) + ori $k0, $k0, %lo(real_exception_handler) + jr $k0 + nop + +_end_entries: + +.set reorder diff -r 5151ff3c7a76 -r beb796ba8f29 stage2/handlers.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage2/handlers.S Tue Jun 23 23:08:19 2015 +0200 @@ -0,0 +1,168 @@ +/* + * Handler routines. + * + * Copyright (C) 2008 by Maurus Cuelenaere + * Copyright (C) 2015 Paul Boddie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +.text +.extern irq_handle +.globl real_exception_handler +.set noreorder +.set noat + +#define C0_STATUS $12 +#define C0_CAUSE $13 +#define C0_EPC $14 +#define C0_CONFIG $16 +#define S_CauseExcCode 2 +#define M_CauseExcCode (0x1f << S_CauseExcCode) + +real_exception_handler: + addiu $sp, -0x80 + sw $ra, 0($sp) + sw $fp, 4($sp) + sw $gp, 8($sp) + sw $t9, 0xC($sp) + sw $t8, 0x10($sp) + sw $s7, 0x14($sp) + sw $s6, 0x18($sp) + sw $s5, 0x1C($sp) + sw $s4, 0x20($sp) + sw $s3, 0x24($sp) + sw $s2, 0x28($sp) + sw $s1, 0x2C($sp) + sw $s0, 0x30($sp) + sw $t7, 0x34($sp) + sw $t6, 0x38($sp) + sw $t5, 0x3C($sp) + sw $t4, 0x40($sp) + sw $t3, 0x44($sp) + sw $t2, 0x48($sp) + sw $t1, 0x4C($sp) + sw $t0, 0x50($sp) + sw $a3, 0x54($sp) + sw $a2, 0x58($sp) + sw $a1, 0x5C($sp) + sw $a0, 0x60($sp) + sw $v1, 0x64($sp) + sw $v0, 0x68($sp) + sw $1, 0x6C($sp) + mflo $k0 + nop + sw $k0, 0x70($sp) + mfhi $k0 + nop + sw $k0, 0x74($sp) + mfc0 $k0, C0_STATUS + sll $zero, 1 + sll $zero, 1 + sll $zero, 1 + sll $zero, 1 + sw $k0, 0x78($sp) + mfc0 $k0, C0_EPC + sll $zero, 1 + sll $zero, 1 + sll $zero, 1 + sll $zero, 1 + sw $k0, 0x7C($sp) + + li $k1, M_CauseExcCode + mfc0 $k0, C0_CAUSE + and $k0, $k1 + beq $zero, $k0, _int + nop + j _exception + nop + +_int: + /* Invoke the handler. */ + + jal irq_handle + nop + j _exception_return + +_exception: + move $a0, $sp + mfc0 $a1, C0_CAUSE + sll $zero, 1 + sll $zero, 1 + sll $zero, 1 + sll $zero, 1 + mfc0 $a2, C0_EPC + sll $zero, 1 + sll $zero, 1 + sll $zero, 1 + sll $zero, 1 + /* jal exception_handler */ + j _exception_return + nop + +_exception_return: + lw $ra, 0($sp) + lw $fp, 4($sp) + lw $gp, 8($sp) + lw $t9, 0xC($sp) + lw $t8, 0x10($sp) + lw $s7, 0x14($sp) + lw $s6, 0x18($sp) + lw $s5, 0x1C($sp) + lw $s4, 0x20($sp) + lw $s3, 0x24($sp) + lw $s2, 0x28($sp) + lw $s1, 0x2C($sp) + lw $s0, 0x30($sp) + lw $t7, 0x34($sp) + lw $t6, 0x38($sp) + lw $t5, 0x3C($sp) + lw $t4, 0x40($sp) + lw $t3, 0x44($sp) + lw $t2, 0x48($sp) + lw $t1, 0x4C($sp) + lw $t0, 0x50($sp) + lw $a3, 0x54($sp) + lw $a2, 0x58($sp) + lw $a1, 0x5C($sp) + lw $a0, 0x60($sp) + lw $v1, 0x64($sp) + lw $v0, 0x68($sp) + lw $1, 0x6C($sp) + lw $k0, 0x70($sp) + mtlo $k0 + nop + lw $k0, 0x74($sp) + mthi $k0 + nop + lw $k0, 0x78($sp) + mtc0 $k0, C0_STATUS + nop + sll $zero, 1 + sll $zero, 1 + sll $zero, 1 + sll $zero, 1 + lw $k0, 0x7C($sp) + mtc0 $k0, C0_EPC + nop + sll $zero, 1 + sll $zero, 1 + sll $zero, 1 + sll $zero, 1 + addiu $sp, 0x80 + eret + nop + +.set reorder +.set at diff -r 5151ff3c7a76 -r beb796ba8f29 stage2/head2.S --- a/stage2/head2.S Tue Jun 23 23:05:00 2015 +0200 +++ b/stage2/head2.S Tue Jun 23 23:08:19 2015 +0200 @@ -20,13 +20,81 @@ * along with this program. If not, see . */ - .text - .extern c_main - - .globl _start - .set noreorder +.text +.extern c_main +.extern _tlb_entry +.extern _exc_entry +.extern _irq_entry +.extern _end_entries +.globl _start +.set noreorder + _start: - add $29, $20, 0x3ffff0 /* sp */ - j c_main + /* Initialise the stack. */ + + la $sp, 0x80080000 + + /* Copy TLB handling instructions. */ + + lui $t0, %hi(_tlb_entry) /* start */ + ori $t0, $t0, %lo(_tlb_entry) + li $t1, 0x80000000 + lui $t2, %hi(_exc_entry) /* end */ + ori $t2, $t2, %lo(_exc_entry) +_tlb_copy: + lw $t3, 0($t0) + addiu $t0, $t0, 4 + sw $t3, 0($t1) + bne $t0, $t2, _tlb_copy + addiu $t1, $t1, 4 /* executed in delay slot before branch */ + + /* Copy exception handling instructions. */ + + move $t0, $t2 /* start */ + li $t1, 0x80000180 + lui $t2, %hi(_irq_entry) /* end */ + ori $t2, $t2, %lo(_irq_entry) +_exc_copy: + lw $t3, 0($t0) + addiu $t0, $t0, 4 + sw $t3, 0($t1) + bne $t0, $t2, _exc_copy + addiu $t1, $t1, 4 /* executed in delay slot before branch */ + + /* Copy IRQ handling instructions. */ - .set reorder + move $t0, $t2 /* start */ + li $t1, 0x80000200 + lui $t2, %hi(_end_entries) /* end */ + ori $t2, $t2, %lo(_end_entries) +_irq_copy: + lw $t3, 0($t0) + addiu $t0, $t0, 4 + sw $t3, 0($t1) + bne $t0, $t2, _irq_copy + addiu $t1, $t1, 4 /* executed in delay slot before branch */ + + /* Initialise interrupts. */ + + mfc0 $t3, $12 /* CP0_STATUS */ + nop + li $t4, 0xffbf00e0 /* BEV = 0 (not bootloader vectors); IM = disable all */ + and $t3, $t3, $t4 /* ... KSU = 0 (kernel mode); ERL = 0; EXL = 0; IE = 0 */ + li $t4, 0x0000ff04 /* IM = enable IM7..IM0; ERL = 1 (set by default) */ + or $t3, $t3, $t4 + mtc0 $t3, $12 + nop + + li $t3, 0x00800000 /* IV = 1 (use 0x80000200 for interrupts) */ + mtc0 $t3, $13 /* CP0_CAUSE */ + nop + + mtc0 $zero, $15 /* CP0_EBASE (should be zero anyway) */ + nop + + /* Start the program. */ + + j c_main + nop + +.set reorder diff -r 5151ff3c7a76 -r beb796ba8f29 stage2/irq.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage2/irq.c Tue Jun 23 23:08:19 2015 +0200 @@ -0,0 +1,95 @@ +/* + * Interrupt handling. + * + * Copyright (C) 2015 Paul Boddie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "board-specific.h" +#include "board.h" +#include "lcd.h" +#include "jzlcd.h" +#include "cpu.h" + +extern vidinfo_t panel_info; +static unsigned short pixel_type; +static unsigned short x, y; +extern unsigned long lastdec; + +void next_pixel() +{ + x++; + if (x >= panel_info.vl_col) { + x = 0; + y++; + if (y >= panel_info.vl_row) + y = 0; + } +} + +/* Tasks. */ + +void plot_pattern() +{ + while (1) { + if (pixel_type) + test_pixel(x, y); + else + clear_pixel(x, y); + next_pixel(); + udelay(100); + } +} + +/* Initialisation and handling. */ + +void irq_init() +{ + timer_init_irq(); + x = 0; y = 0; pixel_type = 1; + enable_interrupts(); +} + +void irq_handle() +{ + unsigned short i; + + /* Check interrupt identity. */ + + if (REG_INTC_IPR & (1 << TIMER_CHAN_IRQ)) { + + /* Update the pixel type. */ + + pixel_type = 1 - pixel_type; + + /* Clear interrupt status. */ + + __intc_ack_irq(TIMER_CHAN_IRQ); + __tcu_clear_full_match_flag(TIMER_CHAN); + + /* Handle other interrupts, anyway. */ + + } else { + for (i = 0; i < 32; i++) { + if (REG_INTC_IPR & (1 << i)) + __intc_ack_irq(i); + } + } +} + +void start_task() +{ + plot_pattern(); +} diff -r 5151ff3c7a76 -r beb796ba8f29 stage2/irq.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage2/irq.h Tue Jun 23 23:08:19 2015 +0200 @@ -0,0 +1,9 @@ +#ifndef __IRQ_H__ +#define __IRQ_H__ + +/* Initialisation functions. */ + +void irq_init(void); +void start_task(void); + +#endif /* __IRQ_H__ */ diff -r 5151ff3c7a76 -r beb796ba8f29 stage2/lcd.c --- a/stage2/lcd.c Tue Jun 23 23:05:00 2015 +0200 +++ b/stage2/lcd.c Tue Jun 23 23:08:19 2015 +0200 @@ -32,35 +32,60 @@ #include "board.h" extern vidinfo_t panel_info; +static void *lcd_base; + +void test_pixel(unsigned short h, unsigned short v) +{ + unsigned short v_max = panel_info.vl_row; + unsigned short h_max = panel_info.vl_col; + u32 *pix = (u32 *)lcd_base + v * h_max + h; + + /* NOTE: Code assumes 32 bits/pixel. */ + + *pix = ( + (((255 * (h_max - h)) / (h_max - 1)) << 16) + + ((((255 * h) / (h_max - 1) + (255 * (v_max - v)) / (v_max - 1)) / 2) << 8) + + ((255 * v) / (v_max - 1)) + ); +} + +void clear_pixel(unsigned short h, unsigned short v) +{ + unsigned short h_max = panel_info.vl_col; + u32 *pix = (u32 *)lcd_base + v * h_max + h; + + *pix = 0; +} static void test_pattern(void *lcd_base) { unsigned short v_max = panel_info.vl_row; unsigned short h_max = panel_info.vl_col; unsigned short v, h; + + for (v = 0; v < v_max; v += 1) { + for (h = 0; h < h_max; h += 1) { + test_pixel(h, v); + } + } +} + +void lcd_clear(void *lcd_base) +{ + unsigned short v_max = panel_info.vl_row; + unsigned short h_max = panel_info.vl_col; + unsigned short v, h; u32 *pix = (u32 *)lcd_base; - /* WARNING: Code silently assumes 32 bit/pixel */ for (v = 0; v < v_max; v += 1) { for (h = 0; h < h_max; h += 1) { - *pix++ = ( - (((255 * (h_max - h)) / (h_max - 1)) << 16) + - ((((255 * h) / (h_max - 1) + (255 * (v_max - v)) / (v_max - 1)) / 2) << 8) + - ((255 * v) / (v_max - 1)) - ); + *pix++ = 0; } } } -void lcd_clear(void *lcd_base) -{ - test_pattern(lcd_base); -} - /* LCD initialisation. */ -static void *lcd_base; - void lcd_init(void) { __lcd_display_pin_init(); diff -r 5151ff3c7a76 -r beb796ba8f29 stage2/lcd.h --- a/stage2/lcd.h Tue Jun 23 23:05:00 2015 +0200 +++ b/stage2/lcd.h Tue Jun 23 23:08:19 2015 +0200 @@ -5,4 +5,9 @@ void lcd_init(void); +/* Output functions. */ + +void test_pixel(unsigned short h, unsigned short v); +void clear_pixel(unsigned short h, unsigned short v); + #endif /* __LCD_H__ */ diff -r 5151ff3c7a76 -r beb796ba8f29 stage2/stage2.c --- a/stage2/stage2.c Tue Jun 23 23:05:00 2015 +0200 +++ b/stage2/stage2.c Tue Jun 23 23:08:19 2015 +0200 @@ -20,12 +20,16 @@ #include "board-specific.h" +#include "irq.h" #include "lcd.h" +#include "cpu.h" void c_main(void) { volatile int started; + flush_cache_all(); + /* The actual work. */ started = is_started(); @@ -36,5 +40,6 @@ timer_init(); } lcd_init(); - while (1); + irq_init(); + start_task(); }