2009-06-10 22:42:01 +03:00
|
|
|
#pypp 0
|
|
|
|
// Iris: micro-kernel for a capability-based operating system.
|
2009-06-24 01:47:13 +03:00
|
|
|
// boot-programs/lcd.ccp: Display driver.
|
2009-06-10 22:42:01 +03:00
|
|
|
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
|
|
|
//
|
|
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
2009-06-10 23:54:12 +03:00
|
|
|
#include "devices.hh"
|
2009-06-22 18:48:05 +03:00
|
|
|
#define ARCH
|
|
|
|
#include "arch.hh"
|
2009-06-10 22:42:01 +03:00
|
|
|
|
2009-07-21 13:17:52 +03:00
|
|
|
__asm__ volatile (".globl charset\ncharset:\n.incbin \"boot-programs/charset.data\"")
|
|
|
|
// I'm too lazy to do this right. The address of charset is really the address of the array.
|
|
|
|
extern unsigned charset
|
|
|
|
|
2009-07-20 01:23:45 +03:00
|
|
|
#define assert(x) do { while (!(x)) kdebug (0, 0); } while (0)
|
|
|
|
|
2009-07-21 13:17:52 +03:00
|
|
|
enum types:
|
|
|
|
LCD_EOF_CB = 32
|
|
|
|
|
2009-07-20 01:23:45 +03:00
|
|
|
// For now, support only 16 bpp.
|
|
|
|
// Screen is 800x480 tft.
|
|
|
|
unsigned h = 800, v = 480, hs = 80, vs = 20, fps = 60, Bpp = 2
|
|
|
|
#define frame_size (v * h * Bpp)
|
|
|
|
|
|
|
|
struct Descriptor:
|
|
|
|
unsigned next
|
|
|
|
unsigned frame
|
|
|
|
unsigned id
|
|
|
|
unsigned cmd
|
|
|
|
|
|
|
|
static void reset (unsigned physical_descriptor):
|
2009-06-10 22:42:01 +03:00
|
|
|
LCD_CTRL = LCD_CTRL_BPP_16 | LCD_CTRL_BST_16
|
2009-07-05 11:52:44 +03:00
|
|
|
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 VSYNC_N (1 << 8)
|
2009-07-20 01:23:45 +03:00
|
|
|
LCD_CFG = MODE_TFT_GEN | VSYNC_N
|
2009-07-05 11:52:44 +03:00
|
|
|
|
|
|
|
cpm_stop_lcd ()
|
2009-06-10 22:42:01 +03:00
|
|
|
|
2009-07-05 11:52:44 +03:00
|
|
|
unsigned pixclock = fps * (hs + h) * (vs + v)
|
2009-07-20 01:23:45 +03:00
|
|
|
unsigned pllout = cpm_get_pllout ()
|
2009-07-05 11:52:44 +03:00
|
|
|
CPM_CFCR2 = pllout / pixclock - 1
|
|
|
|
|
|
|
|
unsigned val = pllout / (pixclock * 4) - 1
|
2009-07-20 01:23:45 +03:00
|
|
|
assert (pllout / (val + 1) <= 150000000)
|
|
|
|
assert (val <= 0xf)
|
2009-07-05 11:52:44 +03:00
|
|
|
cpm_set_lcdclk_div (val)
|
|
|
|
CPM_CFCR |= CPM_CFCR_UPE
|
|
|
|
|
|
|
|
cpm_start_lcd ()
|
2009-06-10 22:42:01 +03:00
|
|
|
|
2009-07-04 17:21:28 +03:00
|
|
|
udelay (1000)
|
2009-07-20 01:23:45 +03:00
|
|
|
LCD_DA0 = physical_descriptor
|
2009-07-05 11:52:44 +03:00
|
|
|
lcd_set_ena ()
|
|
|
|
lcd_enable_eof_intr ()
|
2009-06-10 22:42:01 +03:00
|
|
|
|
2009-07-21 13:17:52 +03:00
|
|
|
static void putchar (unsigned x, unsigned y, unsigned utf8, unsigned fg = 0xffff, unsigned bg = 0x0000):
|
|
|
|
if utf8 < 32 || utf8 > 126:
|
|
|
|
utf8 = 127
|
|
|
|
unsigned idx = utf8 - 32
|
|
|
|
unsigned char *c = &((unsigned char *)&charset)[idx * 6]
|
|
|
|
unsigned lookup[2] = { bg, fg }
|
|
|
|
for unsigned k = 0; k < 6; ++k:
|
|
|
|
for unsigned r = 0; r < 8; ++r:
|
|
|
|
LCD_FRAMEBUFFER_BASE[(y * 8 + r) * 800 + x * 6 + k] = lookup[c[k] & (1 << r) ? 1 : 0]
|
|
|
|
|
|
|
|
static unsigned read_rest (unsigned num, char const *&utf8):
|
|
|
|
unsigned ret = 0
|
|
|
|
while num--:
|
|
|
|
if (*utf8 & 0xc0) != 0x80:
|
|
|
|
return ~0
|
|
|
|
ret <<= 6
|
|
|
|
ret |= (*utf8++) & 0x3f
|
|
|
|
return ret
|
|
|
|
|
|
|
|
static unsigned read_utf8 (char const *&utf8):
|
|
|
|
unsigned c = *utf8++
|
|
|
|
if !(c & 0x80):
|
|
|
|
return c
|
|
|
|
if !(c & 0x40):
|
|
|
|
// Invalid character.
|
|
|
|
return 0
|
|
|
|
if !(c & 0x20):
|
|
|
|
// 2-byte character.
|
|
|
|
c &= 0x1f
|
|
|
|
c <<= 6
|
|
|
|
c |= read_rest (1, utf8)
|
|
|
|
else if !(c & 0x10):
|
|
|
|
// 3-byte character.
|
|
|
|
c &= 0xf
|
|
|
|
c <<= 12
|
|
|
|
c |= read_rest (2, utf8)
|
|
|
|
else if !(c & 0x8):
|
|
|
|
// 4-byte character.
|
|
|
|
c &= 0x7
|
|
|
|
c <<= 18
|
|
|
|
c |= read_rest (3, utf8)
|
|
|
|
else if !(c & 0x4):
|
|
|
|
// 5-byte character.
|
|
|
|
c &= 0x3
|
|
|
|
c <<= 24
|
|
|
|
c |= read_rest (4, utf8)
|
|
|
|
else if !(c & 0x2):
|
|
|
|
// 6-byte character.
|
|
|
|
c &= 0x1
|
|
|
|
c <<= 30
|
|
|
|
c |= read_rest (5, utf8)
|
|
|
|
else
|
|
|
|
// Invalid character.
|
|
|
|
return 0
|
|
|
|
if c == ~0:
|
|
|
|
return 0
|
|
|
|
return c
|
|
|
|
|
|
|
|
static void putstr (unsigned x, unsigned y, char const *utf8):
|
|
|
|
while *utf8:
|
|
|
|
putchar (x++, y, read_utf8 (utf8))
|
|
|
|
|
|
|
|
static unsigned log_x = 1, log_y = 1
|
|
|
|
static void inc_logx ():
|
|
|
|
if ++log_x >= 800 / 6:
|
|
|
|
log_x = 1
|
|
|
|
if ++log_y >= 480 / 8:
|
|
|
|
log_y = 1
|
|
|
|
|
|
|
|
static void log (char const *utf8):
|
|
|
|
while *utf8:
|
|
|
|
unsigned c = read_utf8 (utf8)
|
|
|
|
switch c:
|
|
|
|
case '\n':
|
|
|
|
while log_x < 800 / 6:
|
|
|
|
putchar (log_x++, log_y, ' ')
|
|
|
|
inc_logx ()
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
putchar (log_x, log_y, c)
|
|
|
|
inc_logx ()
|
|
|
|
|
2009-06-10 22:42:01 +03:00
|
|
|
int main ():
|
2009-07-20 01:23:45 +03:00
|
|
|
// TODO: The descriptor takes an entire uncached page, because I don't know how to force a cache write-back. It's much better to do that instead.
|
2009-06-10 23:54:12 +03:00
|
|
|
map_gpio ()
|
|
|
|
map_pwm0 ()
|
|
|
|
map_lcd ()
|
|
|
|
map_cpm ()
|
2009-06-10 22:42:01 +03:00
|
|
|
|
2009-07-20 01:23:45 +03:00
|
|
|
unsigned pages = (frame_size + 16 + ~PAGE_MASK) >> PAGE_BITS
|
|
|
|
assert (pages > CAPPAGE_SIZE && pages <= 2 * CAPPAGE_SIZE)
|
|
|
|
unsigned physical = alloc_range (__my_memory, pages)
|
|
|
|
assert (physical)
|
|
|
|
//Capability cappage[2]
|
|
|
|
//unsigned base[2]
|
|
|
|
//cappage[0] = memory_create_cappage (__my_memory, &base[0])
|
|
|
|
//cappage[1] = memory_create_cappage (__my_memory, &base[1])
|
|
|
|
for unsigned i = 0; i < CAPPAGE_SIZE; ++i:
|
|
|
|
Capability page = memory_create_page (__my_memory)
|
|
|
|
//cappage_set (cappage[0], page, i)
|
|
|
|
alloc_physical (page, physical + i * PAGE_SIZE, 0, 1)
|
|
|
|
memory_map (__my_memory, page, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE, 1)
|
|
|
|
drop (page)
|
|
|
|
for unsigned i = 0; i < pages - CAPPAGE_SIZE; ++i:
|
|
|
|
Capability page = memory_create_page (__my_memory)
|
|
|
|
//cappage_set (cappage[1], page, i)
|
|
|
|
alloc_physical (page, physical + (i + CAPPAGE_SIZE) * PAGE_SIZE, 0, 1)
|
|
|
|
memory_map (__my_memory, page, (unsigned)LCD_FRAMEBUFFER_BASE + (i + CAPPAGE_SIZE) * PAGE_SIZE, 1)
|
|
|
|
drop (page)
|
|
|
|
for unsigned y = 0; y < 480; ++y:
|
|
|
|
unsigned g = (y << 6) / 480
|
|
|
|
unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
|
|
|
|
for unsigned x = 0; x < 800; ++x:
|
|
|
|
unsigned r = (x << 5) / 800
|
|
|
|
unsigned b = ((9 * x * x + 25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
|
|
|
|
if r != olr:
|
|
|
|
olr = r
|
|
|
|
r = 0x1f
|
|
|
|
unsigned oyb = b
|
|
|
|
if y > 0:
|
|
|
|
oyb = ((9 * x * x + 25 * (y - 1) * (y - 1)) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
|
|
|
|
if b != ob || b != oyb:
|
|
|
|
ob = b
|
|
|
|
b = 0x1f
|
|
|
|
LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b)
|
2009-07-21 13:17:52 +03:00
|
|
|
log ("testing!\nIs dit een werkende console?\nLinks, rechts?\n")
|
2009-07-20 01:23:45 +03:00
|
|
|
Descriptor *descriptor = (Descriptor *)((unsigned)LCD_FRAMEBUFFER_BASE + frame_size)
|
|
|
|
unsigned physical_descriptor = physical + frame_size
|
|
|
|
descriptor->next = physical_descriptor
|
|
|
|
descriptor->frame = physical
|
|
|
|
descriptor->id = 0xdeadbeef
|
|
|
|
descriptor->cmd = LCD_CMD_EOFINT | ((frame_size / 4) << LCD_CMD_LEN_BIT)
|
|
|
|
reset (physical_descriptor)
|
2009-07-05 11:52:44 +03:00
|
|
|
register_interrupt (IRQ_LCD)
|
2009-07-21 13:17:52 +03:00
|
|
|
|
|
|
|
Capability eof_cb = 0
|
|
|
|
|
|
|
|
Capability cap = receiver_create_capability (__my_receiver, LCD_EOF_CB)
|
|
|
|
invoke_11 (__my_parent, cap, INIT_SET_LCD)
|
|
|
|
drop (cap)
|
2009-06-22 17:13:00 +03:00
|
|
|
|
2009-06-10 22:42:01 +03:00
|
|
|
while true:
|
|
|
|
Message msg
|
2009-07-20 01:23:45 +03:00
|
|
|
wait (&msg)
|
2009-06-10 22:42:01 +03:00
|
|
|
switch msg.protected_data:
|
2009-07-05 11:52:44 +03:00
|
|
|
case IRQ_LCD:
|
2009-07-20 01:23:45 +03:00
|
|
|
lcd_clr_eof ()
|
2009-07-05 11:52:44 +03:00
|
|
|
register_interrupt (IRQ_LCD)
|
2009-07-21 13:17:52 +03:00
|
|
|
if eof_cb:
|
|
|
|
invoke_00 (eof_cb)
|
2009-06-10 22:42:01 +03:00
|
|
|
break
|
2009-07-21 13:17:52 +03:00
|
|
|
case LCD_EOF_CB:
|
|
|
|
if eof_cb:
|
|
|
|
drop (eof_cb)
|
|
|
|
eof_cb = msg.cap[0]
|
2009-06-10 22:42:01 +03:00
|
|
|
break
|