#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" // Pin definitions, all in port 2. #define PWM_ENABLE (1 << 30) #define SPEN (1 << 0) //LCD_SPL #define SPCK (1 << 1) //LCD_CLS #define SPDA (1 << 2) //LCD_PS #define LCD_RET (1 << 3) //LCD_REV //use for lcd reset static void set_backlight (bool state): if state: PWM_DUT (0) = 300 PWM_CTR (0) = 0xbf GPIO_GPDR (2) |= PWM_ENABLE else: PWM_DUT (0) = 0 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) // 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) GPIO_GPDR (2) |= LCD_RET udelay (10000) lcd_enable () // For now, support only 16 bpp. // Screen is 800x480 tft. 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 // Stop lcd. CPM_MSCR |= 1 << 7 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 // Start lcd. CPM_MSCR &= ~(1 << 7) udelay (1000) int main (): map_gpio () map_pwm0 () map_lcd () map_cpm () reset () while true: set_backlight (false) kdebug (0) set_backlight (true) kdebug (0) schedule () while true: Message msg if !wait (&msg): continue switch msg.protected_data: case LCD_BACKLIGHT: set_backlight (msg.data[0]) break case LCD_RESET: reset () break