From aeb19ea3efaaaab76a74f85684d7a9f7392a15d0 Mon Sep 17 00:00:00 2001 From: Steve Markgraf Date: Tue, 22 Nov 2022 12:33:14 +0100 Subject: [PATCH] fw: Add display driver for K200i/K220i Change-Id: I90fbe583983de34f39ec402d5a35712dfe57222b --- src/target/firmware/Makefile | 3 +- src/target/firmware/board/se_k2x0/init.c | 25 +-- src/target/firmware/fb/fb_k2x0.c | 190 +++++++++++++++++++++++ 3 files changed, 208 insertions(+), 10 deletions(-) create mode 100644 src/target/firmware/fb/fb_k2x0.c diff --git a/src/target/firmware/Makefile b/src/target/firmware/Makefile index af50d45ec..18450ac10 100644 --- a/src/target/firmware/Makefile +++ b/src/target/firmware/Makefile @@ -35,6 +35,7 @@ FB_e99_OBJS=$(FB_OBJS) fb/fb_rgb332.o fb/fb_ssd1783.o FB_e86_OBJS=$(FB_OBJS) fb/fb_rgb332.o fb/fb_td014.o FB_j100_OBJS=$(FB_OBJS) fb/fb_rgb332.o fb/fb_ssd1963.o FB_dpl10_OBJS=$(FB_OBJS) fb/fb_rgb332.o fb/fb_s6b33b1x.o +FB_k2x0_OBJS=$(FB_OBJS) fb/fb_rgb332.o fb/fb_k2x0.o FB_dummy_OBJS=$(FB_OBJS) fb/fb_dummy.o # TI Calypso @@ -104,7 +105,7 @@ BOARD_se_j100_ENVIRONMENTS=$(compal_COMMON_ENVIRONMENTS) BOARD_se_k2x0_OBJS=$(calypso_COMMON_OBJS) board/se_k2x0/init.o \ board/se_k2x0/rffe_k2x0.o \ board/gta0x/rf_tables.o board/gta0x/afcparams.o \ - board/common/readcal_tiffs.o battery/dummy.o $(FB_dummy_OBJS) + board/common/readcal_tiffs.o battery/dummy.o $(FB_k2x0_OBJS) BOARD_se_k2x0_ENVIRONMENTS=highram # diff --git a/src/target/firmware/board/se_k2x0/init.c b/src/target/firmware/board/se_k2x0/init.c index b957f86ea..71218670a 100644 --- a/src/target/firmware/board/se_k2x0/init.c +++ b/src/target/firmware/board/se_k2x0/init.c @@ -47,29 +47,36 @@ #include "keymap.h" #define ASIC_CONF_REG 0xfffef008 +#define ARMIO_LATCH_OUT 0xfffe4802 +#define IO_CNTL_REG 0xfffe4804 +#define IO_CONF_REG 0xfffef00a static void board_io_init(void) { uint16_t reg; reg = readw(ASIC_CONF_REG); + /* Set LPG and PWL pin mux */ + reg |= (1 << 6) | (1 << 4); /* TWL3025: Set SPI+RIF RX clock to rising edge */ reg |= (1 << 13) | (1 << 14); writew(reg, ASIC_CONF_REG); + + writew(0xc060, IO_CNTL_REG); + writew(0x03fd, IO_CONF_REG); + + /* set default IO state */ + writew(0x1f83, ARMIO_LATCH_OUT); } void board_init(int with_irq) { - /* Disable watchdog (compal loader leaves it enabled) */ - wdog_enable(0); - - /* Configure the memory interface - TODO: adapt for K2x0i, right now just - * copied from Pirelli DP-L10 */ + /* Configure the memory interface */ calypso_mem_cfg(CALYPSO_nCS0, 4, CALYPSO_MEM_16bit, 1); - calypso_mem_cfg(CALYPSO_nCS1, 4, CALYPSO_MEM_16bit, 1); - calypso_mem_cfg(CALYPSO_nCS2, 5, CALYPSO_MEM_16bit, 1); - calypso_mem_cfg(CALYPSO_nCS3, 4, CALYPSO_MEM_16bit, 1); - calypso_mem_cfg(CALYPSO_CS4, 7, CALYPSO_MEM_16bit, 1); + calypso_mem_cfg(CALYPSO_nCS1, 5, CALYPSO_MEM_16bit, 1); + calypso_mem_cfg(CALYPSO_nCS2, 4, CALYPSO_MEM_16bit, 1); + calypso_mem_cfg(CALYPSO_nCS3, 5, CALYPSO_MEM_16bit, 1); + calypso_mem_cfg(CALYPSO_CS4, 5, CALYPSO_MEM_8bit, 1); /* TODO: add one dummy cycle */ calypso_mem_cfg(CALYPSO_nCS6, 0, CALYPSO_MEM_32bit, 1); calypso_mem_cfg(CALYPSO_nCS7, 0, CALYPSO_MEM_32bit, 0); diff --git a/src/target/firmware/fb/fb_k2x0.c b/src/target/firmware/fb/fb_k2x0.c new file mode 100644 index 000000000..7e433cd87 --- /dev/null +++ b/src/target/firmware/fb/fb_k2x0.c @@ -0,0 +1,190 @@ +/* Framebuffer implementation for SE K200i/K220i - + * combined driver for Core Logic CL761ST and S6B33B1X derivative */ + +/* (C) 2022 by Steve Markgraf + * + * All Rights Reserved + * + * 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 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. + * + */ + +#include +#include + +#include +#include +#include +#include + +#define K2X0_WIDTH 128 +#define K2X0_HEIGHT 128 + +#define ARMIO_LATCH_OUT 0xfffe4802 +#define CS3_ADDR 0x02000000 + +#define DISPLAY_CMD_ADDR (CS3_ADDR + 0) +#define DISPLAY_DATA_ADDR (CS3_ADDR + 2) +#define CL761_INDEX_ADDR (CS3_ADDR + 4) +#define CL761_DATA_ADDR (CS3_ADDR + 6) + +#define CL761_CLK (1 << 4) +#define CL761_RESET (1 << 9) +#define K2X0_ENABLE_BACKLIGHT (1 << 3) + +static uint8_t fb_k2x0_mem[K2X0_WIDTH * K2X0_HEIGHT]; + +static const uint8_t k2x0_initdata[] = { + 0x2c, /* CMD: Standby Mode off */ + 0x02, /* CMD: Oscillation Mode Set */ + 0x01, /* DATA: oscillator on */ + 0x26, /* CMD: DCDC and AMP ON/OFF set */ + 0x01, /* DATA: Booster 1 on */ + 0x26, /* CMD: DCDC and AMP ON/OFF set */ + 0x09, /* DATA: Booster 1 on, OP-AMP on */ + 0x26, /* CMD: DCDC and AMP ON/OFF set */ + 0x0b, /* DATA: Booster 1 + 2 on, OP-AMP on */ + 0x26, /* CMD: DCDC and AMP ON/OFF set */ + 0x0f, /* DATA: Booster 1 + 2 + 3 on, OP-AMP on */ + 0x10, /* CMD: Driver output mode set */ + 0x00, /* DATA: Display duty: 1/66 */ + 0x20, /* CMD: DC-DC Select */ + 0x01, /* DATA: step up x1.5 */ + 0x24, /* CMD: DCDC Clock Division Set */ + 0x08, /* DATA: fPCK = fOSC/32 */ + 0x28, /* CMD: Temperature Compensation set */ + 0x02, /* DATA: slope -0.10%/degC */ + 0x2a, /* CMD: Contrast Control */ + 0x1d, /* DATA: Constrast Level 29 */ + 0x30, /* CMD: Addressing mode set */ + 0x53, /* DATA: 256 color mode (orignal FW uses 0x13, 65k colors) */ + 0x32, /* CMD: ROW vector mode set */ + 0x0e, /* DATA: every subframe */ + 0x34, /* CMD: N-block inversion set */ + 0x8d, /* DATA: inversion on, every 1 block and every 2 frames */ + 0x36, /* CMD: unknown */ + 0x00, /* DATA: unknown */ + 0x40, /* CMD: Entry mode set */ + 0x80, /* DATA: Y address counter mode */ + 0x45, /* CMD: RAM Skip Area Set */ + 0x00, /* DATA: No Skip */ + 0x53, /* CMD: Specified Display Pattern Set */ + 0x00, /* DATA: Normal display */ + 0x55, /* CMD: Partial Display Mode Set */ + 0x00, /* DATA: Partial display OFF */ + 0x51, /* CMD: Display on */ +}; + +uint16_t cl761_read_reg(uint16_t reg) +{ + writew(reg, CL761_INDEX_ADDR); + return readw(CL761_INDEX_ADDR); +} + +void cl761_write_reg(uint8_t reg, uint16_t data) +{ + writew(reg, CL761_INDEX_ADDR); + writew(data, CL761_DATA_ADDR); +} + +static void fb_k2x0_init(void) +{ + unsigned int i; + uint16_t reg; + + printf("%s: initializing LCD.\n", __FUNCTION__); + + reg = readw(ARMIO_LATCH_OUT); + reg &= ~(CL761_RESET | (1 << 1)); + reg |= CL761_CLK; + writew(reg, ARMIO_LATCH_OUT); + delay_ms(10); + reg |= CL761_RESET; + writew(reg, ARMIO_LATCH_OUT); + + /* we need to perform a dummy register read for the + * CL761 to pass through the chip select to the display */ + cl761_read_reg(0x2e); + delay_ms(1); + + reg &= ~CL761_CLK; + reg |= (1 << 1) | K2X0_ENABLE_BACKLIGHT; + writew(reg, ARMIO_LATCH_OUT); + + for (i = 0; i < sizeof(k2x0_initdata); i++) + writew(k2x0_initdata[i], DISPLAY_CMD_ADDR); +} + +static void fb_k2x0_flush(void) +{ + unsigned int i; + int x, y; + uint8_t *p; + uint8_t prepare_disp_write_cmds[] = { + 0x43, /* set column address */ + fb_rgb332->damage_x1, + fb_rgb332->damage_x2 - 1, + 0x42, /* set page address (Y) */ + fb_rgb332->damage_y1, + fb_rgb332->damage_y2 - 1, + }; + + /* If everything's clean, just return */ + if (fb_rgb332->damage_x1 == fb_rgb332->damage_x2 || + fb_rgb332->damage_y1 == fb_rgb332->damage_y2) { + printf("%s: no damage\n", __FUNCTION__); + return; + } + + for (i = 0; i < sizeof(prepare_disp_write_cmds); i++) + writew(prepare_disp_write_cmds[i], DISPLAY_CMD_ADDR); + + for (y = fb_rgb332->damage_y1; y < fb_rgb332->damage_y2; y++) { + p = & fb_rgb332->mem[y * framebuffer->width]; // start of line + p += fb_rgb332->damage_x1; // start of damage area + + for (x = fb_rgb332->damage_x1; x < fb_rgb332->damage_x2; x++) { + /* For whatever reason, the 256 color mode of this + * display uses 'RBG323' */ + uint8_t d = *p++; + d = (d & 0xe0) | ((d & 0x1c) >> 2) | ((d & 0x03) << 3); + + /* We need to transfer the data twice in the 256 color mode. + * Interestingly, the red and green information is taken + * from the first byte written, and the blue information + * from the second byte written. */ + writew(d, DISPLAY_DATA_ADDR); + writew(d, DISPLAY_DATA_ADDR); + } + } + + fb_rgb332->damage_x1 = fb_rgb332->damage_x2 = 0; + fb_rgb332->damage_y1 = fb_rgb332->damage_y2 = 0; +} + +static struct framebuffer fb_k2x0_framebuffer = { + .name = "k2x0", + .init = fb_k2x0_init, + .clear = fb_rgb332_clear, + .boxto = fb_rgb332_boxto, + .lineto = fb_rgb332_lineto, + .putstr = fb_rgb332_putstr, + .flush = fb_k2x0_flush, + .width = K2X0_WIDTH, + .height = K2X0_HEIGHT +}; + +static struct fb_rgb332 fb_k2x0_rgb332 = { + .mem = fb_k2x0_mem +}; + +struct framebuffer *framebuffer = &fb_k2x0_framebuffer; +struct fb_rgb332 *fb_rgb332 = &fb_k2x0_rgb332;