Module Name: src Committed By: tnn Date: Thu Aug 5 19:07:09 UTC 2021
Modified Files: src/sys/dev/ic: ssdfb.c ssdfbvar.h Log Message: ssdfb: support the SSD1353 controller and the DEP 160128A(1)-RGB display DEP 160128A is a 160x128 18-bit RGB OLED display module advertised as having an 8-bit parallel I/O interface. The controller can however attach serially via spi(4) by moving jumper resistors J1 and J2 to GND position. To generate a diff of this commit: cvs rdiff -u -r1.17 -r1.18 src/sys/dev/ic/ssdfb.c cvs rdiff -u -r1.8 -r1.9 src/sys/dev/ic/ssdfbvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ic/ssdfb.c diff -u src/sys/dev/ic/ssdfb.c:1.17 src/sys/dev/ic/ssdfb.c:1.18 --- src/sys/dev/ic/ssdfb.c:1.17 Thu Aug 5 00:16:36 2021 +++ src/sys/dev/ic/ssdfb.c Thu Aug 5 19:07:09 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: ssdfb.c,v 1.17 2021/08/05 00:16:36 tnn Exp $ */ +/* $NetBSD: ssdfb.c,v 1.18 2021/08/05 19:07:09 tnn Exp $ */ /* * Copyright (c) 2019 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ssdfb.c,v 1.17 2021/08/05 00:16:36 tnn Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ssdfb.c,v 1.18 2021/08/05 19:07:09 tnn Exp $"); #include "opt_ddb.h" @@ -75,6 +75,7 @@ static void ssdfb_cursor(void *, int, in /* hardware interface */ static int ssdfb_init_ssd1306(struct ssdfb_softc *); static int ssdfb_init_ssd1322(struct ssdfb_softc *); +static int ssdfb_init_ssd1353(struct ssdfb_softc *); static int ssdfb_set_contrast(struct ssdfb_softc *, uint8_t, bool); static int ssdfb_set_display_on(struct ssdfb_softc *, bool, bool); static int ssdfb_set_mode(struct ssdfb_softc *, u_int); @@ -89,6 +90,7 @@ static void ssdfb_set_usepoll(struct ssd static int ssdfb_sync(struct ssdfb_softc *, bool); static int ssdfb_sync_ssd1306(struct ssdfb_softc *, bool); static int ssdfb_sync_ssd1322(struct ssdfb_softc *, bool); +static int ssdfb_sync_ssd1353(struct ssdfb_softc *, bool); static uint64_t ssdfb_transpose_block(uint8_t *, size_t); /* misc helpers */ @@ -104,7 +106,8 @@ static const char *ssdfb_controller_name [SSDFB_CONTROLLER_UNKNOWN] = "unknown", [SSDFB_CONTROLLER_SSD1306] = "Solomon Systech SSD1306", [SSDFB_CONTROLLER_SH1106] = "Sino Wealth SH1106", - [SSDFB_CONTROLLER_SSD1322] = "Solomon Systech SSD1322" + [SSDFB_CONTROLLER_SSD1322] = "Solomon Systech SSD1322", + [SSDFB_CONTROLLER_SSD1353] = "Solomon Systech SSD1353" }; /* @@ -204,6 +207,44 @@ static const struct ssdfb_product ssdfb_ .p_multiplex_ratio = 0x3f, .p_init = ssdfb_init_ssd1322, .p_sync = ssdfb_sync_ssd1322 + }, + { + .p_product_id = SSDFB_PRODUCT_SSD1353_GENERIC, + .p_controller_id = SSDFB_CONTROLLER_SSD1353, + .p_name = "generic", + .p_width = 160, + .p_height = 132, + .p_bits_per_pixel = 32, + .p_rgb = true, + .p_panel_shift = 0, + .p_compin_cfg = SSD1353_REMAP_RGB | SSD1353_REMAP_SPLIT_ODD_EVEN + | __SHIFTIN(2, SSD1353_REMAP_PIXEL_FORMAT_MASK), + .p_vcomh_deselect_level = SSD1353_DEFAULT_VCOMH, + .p_fosc = SSD1353_DEFAULT_FREQUENCY, + .p_fosc_div = SSD1353_DEFAULT_DIVIDER, + .p_default_contrast = SSD1353_DEFAULT_CONTRAST_CONTROL, + .p_multiplex_ratio = 0x83, + .p_init = ssdfb_init_ssd1353, + .p_sync = ssdfb_sync_ssd1353 + }, + { + .p_product_id = SSDFB_PRODUCT_DEP_160128A_RGB, + .p_controller_id = SSDFB_CONTROLLER_SSD1353, + .p_name = "Display Elektronik GmbH DEP 160128A(1)-RGB", + .p_width = 160, + .p_height = 128, + .p_bits_per_pixel = 32, + .p_rgb = true, + .p_panel_shift = 0, + .p_compin_cfg = SSD1353_REMAP_RGB | SSD1353_REMAP_SPLIT_ODD_EVEN + | __SHIFTIN(2, SSD1353_REMAP_PIXEL_FORMAT_MASK), + .p_vcomh_deselect_level = SSD1353_DEFAULT_VCOMH, + .p_fosc = SSD1353_DEFAULT_FREQUENCY, + .p_fosc_div = SSD1353_DEFAULT_DIVIDER, + .p_default_contrast = SSD1353_DEFAULT_CONTRAST_CONTROL, + .p_multiplex_ratio = 0x83, + .p_init = ssdfb_init_ssd1353, + .p_sync = ssdfb_sync_ssd1353 } }; @@ -872,18 +913,148 @@ ssdfb_init_ssd1322(struct ssdfb_softc *s } static int +ssdfb_init_ssd1353(struct ssdfb_softc *sc) +{ + int error; + uint8_t cmd[3]; + bool usepoll = true; + uint8_t remap; + + /* + * Enter sleep. + */ + SSDFB_CMD2(SSD1353_CMD_SET_COMMAND_LOCK, SSD1353_COMMAND_UNLOCK_MAGIC); + if (error) + return error; + SSDFB_CMD1(SSD1353_CMD_RESET); + if (error) + return error; + SSDFB_CMD1(SSD1353_CMD_DEACTIVATE_SCROLL); + if (error) + return error; + SSDFB_CMD1(SSD1353_CMD_SET_DISPLAY_OFF); + if (error) + return error; + + /* + * Start charge pumps. + */ + SSDFB_CMD2(SSD1353_CMD_SET_VCOMH, sc->sc_p->p_vcomh_deselect_level); + if (error) + return error; + SSDFB_CMD2(SSD1353_CMD_SET_PRE_CHARGE_VOLTAGE_LEVEL, + SSD1353_DEFAULT_PRE_CHARGE_VOLTAGE_LEVEL); + if (error) + return error; + + /* + * Configure timing characteristics. + */ + SSDFB_CMD2(SSD1353_CMD_SET_FRONT_CLOCK_DIVIDER, + __SHIFTIN(sc->sc_p->p_fosc, SSD1322_FREQUENCY_MASK) | + __SHIFTIN(sc->sc_p->p_fosc_div, SSD1322_DIVIDER_MASK)); + if (error) + return error; + SSDFB_CMD2(SSD1353_CMD_SET_PHASE_LENGTH, + __SHIFTIN(SSD1353_DEFAULT_PHASE_2, + SSD1322_PHASE_LENGTH_PHASE_2_MASK) | + __SHIFTIN(SSD1353_DEFAULT_PHASE_1, + SSD1322_PHASE_LENGTH_PHASE_1_MASK)); + if (error) + return error; + SSDFB_CMD2(SSD1353_CMD_SET_SECOND_PRECHARGE_PERIOD, + SSD1353_DEFAULT_SECOND_PRECHARGE_PERIOD); + if (error) + return error; + SSDFB_CMD2(SSD1353_CMD_SET_SECOND_PRECHARGE_SPEED, + SSD1353_DEFAULT_SECOND_PRECHARGE_SPEED); + if (error) + return error; + + /* + * Configure physical display panel layout. + */ + SSDFB_CMD2(SSD1353_CMD_SET_MULTIPLEX_RATIO, sc->sc_p->p_multiplex_ratio); + if (error) + return error; + remap = sc->sc_p->p_compin_cfg; + if (sc->sc_upsidedown) + remap ^= SSD1353_REMAP_COM_DIRECTION; + else + remap ^= SSD1353_REMAP_SEG_DIRECTION; + SSDFB_CMD2(SSD1353_CMD_REMAP_COLOR_DEPTH, remap); + if (error) + return error; + + /* + * Contrast settings. + */ + SSDFB_CMD1(SSD1353_CMD_SET_DEFAULT_GRAY_SCALE_TABLE); + if (error) + return error; + SSDFB_CMD2(SSD1353_CMD_SET_CONTRAST_CONTROL_A, sc->sc_contrast); + if (error) + return error; + SSDFB_CMD2(SSD1353_CMD_SET_CONTRAST_CONTROL_B, sc->sc_contrast); + if (error) + return error; + SSDFB_CMD2(SSD1353_CMD_SET_CONTRAST_CONTROL_C, sc->sc_contrast); + if (error) + return error; + SSDFB_CMD2(SSD1353_CMD_MASTER_CURRENT_CONTROL, + SSD1353_DEFAULT_MASTER_CURRENT_ATTENUATION); + if (error) + return error; + + /* + * Reset display engine state. + */ + SSDFB_CMD2(SSD1353_CMD_SET_DISPLAY_OFFSET, 0x00); + if (error) + return error; + SSDFB_CMD2(SSD1353_CMD_SET_DISPLAY_START_LINE, 0x00); + if (error) + return error; + SSDFB_CMD1(sc->sc_inverse + ? SSD1353_CMD_INVERSE_DISPLAY + : SSD1353_CMD_NORMAL_DISPLAY); + if (error) + return error; + + ssdfb_clear_screen(sc); + error = ssdfb_sync(sc, usepoll); + if (error) + return error; + + error = ssdfb_set_display_on(sc, true, usepoll); + + return error; +} + +static int ssdfb_set_contrast(struct ssdfb_softc *sc, uint8_t value, bool usepoll) { uint8_t cmd[2]; + int error; + cmd[1] = sc->sc_contrast = value; switch (sc->sc_p->p_controller_id) { case SSDFB_CONTROLLER_SSD1322: cmd[0] = SSD1322_CMD_SET_CONTRAST_CURRENT; break; + case SSDFB_CONTROLLER_SSD1353: + cmd[0] = SSD1353_CMD_SET_CONTRAST_CONTROL_A; + error = sc->sc_cmd(sc->sc_cookie, cmd, sizeof(cmd), usepoll); + if (error) + return error; + cmd[0] = SSD1353_CMD_SET_CONTRAST_CONTROL_B; + error = sc->sc_cmd(sc->sc_cookie, cmd, sizeof(cmd), usepoll); + if (error) + return error; + cmd[0] = SSD1353_CMD_SET_CONTRAST_CONTROL_C; default: cmd[0] = SSDFB_CMD_SET_CONTRAST_CONTROL; } - cmd[1] = sc->sc_contrast = value; return sc->sc_cmd(sc->sc_cookie, cmd, sizeof(cmd), usepoll); } @@ -1200,6 +1371,57 @@ ssdfb_sync_ssd1322(struct ssdfb_softc *s return 0; } +static int +ssdfb_sync_ssd1353(struct ssdfb_softc *sc, bool usepoll) +{ + int width = sc->sc_p->p_width; + int height = sc->sc_p->p_height; + struct rasops_info *ri = &sc->sc_ri; + int x, y; + uint32_t *src, *blockp; + int x1, x2, y1, y2; + + /* + * Transfer rasops bitmap into gddram shadow buffer while keeping track + * of the bounding box of the dirty region we scribbled over. + */ + x1 = width; + x2 = -1; + y1 = height; + y2 = -1; + blockp = (uint32_t*)sc->sc_gddram; + for (y = 0; y < height; y++) { + src = (uint32_t*)&ri->ri_bits[y * ri->ri_stride]; + for (x = 0; x < width; x++) { + if (*blockp != *src) { + *blockp = *src; + if (x1 > x) + x1 = x; + if (x2 < x) + x2 = x; + if (y1 > y) + y1 = y; + if (y2 < y) + y2 = y; + } + blockp++; + src++; + } + } + + blockp = (uint32_t*)sc->sc_gddram; + if (x2 != -1) + return sc->sc_transfer_rect(sc->sc_cookie, + x1 + sc->sc_p->p_panel_shift, + x2 + sc->sc_p->p_panel_shift, + y1, + y2, + (uint8_t*)&blockp[y1 * width + x1], + width * sc->sc_p->p_bits_per_pixel / 8, + usepoll); + return 0; +} + static uint64_t ssdfb_transpose_block(uint8_t *src, size_t src_stride) { Index: src/sys/dev/ic/ssdfbvar.h diff -u src/sys/dev/ic/ssdfbvar.h:1.8 src/sys/dev/ic/ssdfbvar.h:1.9 --- src/sys/dev/ic/ssdfbvar.h:1.8 Thu Aug 5 00:16:36 2021 +++ src/sys/dev/ic/ssdfbvar.h Thu Aug 5 19:07:09 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: ssdfbvar.h,v 1.8 2021/08/05 00:16:36 tnn Exp $ */ +/* $NetBSD: ssdfbvar.h,v 1.9 2021/08/05 19:07:09 tnn Exp $ */ /* * Copyright (c) 2019 The NetBSD Foundation, Inc. @@ -282,6 +282,7 @@ typedef enum { SSDFB_CONTROLLER_SSD1306=1, SSDFB_CONTROLLER_SH1106=2, SSDFB_CONTROLLER_SSD1322=3, + SSDFB_CONTROLLER_SSD1353=4, } ssdfb_controller_id_t; typedef enum { @@ -291,6 +292,8 @@ typedef enum { SSDFB_PRODUCT_ADAFRUIT_931=3, SSDFB_PRODUCT_ADAFRUIT_938=4, SSDFB_PRODUCT_SSD1322_GENERIC=5, + SSDFB_PRODUCT_SSD1353_GENERIC=6, + SSDFB_PRODUCT_DEP_160128A_RGB=7, } ssdfb_product_id_t; #define SSDFB_I2C_DEFAULT_ADDR 0x3c