Update sreen driver and add fx9860 II driver

This commit is contained in:
Yann MAGNIN 2020-02-07 21:43:20 +01:00
parent 105eb7c482
commit 53a1ebf5a3
8 changed files with 229 additions and 122 deletions

View File

@ -26,7 +26,8 @@ extern void kvram_clr_str_area(int x, int y, int width, int height);
extern void printk(int x, int y, char const *str, ...);
// Hardware specific function (do not use !)
extern void t6k11_display(void *vram);
extern void t6k11_lcd_driver(void *vram);
extern void t6k11_variant_lcd_driver(uint8_t *vram);
//---
// Timer functions.

View File

@ -1,16 +1,158 @@
.global _t6k11_display
.type _t6k11_display, @function
.text
.global _t6k11_lcd_driver
.type _t6k11_lcd_driver, @function
.align 2
/*
** @proto: void _t6k11_lcd_driver(void *vram)
**
** @note:
** This function will display the vram on the screen.
** This is the T6K11 drivers, *DO NOT USE* this function if
** you are not absolutly sure that what you are doing.
**
** @register list:
** 0 - Display mode
** 1 - Counter mode
** 2 - Set analog control mode
** 3 - Set alternating signal mode
** 4 - Set X-address AND Set Y-address
** 5 - Set Z-address
** 6 - Contrast control
** 7 - Data Write AND Data Read
** 8 - Unknown, test mode only
** 9 - Unknown, test mode only
** 10 - Unknown, test mode only
** 11 - Unknown, test mode only
** 12 - D/A converter power control
** 13 - Unknown, test mode only.
** 14 - Unknown, test mode only.
** 15 - Unknown, test mode only.
**
*/
_t6k11_lcd_driver:
! To avoid reentrace with the Video
! RAM and I/O opetation, we need to
! display data using atomic operation.
! The next part *SHOULD* be exception save !
mov.l .sr_int_msk, r1 ! Get SR mask for interrupt blocking.
stc sr, r0 ! Save current SR register data.
mov r0, r2 ! Get SR register data.
or r1, r2 ! Set SR.BL = 1 and SR.IMASK = 0b1111
ldc r2, sr ! Update SR register
! Stack management
mov.l r8, @-r15 ! save r8 register.
mov.l r0, @-r15 ! save SR register.
! Get LCD register addresses.
mov.l .LCD_register_selector, r0 ! r0 = LCD register selector address.
mov.l .LCD_data_register, r1 ! r1 = LCD data register.
! Set the X-adress counter to up-mode.
! @note:
! The X-address counter is used
! for the row and the Y-addresss counter
! for the column.
mov #1, r2 ! r0 = counter mode register address.
mov.b r2, @r0 ! Select the counter register.
mov #1, r3 ! r0 = Y-address counter "Yup" mode.
mov.b r3, @r1 ! Set the Y-address counter register to "Yup" mode.
! "pre-generate" register data
! r0 - LCD register selector
! r1 - LCD data register
! r2 - X-address / Y-address counter register
! r3 - data write address
! r4 - vram
! r5 - row counter
! r6 - Y-address counter
! r7 - X-address counter
mov #4, r2 ! X-address / Y-address counter.
mov #7, r3 ! Data Write register
mov #64, r5 ! Row counter
mov #0, r6 ! Y-address counter (column, alway 0)
mov #192, r7 ! X-address counter (row, 192 = 0, see documentation)
row_loop:
! Select the X-address / Y-address counter.
mov.b r2, @r0 ! Select X/Y address counter register.
! Update X-address counter / Reset the Y-address counter
mov.b r7, @r1 ! Set X-address counter to current row
mov.b r6, @r1 ! Set Y-address counter to 0
! Select Data write register.
mov.b r3, @r0 ! Select Data Write register
! Avoid loop, so write line manually.
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
mov.b @r4+, r8
mov.b r8, @r1
! Check next line.
dt r5 ! if (--r5) == 0...
bf.s row_loop ! ...if not, jump at <row_loop>
add #1, r7 ! (db) update row counter.
exit_part:
! Exit properly
ldc.l @r15+, sr ! restore SR register
mov.l @r15+, r8 ! resotre r8 register
rts ! exit.
nop ! (db) nop.
.align 4
.LCD_register_selector: .long 0xb4000000 /* LCD register selector */
.LCD_data_register: .long 0xb4010000 /* LCD data register */
.sr_int_msk: .long 0x100000f0 /* SR interrupt mask */
.end
/*
NOTE: OLD BUT FAST AND NOT SAFE
NOTE: FOR MULTIPLE PROCESS !
_t6k11_display(void *vram)
This function will display the vram on the screen.
This is the T6K11 drivers, DO NOT USE this function if you are
not absolutly sure that what you are doing.
TODO: use DMA ?
*/
# register organisation:
# r0 Y axis loop.
# r1 LCD register selector.
@ -49,7 +191,7 @@ _t6k11_display:
mov.l @r15+, r9
rts
mov.l @r15+, r8
.align 4
1: .long 0xb4000000 /* LCD register selector */
2: .long 0xb4010000 /* LCD data register */
*/
!.align 4
!1: .long 0xb4000000 /* LCD register selector */
!2: .long 0xb4010000 /* LCD data register */

View File

@ -0,0 +1,57 @@
#include <kernel/util.h>
#include <kernel/atomic.h>
// Internal symbols
static volatile uint8_t *sel = (void *)0xb4000000;
static volatile uint8_t *cmd = (void *)0xb4010000;
static void command(uint8_t reg, uint8_t data)
{
*sel = reg;
*cmd = data;
}
void t6k11_variant_lcd_driver(uint8_t *vram)
{
int y;
// Start atomic operations
atomic_start();
y = -1;
while (++y < 64)
{
// Row selector
command(8, y | 0x80);
command(8, 4);
// Send the row's data to the device
// @note: Unroll the loop for more speed (?)
*sel = 10;
*cmd = vram[0];
*cmd = vram[1];
*cmd = vram[2];
*cmd = vram[3];
*cmd = vram[4];
*cmd = vram[5];
*cmd = vram[6];
*cmd = vram[7];
*cmd = vram[8];
*cmd = vram[9];
*cmd = vram[10];
*cmd = vram[11];
*cmd = vram[12];
*cmd = vram[13];
*cmd = vram[14];
*cmd = vram[15];
// Update vram ptr
vram = &vram[16];
}
// Stop atomic operations
atomic_stop();
}

View File

@ -1,107 +0,0 @@
.text
.global _sched_context_switch
.type _sched_context_switch, @function
.align 2
/*
** void sched_context_switch(common_context_t *current, common_context_t *next);
**
** @note:
** r4 - current scheduler task
** r5 - next task
** r0 - tmp
*/
_sched_context_switch:
! Save contexts arg
mov.l r8, @-r15 ! save r8
mov.l r9, @-r15 ! save r9
mov r4, r8 ! save current context into unbankable reg
mov r5, r9 ! save next context into unbankable reg
! Update SR register to block interrupt / exception and
! switch register bank to simalate system call.
! @note:
! Normaly this is the TMU0 interrupt so the interrupt
! and register banck is already switchted BUT durring the
! bootstrap part, the kernel call this function in "user"
! context. This is why we force update CPU configuration.
mov.l .sr_msk, r1 ! get mask for SR.BL = 1, SR.RB = 1 and SR.IMASK = 0b1111
stc sr, r0 ! get SR register
or r1, r0 ! set mask for BL, RB and IMASK
ldc r0, sr ! update SR regsiter
! Restore context arg
mov r8, r4 ! restore current context
mov r9, r5 ! restore next context
mov.l @r15+, r9 ! restore r9
mov.l @r15+, r8 ! restore r8
save_current_context:
! Check current process
! @note: current process can be NULL !
tst r4, r4 ! if current task == NULL...
bt context_load ! ...if yes, jump at <context_switch>
add #84, r4 ! get &process->context (end)
! save current context
!sts.l pr, @-r4 ! get pr regsiter
stc.l spc, @-r4 ! get spc regsiter
stc.l ssr, @-r4 ! get ssr regsiter
sts.l mach, @-r4 ! get mach regsiter
sts.l macl, @-r4 ! get macl regsiter
stc.l gbr, @-r4 ! get gbr regsiter
mov.l r15, @-r4 ! get r15 register
mov.l r14, @-r4 ! get r14 regsiter
mov.l r13, @-r4 ! get r13 regsiter
mov.l r12, @-r4 ! get r12 regsiter
mov.l r11, @-r4 ! get r11 regsiter
mov.l r10, @-r4 ! get r10 regsiter
mov.l r9, @-r4 ! get r9 regsiter
mov.l r8, @-r4 ! get r8 regsiter
stc.l R7_BANK, @-r4 ! get "process" r7 regsiter
stc.l R6_BANK, @-r4 ! get "process" r6 regsiter
stc.l R5_BANK, @-r4 ! get "process" r5 regsiter
stc.l R4_BANK, @-r4 ! get "process" r4 regsiter
stc.l R3_BANK, @-r4 ! get "process" r3 regsiter
stc.l R2_BANK, @-r4 ! get "process" r2 regsiter
stc.l R1_BANK, @-r4 ! get "process" r1 regsiter
stc.l R0_BANK, @-r4 ! get "process" r0 regsiter
context_load:
! Load next process
! @note: next process can not be NULL !
ldc.l @r5+, R0_BANK ! set "process" r0 regsiter
ldc.l @r5+, R1_BANK ! set "process" r1 regsiter
ldc.l @r5+, R2_BANK ! set "process" r2 regsiter
ldc.l @r5+, R3_BANK ! set "process" r3 regsiter
ldc.l @r5+, R4_BANK ! set "process" r4 regsiter
ldc.l @r5+, R5_BANK ! set "process" r5 regsiter
ldc.l @r5+, R6_BANK ! set "process" r6 regsiter
ldc.l @r5+, R7_BANK ! set "process" r7 regsiter
mov.l @r5+, r8 ! set r8 regsiter
mov.l @r5+, r9 ! set r9 regsiter
mov.l @r5+, r10 ! set r10 regsiter
mov.l @r5+, r11 ! set r11 regsiter
mov.l @r5+, r12 ! set r12 regsiter
mov.l @r5+, r13 ! set r13 regsiter
mov.l @r5+, r14 ! set r14 regsiter
mov.l @r5+, r15 ! set r15 register
ldc.l @r5+, gbr ! set gbr regsiter
lds.l @r5+, macl ! set macl regsiter
lds.l @r5+, mach ! set mach regsiter
ldc.l @r5+, ssr ! set ssr regsiter
ldc.l @r5+, spc ! set spc regsiter
!lds.l @r5+, pr ! set pr regsiter
! Process switch
rte ! use RTE to switch process
nop ! (db) nop
.align 4
.sr_msk: .long 0x700000f0
.end

View File

@ -198,7 +198,7 @@ process_switch:
.sched_schedule: .long _sched_schedule
.timer_tstr_register: .long 0xa4490004
.timer_unf_field: .long 0x00000100
#ifndef __SCHED_DEBUG__
#ifdef __SCHED_DEBUG__
.sched_debug: .long _sched_debug
#endif
.end

View File

@ -13,7 +13,7 @@ uint32_t sched_timer_tstr_bit = 0;
//void sched_handler(void);
//FIXME: remove me and wrap timer interrupt when occur !!
static void scheduler_timer_callback(void)
/*static void scheduler_timer_callback(void)
{
common_context_t *context_current;
common_context_t *context_next;
@ -38,7 +38,7 @@ static void scheduler_timer_callback(void)
// Context switch
sched_context_switch(context_current, context_next);
}
}*/
void sched_start(void)
{
@ -93,7 +93,6 @@ void sched_start(void)
// @note: I use Po/4 on TMU prescaler
// TODO: generate quantum and quantum counter for preemption !
uint32_t ticks = (per_freq / 4) / 16;
//sched_timer_id = timer_install(scheduler_timer_callback, NULL, ticks, 0);
sched_timer_id = timer_install(NULL, NULL, ticks, 0);
sched_timer_address = (uint32_t)&SH7305_TMU.TIMER[sched_timer_id].TCR;
sched_timer_intevt = 0x400 + (0x20 * sched_timer_id);

View File

@ -1,5 +1,6 @@
#include <kernel/font.h>
#include <kernel/devices/display.h>
#include <kernel/atomic.h>
// Font bitmap.
static const uint8_t kernel_font_bitmap[] = {
@ -55,9 +56,11 @@ static void font_draw_core(struct font_block_s *fblock)
// this is why we use y << 2 because 2^2 = 4.
vram_offset_y = fblock->y << 2;
// Start atomic operations
atomic_start();
// Draw character, pixer per pixel... (x_x)
// TODO: update me !!
// TODO: atomic operation !!
y = -1;
while (++y < fblock->height)
{
@ -80,6 +83,9 @@ static void font_draw_core(struct font_block_s *fblock)
fblock->bitmap.y = fblock->bitmap.y + KERNEL_FONT_BITMAP_WIDTH;
vram_offset_y = vram_offset_y + 4;
}
// Stop atomic operations
atomic_stop();
}

View File

@ -30,7 +30,11 @@ void kvram_clear(void)
void kvram_display(void)
{
//TODO: handle screen hadware !
t6k11_display(vram);
//TODO: load dynamically screen driver during the boot
if (*(uint8_t*)0xa0010021 == '3')
t6k11_variant_lcd_driver((void*)vram);
else
t6k11_lcd_driver(vram);
}
/* kvram_scroll() - Scroll up the Video RAM */
@ -150,6 +154,9 @@ void kvram_clr_str_area(int x, int y, int width, int height)
// Get VRAM offset
vram_offset_y = y << 2;
// Start atomic operations
atomic_start();
//DEbug
/*kvram_clear();
printk(0, 0, "kvram_clr_str_area debug !");
@ -176,6 +183,8 @@ void kvram_clr_str_area(int x, int y, int width, int height)
vram_offset_y = vram_offset_y + 4;
}
// Stop atomic operations
atomic_start();
}
/* kvram_ascii() - Draw ASCII character into Video RAM */