summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2018-08-17 14:20:16 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2018-08-17 14:20:16 +0000
commit12bbcee934da25f0d927ea655360bd8f77003222 (patch)
tree707138a38c4c912dd56e713e02e5fa4e7c263ca5
parenta165dc03b502bec3347c7c824c3a6ade57474cf5 (diff)
Support reading and using serveral device tree attributes for ssdfb(4),
since some OLED display controller settings can change depending on the actual hardware integration.
-rw-r--r--sys/dev/fdt/ssdfb.c82
1 files changed, 54 insertions, 28 deletions
diff --git a/sys/dev/fdt/ssdfb.c b/sys/dev/fdt/ssdfb.c
index 9c1c1e9faa1..992081a28e6 100644
--- a/sys/dev/fdt/ssdfb.c
+++ b/sys/dev/fdt/ssdfb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssdfb.c,v 1.5 2018/08/09 14:43:17 patrick Exp $ */
+/* $OpenBSD: ssdfb.c,v 1.6 2018/08/17 14:20:15 patrick Exp $ */
/*
* Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
*
@@ -40,9 +40,11 @@
#define SSDFB_SET_PAGE_RANGE 0x22
#define SSDFB_SET_START_LINE 0x40
#define SSDFB_SET_CONTRAST_CONTROL 0x81
+#define SSDFB_SET_COLUMN_DIRECTION_NORMAL 0xa0
#define SSDFB_SET_COLUMN_DIRECTION_REVERSE 0xa1
#define SSDFB_SET_MULTIPLEX_RATIO 0xa8
-#define SSDFB_SET_COM_OUTPUT_DIRECTION 0xc0
+#define SSDFB_SET_COM_OUTPUT_DIRECTION_NORMAL 0xc0
+#define SSDFB_SET_COM_OUTPUT_DIRECTION_REMAP 0xc8
#define SSDFB_ENTIRE_DISPLAY_ON 0xa4
#define SSDFB_SET_DISPLAY_MODE_NORMAL 0xa6
#define SSDFB_SET_DISPLAY_MODE_INVERS 0xa7
@@ -58,12 +60,12 @@
#define SSDFB_I2C_COMMAND 0x00
#define SSDFB_I2C_DATA 0x40
-#define SSDFB_WIDTH 128
-#define SSDFB_HEIGHT 64
-
struct ssdfb_softc {
struct device sc_dev;
int sc_node;
+ int sc_width;
+ int sc_height;
+ int sc_pgoff;
uint8_t *sc_fb;
size_t sc_fbsize;
@@ -153,7 +155,6 @@ struct cfdriver ssdfb_cd = {
};
struct wsscreen_descr ssdfb_std_descr = { "std" };
-struct wsdisplay_charcell ssdfb_bs[SSDFB_WIDTH * SSDFB_HEIGHT];
const struct wsscreen_descr *ssdfb_descrs[] = {
&ssdfb_std_descr
@@ -288,20 +289,25 @@ ssdfb_attach(struct ssdfb_softc *sc)
free(gpio, M_DEVBUF, len);
}
- sc->sc_fbsize = (SSDFB_WIDTH * SSDFB_HEIGHT) / 8;
+ sc->sc_width = OF_getpropint(sc->sc_node, "solomon,width", 96);
+ sc->sc_height = OF_getpropint(sc->sc_node, "solomon,height", 16);
+ sc->sc_pgoff = OF_getpropint(sc->sc_node, "solomon,page-offset", 1);
+
+ sc->sc_fbsize = (sc->sc_width * sc->sc_height) / 8;
sc->sc_fb = malloc(sc->sc_fbsize, M_DEVBUF, M_WAITOK | M_ZERO);
ri = &sc->sc_rinfo;
ri->ri_bits = malloc(sc->sc_fbsize, M_DEVBUF, M_WAITOK | M_ZERO);
- ri->ri_bs = ssdfb_bs;
+ ri->ri_bs = mallocarray(sc->sc_width * sc->sc_height,
+ sizeof(struct wsdisplay_charcell), M_DEVBUF, M_WAITOK | M_ZERO);
ri->ri_flg = RI_CLEAR | RI_VCONS;
ri->ri_depth = 1;
- ri->ri_width = SSDFB_WIDTH;
- ri->ri_height = SSDFB_HEIGHT;
+ ri->ri_width = sc->sc_width;
+ ri->ri_height = sc->sc_height;
ri->ri_stride = ri->ri_width * ri->ri_depth / 8;
ri->ri_hw = sc;
- rasops_init(ri, SSDFB_HEIGHT, SSDFB_WIDTH);
+ rasops_init(ri, sc->sc_height, sc->sc_width);
ssdfb_std_descr.ncols = ri->ri_cols;
ssdfb_std_descr.nrows = ri->ri_rows;
ssdfb_std_descr.textops = &ri->ri_ops;
@@ -341,6 +347,8 @@ int
ssdfb_detach(struct ssdfb_softc *sc, int flags)
{
struct rasops_info *ri = &sc->sc_rinfo;
+ free(ri->ri_bs, M_DEVBUF, sc->sc_width * sc->sc_height *
+ sizeof(struct wsdisplay_charcell));
free(ri->ri_bits, M_DEVBUF, sc->sc_fbsize);
free(sc->sc_fb, M_DEVBUF, sc->sc_fbsize);
return 0;
@@ -359,41 +367,56 @@ ssdfb_init(struct ssdfb_softc *sc)
ssdfb_write_command(sc, reg, 2);
reg[0] = SSDFB_SET_PAGE_START_ADDRESS;
ssdfb_write_command(sc, reg, 1);
- ssdfb_set_range(sc, 0, SSDFB_WIDTH - 1,
- 0, (SSDFB_HEIGHT / 8) - 1);
- reg[0] = SSDFB_SET_DISPLAY_CLOCK_DIVIDE_RATIO;
- reg[1] = 0xa0;
- ssdfb_write_command(sc, reg, 2);
+ ssdfb_set_range(sc, 0, sc->sc_width - 1,
+ 0, (sc->sc_height / 8) - 1);
+ if (OF_is_compatible(sc->sc_node, "solomon,ssd1309fb-i2c") ||
+ OF_is_compatible(sc->sc_node, "solomon,ssd1309fb-spi")) {
+ reg[0] = SSDFB_SET_DISPLAY_CLOCK_DIVIDE_RATIO;
+ reg[1] = 0xa0;
+ ssdfb_write_command(sc, reg, 2);
+ }
reg[0] = SSDFB_SET_MULTIPLEX_RATIO;
reg[1] = 0x3f;
ssdfb_write_command(sc, reg, 2);
reg[0] = SSDFB_SET_DISPLAY_OFFSET;
- reg[1] = 0x00;
+ reg[1] = OF_getpropint(sc->sc_node, "solomon,com-offset", 0);
ssdfb_write_command(sc, reg, 2);
reg[0] = SSDFB_SET_START_LINE | 0x00;
ssdfb_write_command(sc, reg, 1);
- reg[0] = SSDFB_SET_COLUMN_DIRECTION_REVERSE;
+ reg[0] = SSDFB_SET_COLUMN_DIRECTION_NORMAL;
+ if (OF_getproplen(sc->sc_node, "solomon,com-invdir") == 0)
+ reg[0] = SSDFB_SET_COLUMN_DIRECTION_REVERSE;
ssdfb_write_command(sc, reg, 1);
- reg[0] = SSDFB_SET_COM_OUTPUT_DIRECTION | 0x08;
+ reg[0] = SSDFB_SET_COM_OUTPUT_DIRECTION_REMAP;
+ if (OF_getproplen(sc->sc_node, "solomon,segment-no-remap") == 0)
+ reg[0] = SSDFB_SET_COM_OUTPUT_DIRECTION_NORMAL;
ssdfb_write_command(sc, reg, 1);
reg[0] = SSDFB_SET_COM_PINS_HARD_CONF;
reg[1] = 0x12;
+ if (OF_getproplen(sc->sc_node, "solomon,com-seq") == 0)
+ reg[1] &= ~(1 << 4);
+ if (OF_getproplen(sc->sc_node, "solomon,com-lrremap") == 0)
+ reg[1] |= 1 << 5;
ssdfb_write_command(sc, reg, 2);
reg[0] = SSDFB_SET_CONTRAST_CONTROL;
reg[1] = 223;
ssdfb_write_command(sc, reg, 2);
reg[0] = SSDFB_SET_PRE_CHARGE_PERIOD;
- reg[1] = 0x82;
- ssdfb_write_command(sc, reg, 2);
- reg[0] = SSDFB_SET_VCOM_DESELECT_LEVEL;
- reg[1] = 0x34;
+ reg[1] = (OF_getpropint(sc->sc_node, "solomon,prechargep1", 2) & 0xf) << 0;
+ reg[1] |= (OF_getpropint(sc->sc_node, "solomon,prechargep2", 2) & 0xf) << 4;
ssdfb_write_command(sc, reg, 2);
+ if (OF_is_compatible(sc->sc_node, "solomon,ssd1309fb-i2c") ||
+ OF_is_compatible(sc->sc_node, "solomon,ssd1309fb-spi")) {
+ reg[0] = SSDFB_SET_VCOM_DESELECT_LEVEL;
+ reg[1] = 0x34;
+ ssdfb_write_command(sc, reg, 2);
+ }
reg[0] = SSDFB_ENTIRE_DISPLAY_ON;
ssdfb_write_command(sc, reg, 1);
reg[0] = SSDFB_SET_DISPLAY_MODE_NORMAL;
ssdfb_write_command(sc, reg, 1);
- ssdfb_partial(sc, 0, SSDFB_WIDTH, 0, SSDFB_HEIGHT);
+ ssdfb_partial(sc, 0, sc->sc_width, 0, sc->sc_height);
reg[0] = SSDFB_SET_DISPLAY_ON;
ssdfb_write_command(sc, reg, 1);
@@ -405,6 +428,9 @@ ssdfb_set_range(struct ssdfb_softc *sc, uint8_t x1, uint8_t x2,
{
uint8_t reg[3];
+ y1 += sc->sc_pgoff;
+ y2 += sc->sc_pgoff;
+
if (sc->sc_column_range[0] != x1 || sc->sc_column_range[1] != x2) {
sc->sc_column_range[0] = x1;
sc->sc_column_range[1] = x2;
@@ -435,7 +461,7 @@ ssdfb_partial(struct ssdfb_softc *sc, uint32_t x1, uint32_t x2,
if (x2 < x1 || y2 < y1)
return;
- if (x2 > SSDFB_WIDTH || y2 > SSDFB_HEIGHT)
+ if (x2 > sc->sc_width || y2 > sc->sc_height)
return;
y1 = y1 & ~0x7;
@@ -676,7 +702,7 @@ ssdfb_copyrows(void *cookie, int src, int dst, int num)
struct ssdfb_softc *sc = ri->ri_hw;
sc->sc_riops.copyrows(cookie, src, dst, num);
- ssdfb_partial(sc, 0, SSDFB_WIDTH,
+ ssdfb_partial(sc, 0, sc->sc_width,
dst * ri->ri_font->fontheight,
(dst + num) * ri->ri_font->fontheight);
return 0;
@@ -690,9 +716,9 @@ ssdfb_eraserows(void *cookie, int row, int num, long attr)
sc->sc_riops.eraserows(cookie, row, num, attr);
if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0)
- ssdfb_partial(sc, 0, SSDFB_WIDTH, 0, SSDFB_HEIGHT);
+ ssdfb_partial(sc, 0, sc->sc_width, 0, sc->sc_height);
else
- ssdfb_partial(sc, 0, SSDFB_WIDTH,
+ ssdfb_partial(sc, 0, sc->sc_width,
row * ri->ri_font->fontheight,
(row + num) * ri->ri_font->fontheight);
return 0;