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
|
|
|
|
2010-01-16 17:13:54 +02:00
|
|
|
__asm__ volatile (".section .rodata\n.globl charset\ncharset:\n.incbin \"source/charset.data\"\n.section .text")
|
2009-12-27 01:12:35 +02:00
|
|
|
extern unsigned char const charset[127-32][8][6]
|
2009-07-21 13:17:52 +03:00
|
|
|
|
2009-12-11 10:43:42 +02:00
|
|
|
#define assert(x) do { if (!(x)) { kdebug ("assertion failed " #x); while (true) {} } } while (0)
|
2009-07-20 01:23:45 +03:00
|
|
|
|
2009-10-10 02:31:10 +03:00
|
|
|
#if defined (TRENDTAC)
|
2009-10-31 10:32:23 +02:00
|
|
|
static unsigned h = 800, v = 480, fps = 60, Bpp = 2
|
2009-12-26 15:17:06 +02:00
|
|
|
#define LOG_X_BASE 1
|
|
|
|
#define LOG_Y_BASE 1
|
2009-10-31 10:32:23 +02:00
|
|
|
#elif defined (NANONOTE)
|
2009-12-11 10:43:42 +02:00
|
|
|
static unsigned h = 320, v = 240, fps = 60, Bpp = 4
|
2009-12-26 15:17:06 +02:00
|
|
|
#define LOG_X_BASE 0
|
|
|
|
#define LOG_Y_BASE 0
|
2009-10-10 02:31:10 +03:00
|
|
|
#else
|
|
|
|
#error unknown board
|
|
|
|
#endif
|
2009-07-20 01:23:45 +03:00
|
|
|
#define frame_size (v * h * Bpp)
|
|
|
|
|
2009-08-24 22:02:35 +03:00
|
|
|
static unsigned physical_descriptor
|
|
|
|
|
2009-10-31 10:32:23 +02:00
|
|
|
/**/struct Descriptor {
|
|
|
|
unsigned next;
|
|
|
|
unsigned frame;
|
|
|
|
unsigned id;
|
|
|
|
unsigned cmd;
|
|
|
|
} __attribute__ ((packed))
|
|
|
|
|
|
|
|
#if defined (NANONOTE)
|
|
|
|
#define SP_PORT 2
|
|
|
|
#define SPEN 21
|
|
|
|
#define SPDA 22
|
|
|
|
#define SPCK 23
|
|
|
|
|
|
|
|
static void udelay (unsigned num):
|
|
|
|
for unsigned i = 0; i < num * (JZ_EXTAL / 1000000); ++i:
|
|
|
|
// set 0 does nothing, but costs at least one clock pulse.
|
|
|
|
gpio_set (SP_PORT, 0)
|
|
|
|
|
|
|
|
// Register names. The registers are not named in the datasheet, and in some cases the name only describes a part of the bits in it.
|
|
|
|
// The registers with bit 6 set have bit 7 set instead, because of the transfer method.
|
|
|
|
enum spi_reg:
|
|
|
|
AC = 0x00
|
|
|
|
DC = 0x01
|
|
|
|
BRIGHTNESS = 0x03
|
|
|
|
FORMAT = 0x04
|
|
|
|
BACKLIGHT1 = 0x05
|
|
|
|
VBLANK = 0x06
|
|
|
|
HBLANK = 0x07
|
|
|
|
BACKLIGHT2 = 0x08
|
|
|
|
SYNC = 0x0b
|
|
|
|
POLARITY = 0x0c
|
2009-12-11 10:43:42 +02:00
|
|
|
CONTRAST_RGB = 0x0d
|
2009-10-31 10:32:23 +02:00
|
|
|
SUB_CONTRAST_R = 0x0e
|
|
|
|
SUB_BRIGHTNESS_R= 0x0f
|
|
|
|
SUB_CONTRAST_B = 0x10
|
|
|
|
SUB_BRIGHTNESS_B= 0x11
|
|
|
|
TRIM = 0x12
|
|
|
|
COLOR = 0x13
|
|
|
|
GAMMA = 0x16
|
|
|
|
GAMMA1 = 0x17
|
|
|
|
GAMMA2 = 0x18
|
|
|
|
GAMMA3 = 0x19
|
|
|
|
GAMMA4 = 0x1a
|
|
|
|
INVERSION = 0xa5
|
|
|
|
HLEVEL = 0xa6
|
|
|
|
LLEVEL = 0xa7
|
|
|
|
FB = 0xb1
|
|
|
|
|
|
|
|
static void write_reg (unsigned reg, unsigned val):
|
2009-12-11 10:43:42 +02:00
|
|
|
unsigned value = (reg << 8) | (val & 0xff)
|
2009-10-31 10:32:23 +02:00
|
|
|
gpio_clear (SP_PORT, 1 << SPEN)
|
|
|
|
udelay (1)
|
|
|
|
for unsigned i = 0; i < 16; ++i, value <<= 1:
|
|
|
|
gpio_clear (SP_PORT, 1 << SPCK)
|
|
|
|
if value & 0x8000:
|
|
|
|
gpio_set (SP_PORT, 1 << SPDA)
|
|
|
|
else:
|
|
|
|
gpio_clear (SP_PORT, 1 << SPDA)
|
|
|
|
udelay (4)
|
|
|
|
gpio_set (SP_PORT, 1 << SPCK)
|
2009-12-11 10:43:42 +02:00
|
|
|
udelay (4)
|
2009-10-31 10:32:23 +02:00
|
|
|
gpio_set (SP_PORT, 1 << SPEN)
|
|
|
|
udelay(4)
|
|
|
|
#endif
|
2009-07-20 01:23:45 +03:00
|
|
|
|
2009-08-24 22:02:35 +03:00
|
|
|
static void reset ():
|
2009-10-31 10:32:23 +02:00
|
|
|
#if defined (TRENDTAC)
|
|
|
|
// Note that the sync pulse is part of the pre-display region.
|
2009-10-10 02:31:10 +03:00
|
|
|
// Vertical timings.
|
2009-10-31 10:32:23 +02:00
|
|
|
unsigned vsync = 20, vpre = 20, vpost = 0
|
2009-10-10 02:31:10 +03:00
|
|
|
// Horizontal timings.
|
2009-10-31 10:32:23 +02:00
|
|
|
unsigned hsync = 80, hpre = 80, hpost = 0
|
|
|
|
|
|
|
|
// One clock pulse per pixel.
|
2009-12-11 10:43:42 +02:00
|
|
|
unsigned cpp = 1
|
2009-10-10 02:31:10 +03:00
|
|
|
// Bits per pixel.
|
|
|
|
unsigned bpp = LCD_CTRL_BPP_16
|
|
|
|
// Configuration.
|
2009-07-05 11:52:44 +03:00
|
|
|
#define MODE_TFT_GEN 0
|
|
|
|
#define VSYNC_N (1 << 8)
|
2009-10-10 02:31:10 +03:00
|
|
|
unsigned cfg = MODE_TFT_GEN | VSYNC_N
|
2009-10-31 10:32:23 +02:00
|
|
|
#elif defined (NANONOTE)
|
|
|
|
// Note that the sync pulse is part of the pre-display region.
|
2009-12-11 10:43:42 +02:00
|
|
|
// Horizontal timings.
|
2009-12-18 10:00:38 +02:00
|
|
|
unsigned hsync = 1, hpre = 70, hpost = 273
|
2009-10-10 02:31:10 +03:00
|
|
|
// Vertical timings.
|
2009-10-31 10:32:23 +02:00
|
|
|
unsigned vsync = 1, vpre = 21, vpost = 2
|
2009-12-11 10:43:42 +02:00
|
|
|
// 3 clocks per pixel.
|
|
|
|
unsigned cpp = 3
|
2009-10-10 02:31:10 +03:00
|
|
|
// Bits per pixel.
|
|
|
|
unsigned bpp = LCD_CTRL_BPP_18_24
|
|
|
|
// Configuration.
|
2009-12-18 10:00:38 +02:00
|
|
|
unsigned cfg = LCD_CFG_MODE_SERIAL_TFT | LCD_CFG_HSP | LCD_CFG_VSP | LCD_CFG_PCP
|
2009-10-31 10:32:23 +02:00
|
|
|
// Set up SPI pins.
|
2009-12-11 10:43:42 +02:00
|
|
|
gpio_as_output (SP_PORT, (1 << SPEN) | (1 << SPCK) | (1 << SPDA))
|
2009-10-31 10:32:23 +02:00
|
|
|
gpio_set (SP_PORT, (1 << SPEN) | (1 << SPCK))
|
|
|
|
#else
|
|
|
|
#error unknown board
|
|
|
|
#endif
|
2009-10-10 02:31:10 +03:00
|
|
|
|
2009-10-31 10:32:23 +02:00
|
|
|
// Note that the sync pulse is part of the pre-display region.
|
2009-12-11 10:43:42 +02:00
|
|
|
unsigned vpe = vsync, vds = vpre, vde = vds + v, vt = vde + vpost
|
2009-12-18 10:00:38 +02:00
|
|
|
unsigned hpe = hsync, hds = hpre, hde = hds + h, ht = hde + hpost
|
2009-07-05 11:52:44 +03:00
|
|
|
|
|
|
|
cpm_stop_lcd ()
|
2009-06-10 22:42:01 +03:00
|
|
|
|
2009-12-11 10:43:42 +02:00
|
|
|
unsigned pixclock = fps * ht * vt
|
2009-10-10 02:31:10 +03:00
|
|
|
|
|
|
|
#if defined (TRENDTAC)
|
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
|
2009-10-10 02:31:10 +03:00
|
|
|
#elif defined (NANONOTE)
|
2009-10-31 10:32:23 +02:00
|
|
|
unsigned val = cpm_get_pllout2 () / pixclock - 1
|
2009-12-11 10:43:42 +02:00
|
|
|
//assert (val < 0x400)
|
|
|
|
//cpm_set_pixdiv (val)
|
|
|
|
//cpm_set_pixdiv (12)
|
2009-10-31 10:32:23 +02:00
|
|
|
|
2009-12-11 10:43:42 +02:00
|
|
|
val = cpm_get_pllout2 () / (pixclock * 3) - 1
|
2009-10-31 10:32:23 +02:00
|
|
|
assert (val < 0x20)
|
2009-12-11 10:43:42 +02:00
|
|
|
//cpm_set_ldiv (val)
|
2009-10-10 02:31:10 +03:00
|
|
|
// Update dividers.
|
2009-12-11 10:43:42 +02:00
|
|
|
//CPM_CPCCR |= CPM_CPCCR_CE
|
|
|
|
#else
|
|
|
|
#error "Unknown board"
|
2009-10-10 02:31:10 +03:00
|
|
|
#endif
|
2009-07-05 11:52:44 +03:00
|
|
|
|
|
|
|
cpm_start_lcd ()
|
2009-10-31 10:32:23 +02:00
|
|
|
|
|
|
|
#ifdef NANONOTE
|
2009-12-11 10:43:42 +02:00
|
|
|
// Reset the controller.
|
2009-12-18 10:00:38 +02:00
|
|
|
write_reg (BACKLIGHT1, 0x1e)
|
2009-10-31 10:32:23 +02:00
|
|
|
// Enable display.
|
|
|
|
write_reg (BACKLIGHT1, 0x5f)
|
2009-12-11 10:43:42 +02:00
|
|
|
// Set data to rgbrgbrgb input, with a delta color filter.
|
|
|
|
write_reg (COLOR, 0x01)
|
2009-10-31 10:32:23 +02:00
|
|
|
#endif
|
2009-06-10 22:42:01 +03:00
|
|
|
|
2010-01-24 22:34:24 +02:00
|
|
|
LCD_CTRL = (bpp << LCD_CTRL_BPP_BIT) | LCD_CTRL_BST_16 | LCD_CTRL_EOFM
|
2009-12-11 10:43:42 +02:00
|
|
|
LCD_CFG = cfg
|
|
|
|
LCD_HSYNC = hpe
|
|
|
|
LCD_VSYNC = vpe
|
|
|
|
LCD_VAT = (ht << 16) | vt
|
|
|
|
LCD_DAH = (hds << 16) | hde
|
|
|
|
LCD_DAV = (vds << 16) | vde
|
|
|
|
LCD_DA0 = physical_descriptor
|
2010-01-24 22:34:24 +02:00
|
|
|
LCD_STATE = 0
|
|
|
|
LCD_CTRL = (bpp << LCD_CTRL_BPP_BIT) | LCD_CTRL_BST_16 | LCD_CTRL_EOFM | LCD_CTRL_ENA
|
2009-12-11 10:43:42 +02:00
|
|
|
|
2009-12-27 01:12:35 +02:00
|
|
|
static void putchar (unsigned x, unsigned y, unsigned ch):
|
2009-07-23 13:06:32 +03:00
|
|
|
if ch < 32 || ch > 126:
|
|
|
|
ch = 127
|
|
|
|
ch -= 32
|
2009-07-21 13:17:52 +03:00
|
|
|
for unsigned k = 0; k < 6; ++k:
|
|
|
|
for unsigned r = 0; r < 8; ++r:
|
2009-12-27 01:12:35 +02:00
|
|
|
LCD_FRAMEBUFFER_BASE[(y * 8 + r) * h + x * 6 + k] = charset[ch][r][k] * 0x00010101
|
|
|
|
|
2009-07-21 13:17:52 +03:00
|
|
|
|
2009-12-26 15:17:06 +02:00
|
|
|
static unsigned log_x = LOG_X_BASE, log_y = LOG_Y_BASE
|
2009-07-21 13:17:52 +03:00
|
|
|
static void inc_logx ():
|
2009-10-10 02:31:10 +03:00
|
|
|
if ++log_x >= h / 6:
|
2009-12-26 15:17:06 +02:00
|
|
|
log_x = LOG_X_BASE
|
2009-10-10 02:31:10 +03:00
|
|
|
if ++log_y >= v / 8:
|
2009-12-26 15:17:06 +02:00
|
|
|
log_y = LOG_Y_BASE
|
2009-07-21 13:17:52 +03:00
|
|
|
|
2009-07-23 13:06:32 +03:00
|
|
|
static void log_char (unsigned ch):
|
|
|
|
switch ch:
|
|
|
|
case '\n':
|
2009-10-10 02:31:10 +03:00
|
|
|
while log_x < h / 6:
|
2009-07-23 13:06:32 +03:00
|
|
|
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++)
|
|
|
|
|
2009-09-06 12:04:09 +03:00
|
|
|
static void log_num (Kernel::Num n):
|
2009-07-23 13:06:32 +03:00
|
|
|
char const *encode = "0123456789abcdef"
|
|
|
|
log_char ('[')
|
|
|
|
for unsigned i = 0; i < 8; ++i:
|
2009-08-18 00:11:15 +03:00
|
|
|
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])
|
2009-07-23 13:06:32 +03:00
|
|
|
log_char (']')
|
|
|
|
|
2009-09-06 12:04:09 +03:00
|
|
|
static void log_msg ():
|
|
|
|
log_str ("prot:")
|
|
|
|
log_num (Kernel::recv.protected_data)
|
2009-07-23 13:06:32 +03:00
|
|
|
log_str ("data:")
|
2009-08-18 00:11:15 +03:00
|
|
|
for unsigned i = 0; i < 2; ++i:
|
2009-09-06 12:04:09 +03:00
|
|
|
log_num (Kernel::recv.data[i])
|
2009-07-23 13:06:32 +03:00
|
|
|
log_char ('\n')
|
2009-07-21 13:17:52 +03:00
|
|
|
|
2009-10-31 10:32:23 +02:00
|
|
|
enum captype:
|
2009-12-26 15:17:06 +02:00
|
|
|
LOG = 32
|
|
|
|
BACKLIGHT
|
2010-01-24 22:34:24 +02:00
|
|
|
LCD
|
2009-10-31 10:32:23 +02:00
|
|
|
|
2009-12-18 10:00:38 +02:00
|
|
|
static unsigned spot (unsigned x, unsigned y, unsigned cx, unsigned cy):
|
|
|
|
unsigned dx2 = (x - cx) * (x - cx)
|
|
|
|
unsigned dy2 = (y - cy) * (y - cy)
|
|
|
|
unsigned d2 = dx2 + dy2
|
|
|
|
unsigned l = 120
|
|
|
|
if d2 >= l * l:
|
|
|
|
return 0
|
|
|
|
return ((l * l - d2 - 1) << 8) / (l * l)
|
|
|
|
|
2009-09-06 12:04:09 +03:00
|
|
|
Kernel::Num start ():
|
2009-12-26 15:17:06 +02:00
|
|
|
Kernel::schedule ()
|
2009-06-10 23:54:12 +03:00
|
|
|
map_lcd ()
|
|
|
|
map_cpm ()
|
2009-10-31 10:32:23 +02:00
|
|
|
#ifdef NANONOTE
|
|
|
|
map_gpio ()
|
|
|
|
#endif
|
2009-06-10 22:42:01 +03:00
|
|
|
|
2009-07-23 13:06:32 +03:00
|
|
|
Descriptor descriptor __attribute__ ((aligned (16)))
|
|
|
|
unsigned pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS
|
2010-01-24 22:34:24 +02:00
|
|
|
#if 0
|
2009-09-06 12:04:09 +03:00
|
|
|
unsigned physical = Kernel::my_memory.alloc_range (pages)
|
2009-08-24 22:02:35 +03:00
|
|
|
assert (physical & PAGE_MASK && ~physical)
|
2009-08-05 11:16:24 +03:00
|
|
|
for unsigned i = 0; i < pages; ++i:
|
2009-09-06 12:04:09 +03:00
|
|
|
Kernel::Page p = Kernel::my_memory.create_page ()
|
2009-12-18 10:00:38 +02:00
|
|
|
p.alloc_physical (physical + (i << PAGE_BITS), false, true)
|
|
|
|
Kernel::my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + (i << PAGE_BITS))
|
2009-09-06 12:04:09 +03:00
|
|
|
Kernel::free_cap (p)
|
2009-10-10 02:31:10 +03:00
|
|
|
for unsigned y = 0; y < v; ++y:
|
|
|
|
for unsigned x = 0; x < h; ++x:
|
2009-12-18 10:00:38 +02:00
|
|
|
unsigned r = spot (x, y, 100, 160)
|
|
|
|
unsigned g = spot (x, y, 160, 60)
|
|
|
|
unsigned b = spot (x, y, 220, 160)
|
2009-10-31 10:32:23 +02:00
|
|
|
#if defined (TRENDTAC)
|
|
|
|
LCD_FRAMEBUFFER_BASE[y * h + x] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)
|
|
|
|
#elif defined (NANONOTE)
|
2009-12-18 10:00:38 +02:00
|
|
|
LCD_FRAMEBUFFER_BASE[y * h + x] = (r << 16) | (g << 8) | b
|
2009-10-31 10:32:23 +02:00
|
|
|
#else
|
|
|
|
#error "Define your framebuffer format."
|
|
|
|
#endif
|
2010-01-24 22:34:24 +02:00
|
|
|
#else
|
|
|
|
unsigned physical = 0
|
|
|
|
#endif
|
2009-09-06 12:04:09 +03:00
|
|
|
Kernel::Page p = Kernel::my_memory.mapping (&descriptor)
|
2009-10-31 10:32:23 +02:00
|
|
|
unsigned paddr = p.physical_address ()
|
|
|
|
physical_descriptor = paddr + ((unsigned)&descriptor & ~PAGE_MASK)
|
2009-09-06 12:04:09 +03:00
|
|
|
Kernel::free_cap (p)
|
2009-07-23 13:06:32 +03:00
|
|
|
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")
|
2009-08-24 22:02:35 +03:00
|
|
|
reset ()
|
2009-06-22 17:13:00 +03:00
|
|
|
|
2009-10-10 02:31:10 +03:00
|
|
|
#if defined (TRENDTAC)
|
2009-12-11 10:43:42 +02:00
|
|
|
Kernel::Cap logcap = Kernel::my_receiver.create_capability (LOG)
|
2009-08-18 00:11:15 +03:00
|
|
|
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
|
2009-10-10 02:31:10 +03:00
|
|
|
#endif
|
2009-07-23 13:06:32 +03:00
|
|
|
|
2009-12-26 15:17:06 +02:00
|
|
|
// Register the backlight device.
|
|
|
|
Kernel::Cap backlight = Kernel::my_receiver.create_capability (BACKLIGHT)
|
2010-01-24 22:34:24 +02:00
|
|
|
Kernel::my_parent.provide_device <Setting> (backlight.copy ())
|
|
|
|
Kernel::free_cap (backlight)
|
|
|
|
|
|
|
|
// Register the display device.
|
|
|
|
Kernel::Cap display = Kernel::my_receiver.create_capability (LCD)
|
|
|
|
Kernel::my_parent.provide_device <Display> (display.copy ())
|
|
|
|
Kernel::free_cap (display)
|
|
|
|
Kernel::my_parent.init_done ()
|
2009-12-26 15:17:06 +02:00
|
|
|
|
2009-10-10 02:31:10 +03:00
|
|
|
Kernel::Cap eof_cb
|
|
|
|
bool have_eof = false
|
2009-12-26 15:17:06 +02:00
|
|
|
bool is_on = true
|
|
|
|
unsigned backlight_user = 0
|
2010-01-24 22:34:24 +02:00
|
|
|
unsigned current_backlight = 0
|
2009-06-10 22:42:01 +03:00
|
|
|
while true:
|
2009-09-06 12:04:09 +03:00
|
|
|
Kernel::wait ()
|
2009-12-30 23:41:45 +02:00
|
|
|
//log_msg ()
|
2009-12-26 15:17:06 +02:00
|
|
|
switch Kernel::recv.protected_data.h:
|
|
|
|
case 0:
|
|
|
|
switch Kernel::recv.protected_data.l:
|
|
|
|
case IRQ_LCD:
|
|
|
|
have_eof = false
|
2010-01-24 22:34:24 +02:00
|
|
|
eof_cb.invoke ()
|
2009-12-26 15:17:06 +02:00
|
|
|
Kernel::free_cap (eof_cb)
|
|
|
|
break
|
|
|
|
#if defined (TRENDTAC)
|
|
|
|
case LOG:
|
|
|
|
log_char (Kernel::recv.data[0].l)
|
|
|
|
break
|
|
|
|
#endif
|
|
|
|
case BACKLIGHT:
|
2010-01-24 22:34:24 +02:00
|
|
|
Kernel::Cap reply = Kernel::get_reply ()
|
|
|
|
Kernel::Cap arg = Kernel::get_arg ()
|
|
|
|
Device::host (BACKLIGHT, current_backlight, reply, arg)
|
|
|
|
break
|
|
|
|
case LCD:
|
|
|
|
Kernel::Cap reply = Kernel::get_reply ()
|
|
|
|
Kernel::Cap arg = Kernel::get_arg ()
|
2009-12-26 15:17:06 +02:00
|
|
|
switch Kernel::recv.data[0].l:
|
|
|
|
case Device::CREATE_USER:
|
2010-01-24 22:34:24 +02:00
|
|
|
Kernel::Memory mem (arg)
|
|
|
|
unsigned width = Kernel::recv.data[0].h >> 16
|
|
|
|
unsigned height = Kernel::recv.data[0].h & 0xffff
|
|
|
|
unsigned mode = Kernel::recv.data[1].l & ~PAGE_MASK
|
|
|
|
unsigned address = Kernel::recv.data[1].l & PAGE_MASK
|
|
|
|
if (width != 0 && width != h) || (height != 0 && height != v) || mode != 0:
|
|
|
|
reply.invoke (Kernel::ERR_INVALID_ARGUMENT)
|
|
|
|
kdebug ("invalid framebuffer requested\n")
|
|
|
|
Kernel::panic (0)
|
|
|
|
Kernel::free_cap (reply)
|
|
|
|
Kernel::free_cap (arg)
|
|
|
|
break
|
|
|
|
Kernel::Caps caps = mem.create_caps (4)
|
|
|
|
caps.set (1, mem.copy ())
|
|
|
|
unsigned slot = caps.use ()
|
|
|
|
unsigned physical = mem.alloc_range (pages)
|
|
|
|
if physical & ~PAGE_MASK:
|
|
|
|
kdebug ("can't allocate framebuffer\n")
|
|
|
|
Kernel::panic (0)
|
|
|
|
assert (physical & PAGE_MASK && ~physical)
|
|
|
|
Kernel::set_recv_arg (Kernel::Cap (slot, 0))
|
|
|
|
Kernel::my_receiver.create_capability (Kernel::Num (physical, LCD))
|
|
|
|
for unsigned i = 0; i < pages; ++i:
|
|
|
|
Kernel::Page p = mem.create_page ()
|
|
|
|
p.alloc_physical (physical + (i << PAGE_BITS), false, true)
|
|
|
|
if address != ~0:
|
|
|
|
//Kernel::panic (0xdeaddead)
|
|
|
|
mem.map (p, address + (i << PAGE_BITS))
|
|
|
|
Kernel::free_cap (p)
|
|
|
|
Kernel::free_slot (slot)
|
|
|
|
reply.invoke (0, 0, caps.copy ())
|
|
|
|
Kernel::free_cap (caps)
|
2009-12-26 15:17:06 +02:00
|
|
|
break
|
|
|
|
case Device::DESTROY_USER:
|
2010-01-24 22:34:24 +02:00
|
|
|
unsigned slot = Kernel::Caps (arg).use ()
|
|
|
|
unsigned physical = Kernel::my_receiver.get_protected (Kernel::Cap (slot, 0)).l
|
|
|
|
if physical == ~0:
|
|
|
|
kdebug ("unable to destroy framebuffer with wrong cap0\n")
|
|
|
|
Kernel::panic (0)
|
|
|
|
break
|
|
|
|
if descriptor.frame == physical && is_on:
|
|
|
|
lcd_clr_ena ()
|
|
|
|
#ifdef NANONOTE
|
|
|
|
write_reg (BACKLIGHT1, 0x5e)
|
|
|
|
#endif
|
|
|
|
Kernel::Memory mem = Kernel::Cap (slot, 1)
|
|
|
|
for unsigned i = 0; i < pages; ++i:
|
|
|
|
mem.destroy (Kernel::Cap (slot, 2 + i))
|
|
|
|
mem.destroy (arg)
|
|
|
|
Kernel::free_slot (slot)
|
|
|
|
reply.invoke ()
|
2009-12-26 15:17:06 +02:00
|
|
|
break
|
|
|
|
case Device::USE:
|
2010-01-24 22:34:24 +02:00
|
|
|
Kernel::Cap first = Kernel::Caps (arg).get (0)
|
|
|
|
unsigned physical = Kernel::my_receiver.get_protected (first).l
|
|
|
|
if physical == ~0:
|
|
|
|
kdebug ("unable to use framebuffer with wrong cap0\n")
|
|
|
|
Kernel::panic (0)
|
|
|
|
break
|
|
|
|
Kernel::free_cap (first)
|
|
|
|
bool was_unused = descriptor.frame == ~0
|
|
|
|
descriptor.frame = physical
|
|
|
|
unsigned dptr = (unsigned)&descriptor
|
|
|
|
__asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
|
|
|
|
if was_unused && is_on:
|
|
|
|
lcd_set_ena ()
|
|
|
|
#ifdef NANONOTE:
|
|
|
|
write_reg (BACKLIGHT1, 0x5f)
|
|
|
|
#endif
|
2009-12-26 15:17:06 +02:00
|
|
|
reply.invoke ()
|
|
|
|
break
|
|
|
|
case Device::UNUSE:
|
2010-01-24 22:34:24 +02:00
|
|
|
Kernel::Cap first = Kernel::Caps (arg).get (0)
|
|
|
|
unsigned physical = Kernel::my_receiver.get_protected (first).l
|
|
|
|
if physical == ~0:
|
|
|
|
kdebug ("unable to unuse framebuffer with wrong cap0\n")
|
|
|
|
Kernel::panic (0)
|
|
|
|
break
|
|
|
|
Kernel::free_cap (first)
|
|
|
|
if descriptor.frame == physical:
|
|
|
|
lcd_clr_ena ()
|
|
|
|
#ifdef NANONOTE
|
|
|
|
write_reg (BACKLIGHT1, 0x5e)
|
|
|
|
#endif
|
2009-12-26 15:17:06 +02:00
|
|
|
reply.invoke ()
|
|
|
|
break
|
|
|
|
default:
|
2010-01-24 22:34:24 +02:00
|
|
|
Kernel::panic (0, "invalid operation for lcd device")
|
|
|
|
Kernel::free_cap (arg)
|
|
|
|
Kernel::free_cap (reply)
|
2009-12-26 15:17:06 +02:00
|
|
|
break
|
|
|
|
default:
|
2010-01-24 22:34:24 +02:00
|
|
|
Kernel::panic (Kernel::recv.protected_data.l, "invalid operation for master lcd")
|
2009-12-26 15:17:06 +02:00
|
|
|
break
|
|
|
|
break
|
|
|
|
case BACKLIGHT:
|
2010-01-24 22:34:24 +02:00
|
|
|
if current_backlight != Kernel::recv.protected_data.l:
|
2009-12-26 15:17:06 +02:00
|
|
|
log_char ('&')
|
|
|
|
log_num (current_backlight)
|
|
|
|
log_num (Kernel::recv.protected_data)
|
|
|
|
log_char ('\n')
|
|
|
|
break
|
|
|
|
switch Kernel::recv.data[0].l:
|
|
|
|
case Setting::SET:
|
|
|
|
// TODO
|
|
|
|
unsigned state = Kernel::recv.data[1].l
|
|
|
|
if !state:
|
|
|
|
#if defined (NANONOTE)
|
|
|
|
if is_on:
|
|
|
|
write_reg (BACKLIGHT1, 0x5e)
|
|
|
|
is_on = false
|
|
|
|
#else
|
|
|
|
#endif
|
|
|
|
else:
|
|
|
|
#if defined (NANONOTE)
|
|
|
|
if !is_on:
|
|
|
|
write_reg (BACKLIGHT1, 0x5f)
|
|
|
|
is_on = true
|
|
|
|
#else
|
|
|
|
#endif
|
|
|
|
Kernel::recv.reply.invoke ()
|
|
|
|
break
|
|
|
|
case Setting::GET_RANGE:
|
|
|
|
Kernel::recv.reply.invoke (~0)
|
|
|
|
break
|
|
|
|
default:
|
2010-01-24 22:34:24 +02:00
|
|
|
Kernel::panic (0, "invalid operation for backlight")
|
2009-12-26 15:17:06 +02:00
|
|
|
break
|
2009-06-10 22:42:01 +03:00
|
|
|
break
|
2010-01-24 22:34:24 +02:00
|
|
|
case LCD:
|
|
|
|
if descriptor.frame != Kernel::recv.protected_data.l:
|
|
|
|
kdebug ("invalid user requesting lcd\n")
|
|
|
|
Kernel::panic (0)
|
|
|
|
break
|
|
|
|
switch Kernel::recv.data[0].l:
|
|
|
|
case Display::SET_EOF_CB:
|
|
|
|
Kernel::Cap reply = Kernel::get_reply ()
|
|
|
|
Kernel::Cap arg = Kernel::get_arg ()
|
|
|
|
if have_eof:
|
|
|
|
Kernel::free_cap (eof_cb)
|
|
|
|
kdebug ("replacing eof_cb\n")
|
|
|
|
Kernel::panic (0)
|
|
|
|
else:
|
|
|
|
lcd_clr_eof ()
|
|
|
|
Kernel::register_interrupt (IRQ_LCD)
|
|
|
|
have_eof = true
|
|
|
|
eof_cb = arg
|
|
|
|
reply.invoke ()
|
|
|
|
Kernel::free_cap (reply)
|
|
|
|
break
|
|
|
|
case Display::GET_INFO:
|
|
|
|
kdebug ("get_info isn't defined yet.\n")
|
|
|
|
Kernel::panic (0)
|
|
|
|
default:
|
|
|
|
Kernel::panic (0, "invalid operation for lcd")
|
2009-07-23 13:06:32 +03:00
|
|
|
break
|
2009-09-06 12:04:09 +03:00
|
|
|
default:
|
2010-01-24 22:34:24 +02:00
|
|
|
Kernel::panic (0, "invalid master operation type for lcd")
|
2009-06-10 22:42:01 +03:00
|
|
|
break
|