/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (c) 2013 by Amaury Pouly * * 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 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include /* off_t */ #include #include "cpu.h" #include "system.h" #include "backlight-target.h" #include "lcd.h" #include "lcdif-imx233.h" #include "clkctrl-imx233.h" #include "pinctrl-imx233.h" #include "dcp-imx233.h" #include "logf.h" #ifndef BOOTLOADER #include "button.h" #include "font.h" #include "action.h" #endif #ifdef HAVE_LCD_ENABLE static bool lcd_on; #endif static bool lcd_has_power; static bool lcd_kind; static void lcd_send(bool data, uint8_t val) { imx233_lcdif_pio_send(data, 1, &val); } void lcd_init_device(void) { // determine power type imx233_pinctrl_acquire(3, 16, "lcd power kind"); imx233_pinctrl_set_function(3, 16, PINCTRL_FUNCTION_GPIO); imx233_pinctrl_enable_gpio(3, 16, false); udelay(10); lcd_has_power = !imx233_pinctrl_get_gpio(3, 16); if(lcd_has_power) { imx233_pinctrl_acquire(0, 27, "lcd power"); imx233_pinctrl_set_function(0, 27, PINCTRL_FUNCTION_GPIO); imx233_pinctrl_enable_gpio(0, 27, true); imx233_pinctrl_set_gpio(0, 27, true); } // determine kind (don't acquire pin because it's a lcdif pin !) imx233_pinctrl_set_function(1, 0, PINCTRL_FUNCTION_GPIO); imx233_pinctrl_enable_gpio(1, 0, false); udelay(10); lcd_kind = imx233_pinctrl_get_gpio(1, 0); imx233_lcdif_init(); imx233_lcdif_reset_lcd(false); imx233_lcdif_reset_lcd(true); imx233_lcdif_setup_system_pins(16); imx233_lcdif_set_timings(2, 2, 2, 2); imx233_lcdif_set_word_length(8); // set mux ratio lcd_send(false, 0xca); lcd_send(true, 131); // set remap, color and depth lcd_send(false, 0xa0); lcd_send(true, 0x74); // set master contrast lcd_send(false, 0xc7); lcd_send(true, 0x8); // set V_COMH lcd_send(false, 0xbe); lcd_send(true, lcd_kind ? 0x1c : 0x18); // set color contrasts lcd_send(false, 0xc1); lcd_send(true, 0x7b); lcd_send(true, 0x69); lcd_send(true, lcd_kind ? 0xcf : 0x9f); // set timings lcd_send(false, 0xb1); lcd_send(true, 0x1f); lcd_send(false, 0xb3); lcd_send(true, 0x80); // set precharge voltages lcd_send(false, 0xbb); lcd_send(true, 0x00); lcd_send(true, 0x00); lcd_send(true, 0x00); // set master config lcd_send(false, 0xad); lcd_send(true, 0x8a); // set power saving mode lcd_send(false, 0xb0); lcd_send(true, 0x00); // set normal display (seem to be a SSD1338 only command, not present in SS1339 datasheet) lcd_send(false, 0xd1); lcd_send(true, 0x02); // set LUT lcd_send(false, 0xb8); static uint8_t lut[32] = { 0x01, 0x15, 0x19, 0x1D, 0x21, 0x25, 0x29, 0x2D, 0x31, 0x35, 0x39, 0x3D, 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, 0x81, 0x85, 0x89, 0x8D }; for(int i = 0; i < 32; i++) lcd_send(true, lut[i]); // set display offset (this lcd is really wired strangely) lcd_send(false, 0xa2); lcd_send(true, 128); // normal display lcd_send(false, 0xa6); // sleep mode off lcd_send(false, 0xaf); // write ram lcd_send(false, 0x5c); imx233_lcdif_set_word_length(16); for(int y = 0; y < LCD_HEIGHT; y++) for(int x = 0; x < LCD_WIDTH; x++) { uint16_t v = 0; imx233_lcdif_pio_send(true, 1, &v); } #ifdef HAVE_LCD_ENABLE lcd_on = true; #endif } #ifdef HAVE_LCD_ENABLE bool lcd_active(void) { return lcd_on; } void lcd_enable(bool enable) { if(lcd_on == enable) return; lcd_on = enable; } #endif void lcd_set_contrast(int val) { // NOTE: this should not interfere with lcd_update_rect imx233_lcdif_wait_ready(); imx233_lcdif_set_word_length(8); // set contrast lcd_send(false, 0xc7); lcd_send(true, val); } void lcd_update(void) { lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); } void lcd_update_rect(int x, int y, int w, int h) { #ifdef HAVE_LCD_ENABLE if(!lcd_on) return; #endif imx233_lcdif_wait_ready(); imx233_lcdif_set_word_length(8); // set column address lcd_send(false, 0x15); lcd_send(true, x); lcd_send(true, x + w - 1); // set row address lcd_send(false, 0x75); lcd_send(true, y); lcd_send(true, y + h - 1); lcd_send(false, 0x5c); imx233_lcdif_set_word_length(16); for(int yy = y; yy < y + h; yy++) imx233_lcdif_pio_send(true, w, FBADDR(x, yy)); } #ifndef BOOTLOADER bool lcd_debug_screen(void) { lcd_setfont(FONT_SYSFIXED); while(1) { int button = get_action(CONTEXT_STD, HZ / 10); switch(button) { case ACTION_STD_NEXT: case ACTION_STD_PREV: case ACTION_STD_OK: case ACTION_STD_MENU: lcd_setfont(FONT_UI); return true; case ACTION_STD_CANCEL: lcd_setfont(FONT_UI); return false; } lcd_clear_display(); lcd_putsf(0, 0, "has power: %d", lcd_has_power); lcd_putsf(0, 1, "lcd kind: %d", lcd_kind); lcd_update(); yield(); } return true; } #endif