Module Name: src Committed By: tnn Date: Thu Aug 19 17:50:18 UTC 2021
Modified Files: src/sys/dev/spi: ssdfb_spi.c Log Message: ssdfb: add support for SSD1306 and SH1106 at spi attachment Only support the 4-wire mode for now. Support for 3-wire mode is theoretically possible but most (all?) modules in circulation have the BS0 / IM0 3-wire config pin internally grounded within the flat-flex assembly so it is not easy to enable & test. To generate a diff of this commit: cvs rdiff -u -r1.10 -r1.11 src/sys/dev/spi/ssdfb_spi.c 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/spi/ssdfb_spi.c diff -u src/sys/dev/spi/ssdfb_spi.c:1.10 src/sys/dev/spi/ssdfb_spi.c:1.11 --- src/sys/dev/spi/ssdfb_spi.c:1.10 Thu Aug 19 11:04:21 2021 +++ src/sys/dev/spi/ssdfb_spi.c Thu Aug 19 17:50:18 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: ssdfb_spi.c,v 1.10 2021/08/19 11:04:21 tnn Exp $ */ +/* $NetBSD: ssdfb_spi.c,v 1.11 2021/08/19 17:50:18 tnn Exp $ */ /* * Copyright (c) 2019 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ssdfb_spi.c,v 1.10 2021/08/19 11:04:21 tnn Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ssdfb_spi.c,v 1.11 2021/08/19 17:50:18 tnn Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -70,6 +70,10 @@ static int ssdfb_spi_xfer_rect_3wire_ssd uint8_t, uint8_t, uint8_t *, size_t, bool); static int ssdfb_spi_cmd_4wire(void *, uint8_t *, size_t, bool); +static int ssdfb_spi_xfer_rect_4wire_sh1106(void *, uint8_t, uint8_t, + uint8_t, uint8_t, uint8_t *, size_t, bool); +static int ssdfb_spi_xfer_rect_4wire_ssd1306(void *, uint8_t, uint8_t, + uint8_t, uint8_t, uint8_t *, size_t, bool); static int ssdfb_spi_xfer_rect_4wire_ssd1322(void *, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t *, size_t, bool); static int ssdfb_spi_xfer_rect_4wire_ssd1353(void *, uint8_t, uint8_t, @@ -87,6 +91,7 @@ CFATTACH_DECL_NEW(ssdfb_spi, sizeof(stru static const struct device_compatible_entry compat_data[] = { { .compat = "solomon,ssd1306", .value = SSDFB_PRODUCT_SSD1306_GENERIC }, + { .compat = "sino,sh1106", .value = SSDFB_PRODUCT_SH1106_GENERIC }, { .compat = "solomon,ssd1322", .value = SSDFB_PRODUCT_SSD1322_GENERIC }, { .compat = "solomon,ssd1353", .value = SSDFB_PRODUCT_SSD1353_GENERIC }, { .compat = "dep160128a", .value = SSDFB_PRODUCT_DEP_160128A_RGB }, @@ -165,6 +170,20 @@ ssdfb_spi_attach(device_t parent, device : ssdfb_spi_cmd_4wire; switch (flags & SSDFB_ATTACH_FLAG_PRODUCT_MASK) { + case SSDFB_PRODUCT_SH1106_GENERIC: + sc->sc.sc_transfer_rect = sc->sc_3wiremode + ? NULL + : ssdfb_spi_xfer_rect_4wire_sh1106; + sc->sc_padding_cmd = SSDFB_CMD_NOP; + sc->sc_late_dc_deassert = true; + break; + case SSDFB_PRODUCT_SSD1306_GENERIC: + sc->sc.sc_transfer_rect = sc->sc_3wiremode + ? NULL + : ssdfb_spi_xfer_rect_4wire_ssd1306; + sc->sc_padding_cmd = SSDFB_CMD_NOP; + sc->sc_late_dc_deassert = true; + break; case SSDFB_PRODUCT_SSD1322_GENERIC: sc->sc.sc_transfer_rect = sc->sc_3wiremode ? ssdfb_spi_xfer_rect_3wire_ssd1322 @@ -215,7 +234,6 @@ ssdfb_spi_xfer_rect_3wire_ssd1322(void * struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie; uint8_t bitstream[128 * 9 / 8]; struct bs_state s; - uint8_t row; size_t rlen = (tocol + 1 - fromcol) * 2; int error; @@ -239,13 +257,14 @@ ssdfb_spi_xfer_rect_3wire_ssd1322(void * return error; KASSERT(rlen <= 128); - for (row = fromrow; row <= torow; row++) { + while (fromrow <= torow) { ssdfb_bitstream_init(&s, bitstream); ssdfb_bitstream_append_data(&s, p, rlen); ssdfb_bitstream_final(&s, sc->sc_padding_cmd); error = spi_send(sc->sc_sh, s.cur - s.base, bitstream); if (error) return error; + fromrow++; p += stride; } @@ -334,19 +353,86 @@ ssdfb_spi_cmd_4wire(void *cookie, uint8_ } static int +ssdfb_spi_xfer_rect_4wire_sh1106(void *cookie, uint8_t fromcol, uint8_t tocol, + uint8_t frompage, uint8_t topage, uint8_t *p, size_t stride, bool usepoll) +{ + struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie; + size_t rlen = tocol + 1 - fromcol; + int error; + uint8_t cmd[] = { + SSDFB_CMD_SET_PAGE_START_ADDRESS_BASE + frompage, + SSDFB_CMD_SET_HIGHER_COLUMN_START_ADDRESS_BASE + (fromcol >> 4), + SSDFB_CMD_SET_LOWER_COLUMN_START_ADDRESS_BASE + (fromcol & 0xf) + }; + + if (usepoll && !cold) + return 0; + + while (frompage <= topage) { + cmd[0] = SSDFB_CMD_SET_PAGE_START_ADDRESS_BASE + frompage; + ssdfb_spi_4wire_set_dc(sc, 0); + error = spi_send(sc->sc_sh, sizeof(cmd), cmd); + if (error) + return error; + ssdfb_spi_4wire_set_dc(sc, 1); + error = spi_send(sc->sc_sh, rlen, p); + if (error) + return error; + frompage++; + p += stride; + } + + return 0; +} + +static int +ssdfb_spi_xfer_rect_4wire_ssd1306(void *cookie, uint8_t fromcol, uint8_t tocol, + uint8_t frompage, uint8_t topage, uint8_t *p, size_t stride, bool usepoll) +{ + struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie; + size_t rlen = tocol + 1 - fromcol; + int error; + uint8_t cmd[] = { + SSD1306_CMD_SET_MEMORY_ADDRESSING_MODE, + SSD1306_MEMORY_ADDRESSING_MODE_HORIZONTAL, + SSD1306_CMD_SET_COLUMN_ADDRESS, + fromcol, + tocol, + SSD1306_CMD_SET_PAGE_ADDRESS, + frompage, + topage + }; + + if (usepoll && !cold) + return 0; + + ssdfb_spi_4wire_set_dc(sc, 0); + error = spi_send(sc->sc_sh, sizeof(cmd), cmd); + if (error) + return error; + ssdfb_spi_4wire_set_dc(sc, 1); + + while (frompage <= topage) { + error = spi_send(sc->sc_sh, rlen, p); + if (error) + return error; + frompage++; + p += stride; + } + + return 0; +} + +static int ssdfb_spi_xfer_rect_4wire_ssd1322(void *cookie, uint8_t fromcol, uint8_t tocol, uint8_t fromrow, uint8_t torow, uint8_t *p, size_t stride, bool usepoll) { struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie; - uint8_t row; size_t rlen = (tocol + 1 - fromcol) * 2; int error; uint8_t cmd; uint8_t data[2]; - /* - * Unlike iic(4), there is no way to force spi(4) to use polling. - */ if (usepoll && !cold) return 0; @@ -381,10 +467,11 @@ ssdfb_spi_xfer_rect_4wire_ssd1322(void * return error; ssdfb_spi_4wire_set_dc(sc, 1); - for (row = fromrow; row <= torow; row++) { + while (fromrow <= torow) { error = spi_send(sc->sc_sh, rlen, p); if (error) return error; + fromrow++; p += stride; } @@ -396,7 +483,6 @@ ssdfb_spi_xfer_rect_4wire_ssd1353(void * uint8_t fromrow, uint8_t torow, uint8_t *p, size_t stride, bool usepoll) { struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie; - uint8_t row; size_t rlen = (tocol + 1 - fromcol) * 3; uint8_t bitstream[160 * 3]; uint8_t *dstp, *srcp, *endp; @@ -404,9 +490,6 @@ ssdfb_spi_xfer_rect_4wire_ssd1353(void * uint8_t cmd; uint8_t data[2]; - /* - * Unlike iic(4), there is no way to force spi(4) to use polling. - */ if (usepoll && !cold) return 0; @@ -447,7 +530,7 @@ ssdfb_spi_xfer_rect_4wire_ssd1353(void * ssdfb_spi_4wire_set_dc(sc, 1); KASSERT(rlen <= sizeof(bitstream)); - for (row = fromrow; row <= torow; row++) { + while (fromrow <= torow) { /* downconvert each row from 32bpp rgba to 18bpp panel format */ dstp = bitstream; endp = dstp + rlen; @@ -461,6 +544,7 @@ ssdfb_spi_xfer_rect_4wire_ssd1353(void * error = spi_send(sc->sc_sh, rlen, bitstream); if (error) return error; + fromrow++; p += stride; }