summaryrefslogtreecommitdiffstats
path: root/src/target/firmware
diff options
context:
space:
mode:
authorSteve Markgraf <steve@steve-m.de>2022-11-22 12:33:14 +0100
committerVadim Yanitskiy <vyanitskiy@sysmocom.de>2022-12-09 20:25:01 +0700
commitaeb19ea3efaaaab76a74f85684d7a9f7392a15d0 (patch)
tree52a8093c7071aeb19fbe8af51d2858f3091c7468 /src/target/firmware
parentc7b7b20ac6bdda636b7dafb559937ea165bbeae3 (diff)
fw: Add display driver for K200i/K220i
Diffstat (limited to 'src/target/firmware')
-rw-r--r--src/target/firmware/Makefile3
-rw-r--r--src/target/firmware/board/se_k2x0/init.c25
-rw-r--r--src/target/firmware/fb/fb_k2x0.c190
3 files changed, 208 insertions, 10 deletions
diff --git a/src/target/firmware/Makefile b/src/target/firmware/Makefile
index af50d45e..18450ac1 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 b957f86e..71218670 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 00000000..7e433cd8
--- /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 <steve@steve-m.de>
+ *
+ * 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 <fb/framebuffer.h>
+#include <fb/fb_rgb332.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <delay.h>
+#include <memory.h>
+
+#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;