/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2021 Aidan MacDonald * * 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 "lcd.h" #include "kernel.h" #include "lcd-x1000.h" #include "gpio-x1000.h" #include "system.h" static const uint32_t fiio_lcd_cmd_enable[] = { /* Software reset */ LCD_INSTR_CMD, 0x01, LCD_INSTR_UDELAY, 120000, /* Sleep out */ LCD_INSTR_CMD, 0x11, LCD_INSTR_UDELAY, 5000, /* Memory access order */ LCD_INSTR_CMD, 0x36, LCD_INSTR_DAT, 0x00, /* Row and column address set */ LCD_INSTR_CMD, 0x2a, LCD_INSTR_DAT, 0x00, LCD_INSTR_DAT, 0x00, LCD_INSTR_DAT, (LCD_WIDTH >> 8) & 0xff, LCD_INSTR_DAT, (LCD_WIDTH & 0xff), LCD_INSTR_CMD, 0x2b, LCD_INSTR_DAT, 0x00, LCD_INSTR_DAT, 0x00, LCD_INSTR_DAT, (LCD_HEIGHT >> 8) & 0xff, LCD_INSTR_DAT, (LCD_HEIGHT & 0xff), /* Interface pixel format */ LCD_INSTR_CMD, 0x3a, LCD_INSTR_DAT, 0x05, /* Enable display inversion */ LCD_INSTR_CMD, 0x21, /* Porch setting */ LCD_INSTR_CMD, 0xb2, LCD_INSTR_DAT, 0x0c, LCD_INSTR_DAT, 0x0c, LCD_INSTR_DAT, 0x00, LCD_INSTR_DAT, 0x33, LCD_INSTR_DAT, 0x33, /* Gate control */ LCD_INSTR_CMD, 0xb7, LCD_INSTR_DAT, 0x35, /* VCOM setting */ LCD_INSTR_CMD, 0xbb, LCD_INSTR_DAT, 0x1f, /* Backlight control 5 */ LCD_INSTR_CMD, 0xbc, LCD_INSTR_DAT, 0xec, /* Backlight control 6 */ LCD_INSTR_CMD, 0xbd, LCD_INSTR_DAT, 0xfe, /* Voltage settings */ LCD_INSTR_CMD, 0xc2, LCD_INSTR_DAT, 0x01, LCD_INSTR_CMD, 0xc3, LCD_INSTR_DAT, 0x19, LCD_INSTR_CMD, 0xc4, LCD_INSTR_DAT, 0x20, /* Frame rate control */ LCD_INSTR_CMD, 0xc6, LCD_INSTR_DAT, 0x0f, /* = 60 fps */ /* Power control 1 */ LCD_INSTR_CMD, 0xd0, LCD_INSTR_DAT, 0xa4, LCD_INSTR_DAT, 0xa1, /* d6 Unknown */ LCD_INSTR_CMD, 0xd6, LCD_INSTR_DAT, 0xa1, /* Positive gamma correction */ LCD_INSTR_CMD, 0xe0, LCD_INSTR_DAT, 0xd0, LCD_INSTR_DAT, 0x06, LCD_INSTR_DAT, 0x0c, LCD_INSTR_DAT, 0x0a, LCD_INSTR_DAT, 0x09, LCD_INSTR_DAT, 0x0a, LCD_INSTR_DAT, 0x32, LCD_INSTR_DAT, 0x33, LCD_INSTR_DAT, 0x49, LCD_INSTR_DAT, 0x19, LCD_INSTR_DAT, 0x14, LCD_INSTR_DAT, 0x15, LCD_INSTR_DAT, 0x2b, LCD_INSTR_DAT, 0x34, /* Negative gamma correction */ LCD_INSTR_CMD, 0xe1, LCD_INSTR_DAT, 0xd0, LCD_INSTR_DAT, 0x06, LCD_INSTR_DAT, 0x0c, LCD_INSTR_DAT, 0x0a, LCD_INSTR_DAT, 0x09, LCD_INSTR_DAT, 0x11, LCD_INSTR_DAT, 0x37, LCD_INSTR_DAT, 0x33, LCD_INSTR_DAT, 0x49, LCD_INSTR_DAT, 0x19, LCD_INSTR_DAT, 0x14, LCD_INSTR_DAT, 0x15, LCD_INSTR_DAT, 0x2d, LCD_INSTR_DAT, 0x34, /* Tearing effect line ON, mode=0 (vsync signal) */ LCD_INSTR_CMD, 0x35, LCD_INSTR_DAT, 0x00, /* Display ON */ LCD_INSTR_CMD, 0x29, LCD_INSTR_END, }; static const uint32_t fiio_lcd_cmd_sleep[] = { /* Display OFF */ LCD_INSTR_CMD, 0x28, /* Sleep IN */ LCD_INSTR_CMD, 0x10, LCD_INSTR_UDELAY, 5000, LCD_INSTR_END, }; static const uint32_t fiio_lcd_cmd_wake[] = { /* Sleep OUT */ LCD_INSTR_CMD, 0x11, LCD_INSTR_UDELAY, 5000, /* Display ON */ LCD_INSTR_CMD, 0x29, LCD_INSTR_END, }; static const uint8_t __attribute__((aligned(64))) fiio_lcd_dma_wr_cmd[] = {0x00, 0x00, 0x00, 0x2c}; const struct lcd_tgt_config lcd_tgt_config = { .bus_width = 16, .cmd_width = 8, .use_6800_mode = 0, .use_serial = 0, .clk_polarity = 0, .dc_polarity = 0, .wr_polarity = 1, .te_enable = 1, .te_polarity = 1, .te_narrow = 0, .dma_wr_cmd_buf = &fiio_lcd_dma_wr_cmd, .dma_wr_cmd_size = sizeof(fiio_lcd_dma_wr_cmd), }; void lcd_tgt_enable(bool enable) { if(enable) { /* reset controller, probably */ gpio_set_level(GPIO_LCD_CE, 1); gpio_set_level(GPIO_LCD_RD, 1); mdelay(5); gpio_set_level(GPIO_LCD_CE, 0); /* set the clock whatever it is... */ lcd_set_clock(X1000_CLK_SCLK_A, 30000000); /* program the initial configuration */ lcd_exec_commands(&fiio_lcd_cmd_enable[0]); } else { /* go to sleep mode first */ lcd_exec_commands(&fiio_lcd_cmd_sleep[0]); /* ensure we wait a total of 120ms before power off */ mdelay(115); /* this is intended to power off the panel but I'm not sure it does */ gpio_set_level(GPIO_LCD_CE, 0); gpio_set_level(GPIO_LCD_RD, 0); } } void lcd_tgt_sleep(bool sleep) { if(sleep) lcd_exec_commands(&fiio_lcd_cmd_sleep[0]); else lcd_exec_commands(&fiio_lcd_cmd_wake[0]); }