#pypp 0 // Iris: micro-kernel for a capability-based operating system. // boot-programs/lcd.ccp: Display driver. // Copyright 2009 Bas Wijnen // // 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 "devices.hh" #define ARCH #include "arch.hh" __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 #define assert(x) do { while (!(x)) kdebug (0, 0); } while (0) enum types: LCD_EOF_CB = 32 // 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): LCD_CTRL = LCD_CTRL_BPP_16 | LCD_CTRL_BST_16 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) LCD_CFG = MODE_TFT_GEN | VSYNC_N cpm_stop_lcd () unsigned pixclock = fps * (hs + h) * (vs + v) unsigned pllout = cpm_get_pllout () CPM_CFCR2 = pllout / pixclock - 1 unsigned val = pllout / (pixclock * 4) - 1 assert (pllout / (val + 1) <= 150000000) assert (val <= 0xf) cpm_set_lcdclk_div (val) CPM_CFCR |= CPM_CFCR_UPE cpm_start_lcd () udelay (1000) LCD_DA0 = physical_descriptor lcd_set_ena () lcd_enable_eof_intr () 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 () int main (): // 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. map_gpio () map_pwm0 () map_lcd () map_cpm () 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) log ("testing!\nIs dit een werkende console?\nLinks, rechts?\n") 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) register_interrupt (IRQ_LCD) Capability eof_cb = 0 Capability cap = receiver_create_capability (__my_receiver, LCD_EOF_CB) invoke_11 (__my_parent, cap, INIT_SET_LCD) drop (cap) while true: Message msg wait (&msg) switch msg.protected_data: case IRQ_LCD: lcd_clr_eof () register_interrupt (IRQ_LCD) if eof_cb: invoke_00 (eof_cb) break case LCD_EOF_CB: if eof_cb: drop (eof_cb) eof_cb = msg.cap[0] break