#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 (".section .rodata\n.globl charset\ncharset:\n.incbin \"boot-programs/charset.data\"\n.section .text") // charset is really the first character in the array. Its address is used as the start of the array. extern unsigned char const charset[127-32][6] #define assert(x) do { while (!(x)) kdebug ("assertion failed " #x); } while (0) enum types: LCD_EOF_CB = 32 LCD_LOG // For now, support only 16 bpp. // Screen is 800x480 tft. static unsigned h = 800, v = 480, hs = 80, vs = 20, fps = 60, Bpp = 2 #define frame_size (v * h * Bpp) static unsigned physical_descriptor struct Descriptor: unsigned next unsigned frame unsigned id unsigned cmd static void reset (): 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 () LCD_DA0 = physical_descriptor lcd_set_ena () lcd_enable_eof_intr () static void putchar (unsigned x, unsigned y, unsigned ch, unsigned fg = 0xffff, unsigned bg = 0x0000): if ch < 32 || ch > 126: ch = 127 ch -= 32 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[charset[ch][k] & (1 << r) ? 1 : 0] 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 (unsigned ch): switch ch: case '\n': while log_x < 800 / 6: putchar (log_x++, log_y, ' ') inc_logx () break default: putchar (log_x, log_y, ch) inc_logx () static void log_str (char const *str): while *str: log_char (*str++) static void log_num (Kernel::Num n): char const *encode = "0123456789abcdef" log_char ('[') for unsigned i = 0; i < 8; ++i: log_char (encode[(n.h >> (4 * (7 - i))) & 0xf]) log_char (' ') for unsigned i = 0; i < 8; ++i: log_char (encode[(n.l >> (4 * (7 - i))) & 0xf]) log_char (']') static void log_msg (): log_str ("prot:") log_num (Kernel::recv.protected_data) log_str ("data:") for unsigned i = 0; i < 2; ++i: log_num (Kernel::recv.data[i]) log_char ('\n') Kernel::Num start (): map_lcd () map_cpm () Descriptor descriptor __attribute__ ((aligned (16))) unsigned pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS unsigned physical = Kernel::my_memory.alloc_range (pages) assert (physical & PAGE_MASK && ~physical) for unsigned i = 0; i < pages; ++i: Kernel::Page p = Kernel::my_memory.create_page () p.alloc_physical (physical + i * PAGE_SIZE, false, true) Kernel::my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE) Kernel::free_cap (p) 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) Kernel::Page p = Kernel::my_memory.mapping (&descriptor) physical_descriptor = p.physical_address () + ((unsigned)&descriptor & ~PAGE_MASK) Kernel::free_cap (p) descriptor.next = physical_descriptor descriptor.frame = physical descriptor.id = 0xdeadbeef descriptor.cmd = LCD_CMD_EOFINT | ((frame_size / 4) << LCD_CMD_LEN_BIT) unsigned dptr = (unsigned)&descriptor __asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0") reset () Kernel::Cap logcap = Kernel::my_receiver.create_capability (LCD_LOG) __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory") Kernel::Cap set_eof_cb = Kernel::my_receiver.create_capability (LCD_EOF_CB) Kernel::my_parent.ocall (set_eof_cb, INIT_SET_LCD) unsigned slot = Kernel::alloc_slot () Kernel::Cap eof_cb = Kernel::alloc_cap () while true: Kernel::wait () //log_msg () switch Kernel::recv.protected_data.l: case IRQ_LCD: lcd_clr_eof () eof_cb.invoke () break case LCD_EOF_CB: Kernel::free_cap (eof_cb) eof_cb = Kernel::recv.arg Kernel::recv.arg = Kernel::alloc_cap () Kernel::recv.reply.invoke () Kernel::register_interrupt (IRQ_LCD) break case LCD_LOG: log_char (Kernel::recv.data[0].l) break default: log_char ('~') break