1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-07-01 00:44:31 +03:00

make lcd almost work

This commit is contained in:
Bas Wijnen 2009-07-05 10:52:44 +02:00
parent eb141d7901
commit 4b47df85e3
11 changed files with 194 additions and 174 deletions

View File

@ -179,7 +179,7 @@ Thread *Memory::alloc_thread ():
ret->pc = 0
ret->sp = 0
Thread_arch_init (ret)
ret->sleep = 0
ret->sleep_count = ~0
ret->flags = 0
ret->schedule_prev = NULL
ret->schedule_next = NULL

View File

@ -37,97 +37,53 @@ static void set_backlight (bool state):
PWM_CTR (0) = 0x3f
GPIO_GPDR (2) &= ~PWM_ENABLE
// Write to a register. Value must be in range [0, 0xff].
static void write_reg (unsigned reg, unsigned value):
unsigned data = (reg << 0xa) | 0x200 | value
GPIO_GPDR (2) |= SPEN
GPIO_GPDR (2) = (GPIO_GPDR (2) & ~SPDA) | SPCK
GPIO_GPDR (2) &= ~SPEN
udelay(25)
for unsigned i = 0; i < 16; ++i:
GPIO_GPDR (2) &= ~SPCK
if data & 0x8000:
GPIO_GPDR (2) |= SPDA
else:
GPIO_GPDR (2) &= ~SPDA
udelay (25)
GPIO_GPDR (2) |= SPCK
udelay (25)
data <<= 1
GPIO_GPDR (2) |= SPEN
udelay(200)
static void lcd_enable ():
udelay (50)
GPIO_GPDR (2) &= ~LCD_RET
udelay(150000)
GPIO_GPDR (2) |= LCD_RET
udelay(10000)
// These values have been copied from the linux source.
// I have no idea what they do.
write_reg (0x00, 0x03)
write_reg (0x01, 0x40)
write_reg (0x02, 0x11)
write_reg (0x03, 0xcd)
write_reg (0x04, 0x32)
write_reg (0x05, 0x0e)
write_reg (0x07, 0x03)
write_reg (0x08, 0x08)
write_reg (0x09, 0x32)
write_reg (0x0A, 0x88)
write_reg (0x0B, 0xc6)
write_reg (0x0C, 0x20)
write_reg (0x0D, 0x20)
set_backlight (true)
static void lcd_disable ():
write_reg (0x00, 0x03)
set_backlight (false)
static void reset ():
gpio_as_pwm ()
gpio_as_lcd_master ()
GPIO_GPDR (2) &= ~PWM_ENABLE
PWM_CTR (0) = 0x3f
PWM_PER (0) = 300
pwm_set_duty (0, 300)
pwm_set_full_duty (0)
set_backlight (false)
// initialize things.
GPIO_GPIER (2) &= ~(PWM_ENABLE | LCD_RET | SPEN | SPCK | SPDA)
GPIO_GPDIR (2) |= PWM_ENABLE | LCD_RET | SPEN | SPCK | SPDA
udelay (50)
GPIO_GPDR (2) &= ~LCD_RET
udelay (150000)
ddelay (2)
GPIO_GPDR (2) |= LCD_RET
udelay (10000)
lcd_enable ()
ddelay (1)
// For now, support only 16 bpp.
// Screen is 800x480 tft.
unsigned h = 800, v = 480, hs = 80, vs = 20, fps = 60, Bpp = 2
LCD_CTRL = LCD_CTRL_BPP_16 | LCD_CTRL_BST_16
LCD_VSYNC = 20
LCD_HSYNC = 80
LCD_DAV = (20 << 16) | 500
LCD_DAH = (80 << 16) | 880
LCD_VAT = (880 << 16) | 500
//LCD_CFG = MODE_TFT_GEN | PCLK_N | VSYNC_N
LCD_VSYNC = vs
LCD_HSYNC = hs
LCD_DAV = (vs << 16) | (vs + v)
LCD_DAH = (hs << 16) | (hs + h)
LCD_VAT = ((hs + h) << 16) | (vs + v)
#define MODE_TFT_GEN 0
#define PCLK_N (1 << 10)
#define VSYNC_N (1 << 8)
LCD_CFG = MODE_TFT_GEN | PCLK_N | VSYNC_N
// Stop lcd.
CPM_MSCR |= 1 << 7
cpm_stop_lcd ()
unsigned pclk = 60 * (800 * 3 + 80) * 500
unsigned pllout = cpm_get_pllout ()
CPM_CFCR2 = pllout / pclk - 1
unsigned v = pllout / (pclk * 4) - 1
while v < 0xf && pllout / (v + 1) > 150000000:
++v
CPM_CFCR = (CPM_CFCR & ~CPM_CFCR_LFR_MASK) | (v << CPM_CFCR_LFR_BIT) | CPM_CFCR_UPE
unsigned pixclock = fps * (hs + h) * (vs + v)
CPM_CFCR2 = pllout / pixclock - 1
unsigned val = pllout / (pixclock * 4) - 1
while val < 0xf && pllout / (val + 1) > 150000000:
++val
cpm_set_lcdclk_div (val)
CPM_CFCR |= CPM_CFCR_UPE
cpm_start_lcd ()
// Start lcd.
CPM_MSCR &= ~(1 << 7)
udelay (1000)
//LCD_DA0 = framebuffer
unsigned frame_size = v * h * Bpp
LCD_CMD0 = LCD_CMD_SOFINT | LCD_CMD_EOFINT | (frame_size << LCD_CMD_LEN_BIT)
lcd_set_ena ()
lcd_enable_eof_intr ()
int main ():
map_gpio ()
@ -136,19 +92,20 @@ int main ():
map_cpm ()
reset ()
while true:
set_backlight (false)
kdebug (0)
set_backlight (true)
kdebug (0)
schedule ()
register_interrupt (IRQ_LCD)
set_backlight (true)
while true:
Message msg
if !wait (&msg):
continue
switch msg.protected_data:
case IRQ_LCD:
kdebug (0)
LCD_STATE &= ~LCD_STATE_EOF
register_interrupt (IRQ_LCD)
// TODO: allow callback
break
case LCD_BACKLIGHT:
set_backlight (msg.data[0])
break

View File

@ -18,6 +18,7 @@
#include "kernel.hh"
// From user-provided, thus untrusted, data, find a capability.
Capability *Memory::find_capability (unsigned code, bool *copy):
if !code:
return NULL
@ -39,6 +40,7 @@ Capability *Memory::find_capability (unsigned code, bool *copy):
return c
return NULL
// Try to deliver a message.
bool Receiver::try_deliver ():
if !messages || !owner || !owner->is_waiting ():
return false
@ -61,6 +63,7 @@ bool Receiver::try_deliver ():
owner->unwait ()
return true
// Send a message to a receiver; try to deliver it immediately.
bool Receiver::send_message (unsigned protected_data, Capability::Context *c):
bool tried_direct = false
if owner && owner->is_waiting () && (protected_data == reply_protected_data || !protected_only):
@ -328,14 +331,19 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability:
thread->unrun ()
break
case CAP_THREAD_INFO_SLEEP:
value = &thread->sleep
value = &thread->sleep_count
if thread->flags & THREAD_FLAG_WAITING:
unsigned newval = (*value & ~c->data[3]) | (c->data[2] & c->data[3])
if *value == ~0 && newval != ~0:
thread->sleep ()
else if *value != ~0 && newval == ~0:
thread->unsleep ()
break
default:
value = Thread_arch_info (thread, c->data[1])
break
if value:
*value &= ~c->data[3]
*value |= c->data[2] & c->data[3]
*value = (*value & ~c->data[3]) | (c->data[2] & c->data[3])
reply_num (*value)
else:
reply_num (0)
@ -655,19 +663,19 @@ static bool kernel_invoke (unsigned target, unsigned protected_data, Capability:
reply_receiver = (Receiver *)protected_data
reply_receiver->protected_only = !(target & (1 << CAP_RECEIVER_CALL_ASYNC))
Capability *c0 = c->cap[0]
if ((unsigned)c0->target & ~KERNEL_MASK) != 0:
Capability r
fill_cap (&r, protected_data, reply_receiver->reply_protected_data)
c->cap[0] = &r
c->copy[0] = true
c0->target->send_message (c0->protected_data, c)
r.invalidate ()
return true
else:
// Kernel call: don't create actual capablities.
c->cap[0] = NULL
kernel_invoke ((unsigned)c0->target, c0->protected_data, c, c0)
return true
if c0:
if ((unsigned)c0->target & ~KERNEL_MASK) != 0:
Capability r
fill_cap (&r, protected_data, reply_receiver->reply_protected_data)
c->cap[0] = &r
c->copy[0] = true
c0->target->send_message (c0->protected_data, c)
r.invalidate ()
else:
// Kernel call: don't create actual capablities.
c->cap[0] = NULL
kernel_invoke ((unsigned)c0->target, c0->protected_data, c, c0)
return true
if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_REPLY))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_REPLY)):
// This is a reply capability.
Receiver *r = (Receiver *)protected_data
@ -717,4 +725,5 @@ bool Capability::invoke (Capability::Context *c):
// This is not a kernel capability: send a message to the receiver.
return target->send_message (protected_data, c)
// This is a kernel capability. Use a function to allow optimized call capabilities.
reply_receiver = NULL
return kernel_invoke ((unsigned)target, protected_data, c, this)

19
iris.h
View File

@ -18,6 +18,13 @@
#ifndef __IRIS_H
#define __IRIS_H
// Without the standard library, we don't have this definition.
// I preferred ((void*)0), but C++ has too strict type-checking to
// make that work.
#ifndef NULL
#define NULL 0
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -501,9 +508,17 @@ static unsigned thread_sleep (Capability thread, unsigned value)
return thread_info (thread, CAP_THREAD_INFO_SLEEP, value, ~0);
}
static void my_sleep (unsigned value)
static int my_sleep (unsigned value, Message *ret)
{
call_n04 (__my_thread, CAP_THREAD_INFO, CAP_THREAD_INFO_SLEEP, value, ~0);
ret->data[0] = CAP_THREAD_INFO;
ret->data[1] = CAP_THREAD_INFO_SLEEP;
ret->data[2] = value;
ret->data[3] = ~0;
ret->cap[0] = 0;
ret->cap[1] = 0;
ret->cap[2] = 0;
ret->cap[3] = 0;
return call (__my_thread, ret);
}
static unsigned thread_get_sleep (Capability thread)

View File

@ -33,11 +33,6 @@
#define EXTERN extern
#endif
// Without the standard library, we don't have this definition.
// I preferred ((void*)0), but C++ has too strict type-checking to
// make that work.
#define NULL 0
struct Object_base
struct Page
struct Thread
@ -73,8 +68,10 @@ struct Thread : public Object <Thread>:
unsigned pc, sp
Thread_arch arch
unsigned flags
unsigned sleep
unsigned sleep_count
Thread *schedule_prev, *schedule_next
void sleep ()
void unsleep ()
void run ()
void unrun ()
void wait ()

View File

@ -111,9 +111,6 @@ start_idle: // 280
// Wait for the next interrupt, then the first thread will be scheduled.
// It is impractical to try to call schedule, because for that the
// idle task would need to own capabilities.
move $v0, $zero
syscall
nop
1: wait
b 1b
nop
@ -221,7 +218,8 @@ save_regs:
#ifndef NDEBUG
// Allow interrupts to set EPC and friends.
mfc0 $k0, $CP0_STATUS
andi $k0, $k0, 0xff00
li $k1, 0x1000ff00
and $k0, $k0, $k1
mtc0 $k0, $CP0_STATUS
#endif

View File

@ -257,12 +257,14 @@ void init ():
GPIO_GPDIR (GPIO_USB_CLK_EN_PORT) |= 1 << GPIO_USB_CLK_EN
GPIO_GPDR (GPIO_USB_CLK_EN_PORT) |= 1 << GPIO_USB_CLK_EN
// Start the operating system timer.
unsigned latch = (JZ_EXTAL + (HZ>>1)) / HZ
// Start the operating system timer, and set it to give an interrupt immediately.
// This is better, because the kernel start with jumping into the idle task and
// waiting for the first interrupt.
unsigned latch = (JZ_EXTAL + (HZ >> 1)) / HZ
ost_disable_all ()
ost_set_mode (0, OST_TCSR_UIE | OST_TCSR_CKS_EXTAL)
ost_set_reload (0, latch)
ost_set_count (0, latch)
ost_set_count (0, 0)
ost_set_mode (0, OST_TCSR_UIE | OST_TCSR_CKS_EXTAL)
ost_enable_channel (0)
intc_unmask_irq (IRQ_OST0)

View File

@ -19,11 +19,40 @@
#define ARCH
#include "../kernel.hh"
static void handle_exit (Thread *old_current):
if !current:
schedule ()
if !current:
current = &idle
if old_current == current:
return
if current != &idle:
if (Memory *)asids[current->address_space->arch.asid] != current->address_space:
if asids[0]:
current->address_space->arch.asid = asids[0]
asids[0] = asids[asids[0]]
else:
static unsigned random = 1
current->address_space->arch.asid = random
// Overwrite used asid, so flush those values from tlb.
flush_tlb (random)
++random
if random >= 64:
random = 1
asids[current->address_space->arch.asid] = (unsigned)current->address_space
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
directory = current->address_space->arch.directory
if current->flags & THREAD_FLAG_PRIV:
cp0_set (CP0_STATUS, 0x1000ff13)
else:
cp0_set (CP0_STATUS, 0x0000ff13)
/// A TLB miss has occurred. This is the slow version. It is only used
/// when k0 or k1 is not 0, or when an error occurs.
/// Otherwise, the ultra-fast code in entry.S is used.
Thread *tlb_refill ():
//panic (0x88776655, "TLB refill")
Thread *old_current = current
if !directory:
panic (0x44449999, "No directory")
unsigned EntryHi
@ -41,11 +70,13 @@ Thread *tlb_refill ():
cp0_set (CP0_ENTRY_LO0, t[idx])
cp0_set (CP0_ENTRY_LO1, t[idx + 1])
__asm__ volatile ("tlbwr")
handle_exit (old_current)
return current
/// An interrupt which is not an exception has occurred.
Thread *interrupt ():
//panic (0x88877722, "Interrupt")
Thread *old_current = current
//dbg_send (INTC_IPR)
unsigned ipr = INTC_IPR
for unsigned i = 0; i < 32; ++i:
@ -68,6 +99,7 @@ Thread *interrupt ():
ost_clear_uf (0)
intc_ack_irq (IRQ_OST0)
timer_interrupt ()
handle_exit (old_current)
return current
void flush_tlb (unsigned asid):
@ -87,10 +119,9 @@ static void arch_invoke ():
Thread *caller = current
target = caller->address_space->find_capability (caller->arch.v0, &wait)
if !target:
// TODO: there must be no action here. This is just because the rest doesn't work yet.
dbg_send (3, 2)
// There must be no action here.
//dbg_send (3, 2)
//dbg_send (caller->arch.v0)
schedule ()
// Calling an invalid capability always fails.
caller->arch.v0 = 0
else:
@ -108,35 +139,10 @@ static void arch_invoke ():
caller->arch.v0 = target->invoke (&c) ? 1 : 0
if caller != current && caller != &idle && (caller->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) == THREAD_FLAG_RUNNING:
current = caller
else if !current:
schedule ()
if !current:
current = &idle
if caller != current:
if (Memory *)asids[current->address_space->arch.asid] != current->address_space:
if asids[0]:
current->address_space->arch.asid = asids[0]
asids[0] = asids[asids[0]]
else:
static unsigned random = 1
current->address_space->arch.asid = random
// Overwrite used asid, so flush those values from tlb.
flush_tlb (random)
++random
if random >= 64:
random = 1
asids[current->address_space->arch.asid] = (unsigned)current->address_space
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
directory = current->address_space->arch.directory
unsigned status
cp0_get (CP0_STATUS, status)
status &= 0x0fffffff
if current->flags & THREAD_FLAG_PRIV:
status |= 0x10000000
cp0_set (CP0_STATUS, status | 0x13)
/// A general exception has occurred.
Thread *exception ():
Thread *old_current = current
unsigned cause
cp0_get (CP0_CAUSE, cause)
switch (cause >> 2) & 0x1f:
@ -220,9 +226,12 @@ Thread *exception ():
panic (0xf5223344, "Reserved exception code")
default:
panic (0xf6223344, "Impossible exception code")
handle_exit (old_current)
return current
/// There's a cache error. Big trouble. Probably not worth trying to recover.
Thread *cache_error ():
panic (0x33333333, "cache error")
Thread *old_current = current
handle_exit (old_current)
return current

View File

@ -23,6 +23,7 @@
// Main clock, for cpu, serial port, and with divisors for most other hardware
#define JZ_EXTAL 3686400
//#define JZ_EXTAL 3072000
// RTC clock
#define RTC_CLOCK 32768
@ -2311,8 +2312,9 @@ static __inline__ void udelay (unsigned us):
GPIO_GPDR (0) = GPIO_GPDR (0)
#ifndef __KERNEL
static __inline__ void mdelay (unsigned ms):
my_sleep ((ms + 99) / 100)
static __inline__ void ddelay (unsigned ds):
Message m
my_sleep (ds, &m)
#endif
/***************************************************************************

View File

@ -109,6 +109,6 @@ void dbg_send (unsigned code, unsigned bits):
dbg_led (false, false, false)
dbg_sleep (200)
dbg_led (true, true, false)
dbg_sleep (500)
dbg_sleep (50)
dbg_led (false, false, false)
dbg_sleep (500)
dbg_sleep (50)

View File

@ -33,18 +33,29 @@ static void unrun_thread (Thread *thread):
first_scheduled = thread->schedule_next
if thread->schedule_next:
thread->schedule_next->schedule_prev = thread->schedule_prev
if thread->sleep:
thread->schedule_next = first_sleeper
thread->schedule_prev = NULL
if thread->schedule_next:
thread->schedule_next->schedule_prev = thread
first_sleeper = thread
void Thread::sleep ():
schedule_next = first_sleeper
if schedule_next:
schedule_next->schedule_prev = this
schedule_prev = NULL
first_sleeper = this
void Thread::unsleep ():
if schedule_next:
schedule_next->schedule_prev = schedule_prev
if schedule_prev:
schedule_prev->schedule_next = schedule_next
else:
first_sleeper = schedule_next
void Thread::run ():
if flags & THREAD_FLAG_RUNNING:
return
flags |= THREAD_FLAG_RUNNING
if flags & THREAD_FLAG_WAITING:
if sleep_count != ~0:
sleep ()
return
run_thread (this)
@ -53,41 +64,47 @@ void Thread::unrun ():
return
flags &= ~THREAD_FLAG_RUNNING
if flags & THREAD_FLAG_WAITING:
if sleep_count != ~0:
unsleep ()
return
unrun_thread (this)
void Thread::unwait ():
if !(flags & THREAD_FLAG_WAITING):
return
flags &= ~THREAD_FLAG_WAITING
if sleep_count != ~0:
unsleep ()
if flags & THREAD_FLAG_RUNNING:
run_thread (this)
static void sleep_tick (Thread *thread):
if !thread->sleep_count:
thread->unwait ()
// Time-out: let the thread know with a special message.
Capability::Context c
for unsigned i = 0; i < 4; ++i:
c.data[i] = 0
c.cap[i] = NULL
c.copy[i] = false
Thread_arch_receive (thread, ~0, &c)
// Fall through to let sleep be set to ~0, so the next wait will be infinitely long again.
--thread->sleep_count
void Thread::wait ():
if flags & THREAD_FLAG_WAITING:
return
if flags & THREAD_FLAG_RUNNING:
unrun_thread (this)
flags |= THREAD_FLAG_WAITING
if sleep_count != ~0:
sleep ()
// Try to receive a message from a Receiver immediately.
for Receiver *r = receivers; r; r = r->next_owned:
if r->try_deliver ():
break
void Thread::unwait ():
if !(flags & THREAD_FLAG_WAITING):
return
flags &= ~THREAD_FLAG_WAITING
if flags & THREAD_FLAG_RUNNING:
run_thread (this)
void timer_interrupt ():
//panic (0x88877744, "Timer interrupt")
Thread *thread, *next
for thread = first_sleeper; thread; thread = next:
next = thread->next
if !--thread->sleep:
if thread->flags & THREAD_FLAG_WAITING:
thread->unwait ()
else:
run_thread (thread)
//#ifndef NDEBUG
//static bool ledstate = false
//dbg_led (false, false, ledstate = !ledstate)
//#endif
return
if sleep_count != ~0:
sleep_tick (this)
void schedule ():
Thread *old = current
@ -95,3 +112,17 @@ void schedule ():
current = current->schedule_next
if !current:
current = first_scheduled
if !current:
current = &idle
void timer_interrupt ():
//panic (0x88877744, "Timer interrupt")
Thread *thread, *next
for thread = first_sleeper; thread; thread = next:
next = thread->next
sleep_tick (thread)
schedule ()
//#ifndef NDEBUG
//static bool ledstate = false
//dbg_led (false, false, ledstate = !ledstate)
//#endif