Module Name:    src
Committed By:   tnn
Date:           Sat Nov  2 14:18:36 UTC 2019

Modified Files:
        src/sys/dev/ic: ssdfb.c ssdfbvar.h

Log Message:
ssdfb: add support for SSD1322


To generate a diff of this commit:
cvs rdiff -u -r1.8 -r1.9 src/sys/dev/ic/ssdfb.c
cvs rdiff -u -r1.4 -r1.5 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.8 src/sys/dev/ic/ssdfb.c:1.9
--- src/sys/dev/ic/ssdfb.c:1.8	Tue Oct 22 22:03:27 2019
+++ src/sys/dev/ic/ssdfb.c	Sat Nov  2 14:18:36 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: ssdfb.c,v 1.8 2019/10/22 22:03:27 tnn Exp $ */
+/* $NetBSD: ssdfb.c,v 1.9 2019/11/02 14:18:36 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.8 2019/10/22 22:03:27 tnn Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ssdfb.c,v 1.9 2019/11/02 14:18:36 tnn Exp $");
 
 #include "opt_ddb.h"
 
@@ -73,6 +73,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_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);
@@ -85,8 +86,9 @@ static void	ssdfb_damage(struct ssdfb_so
 static void	ssdfb_thread(void *);
 static void	ssdfb_set_usepoll(struct ssdfb_softc *, bool);
 static int	ssdfb_sync(struct ssdfb_softc *, bool);
-static uint64_t	ssdfb_transpose_block_1bpp(uint8_t *, size_t);
-static uint64_t	ssdfb_transpose_block_8bpp(uint8_t *, size_t);
+static int	ssdfb_sync_ssd1306(struct ssdfb_softc *, bool);
+static int	ssdfb_sync_ssd1322(struct ssdfb_softc *, bool);
+static uint64_t	ssdfb_transpose_block(uint8_t *, size_t);
 
 /* misc helpers */
 static const struct ssdfb_product *
@@ -114,6 +116,7 @@ static const struct ssdfb_product ssdfb_
 		.p_name =		"generic",
 		.p_width =		128,
 		.p_height =		64,
+		.p_bits_per_pixel =	1,
 		.p_panel_shift =	0,
 		.p_fosc =		0x8,
 		.p_fosc_div =		0,
@@ -124,9 +127,8 @@ static const struct ssdfb_product ssdfb_
 		.p_vcomh_deselect_level = SSD1306_VCOMH_DESELECT_LEVEL_0_77_VCC,
 		.p_default_contrast =	0x7f,
 		.p_multiplex_ratio =	0x3f,
-		.p_chargepump_cmd =	SSD1306_CMD_SET_CHARGE_PUMP,
-		.p_chargepump_arg =	SSD1306_CHARGE_PUMP_ENABLE,
-		.p_init =		ssdfb_init_ssd1306
+		.p_init =		ssdfb_init_ssd1306,
+		.p_sync =		ssdfb_sync_ssd1306
 	},
 	{
 		.p_product_id =		SSDFB_PRODUCT_SH1106_GENERIC,
@@ -134,6 +136,7 @@ static const struct ssdfb_product ssdfb_
 		.p_name =		"generic",
 		.p_width =		128,
 		.p_height =		64,
+		.p_bits_per_pixel =	1,
 		.p_panel_shift =	2,
 		.p_fosc =		0x5,
 		.p_fosc_div =		0,
@@ -144,9 +147,8 @@ static const struct ssdfb_product ssdfb_
 		.p_vcomh_deselect_level = SH1106_VCOMH_DESELECT_LEVEL_DEFAULT,
 		.p_default_contrast =	0x80,
 		.p_multiplex_ratio =	0x3f,
-		.p_chargepump_cmd =	SH1106_CMD_SET_CHARGE_PUMP_7V4,
-		.p_chargepump_arg =	SSDFB_CMD_NOP,
-		.p_init =		ssdfb_init_ssd1306
+		.p_init =		ssdfb_init_ssd1306,
+		.p_sync =		ssdfb_sync_ssd1306
 	},
 	{
 		.p_product_id =		SSDFB_PRODUCT_ADAFRUIT_938,
@@ -154,6 +156,7 @@ static const struct ssdfb_product ssdfb_
 		.p_name =		"Adafruit Industries, LLC product 938",
 		.p_width =		128,
 		.p_height =		64,
+		.p_bits_per_pixel =	1,
 		.p_panel_shift =	0,
 		.p_fosc =		0x8,
 		.p_fosc_div =		0,
@@ -163,9 +166,8 @@ static const struct ssdfb_product ssdfb_
 		.p_vcomh_deselect_level = 0x40,
 		.p_default_contrast =	0x8f,
 		.p_multiplex_ratio =	0x3f,
-		.p_chargepump_cmd =	SSD1306_CMD_SET_CHARGE_PUMP,
-		.p_chargepump_arg =	SSD1306_CHARGE_PUMP_ENABLE,
-		.p_init =		ssdfb_init_ssd1306
+		.p_init =		ssdfb_init_ssd1306,
+		.p_sync =		ssdfb_sync_ssd1306
 	},
 	{
 		.p_product_id =		SSDFB_PRODUCT_ADAFRUIT_931,
@@ -173,6 +175,7 @@ static const struct ssdfb_product ssdfb_
 		.p_name =		"Adafruit Industries, LLC product 931",
 		.p_width =		128,
 		.p_height =		32,
+		.p_bits_per_pixel =	1,
 		.p_panel_shift =	0,
 		.p_fosc =		0x8,
 		.p_fosc_div =		0,
@@ -182,9 +185,24 @@ static const struct ssdfb_product ssdfb_
 		.p_vcomh_deselect_level = 0x40,
 		.p_default_contrast =	0x8f,
 		.p_multiplex_ratio =	0x1f,
-		.p_chargepump_cmd =	SSD1306_CMD_SET_CHARGE_PUMP,
-		.p_chargepump_arg =	SSD1306_CHARGE_PUMP_ENABLE,
-		.p_init =		ssdfb_init_ssd1306
+		.p_init =		ssdfb_init_ssd1306,
+		.p_sync =		ssdfb_sync_ssd1306
+	},
+	{
+		.p_product_id =		SSDFB_PRODUCT_SSD1322_GENERIC,
+		.p_controller_id =	SSDFB_CONTROLLER_SSD1322,
+		.p_name =		"generic",
+		.p_width =		256,
+		.p_height =		64,
+		.p_bits_per_pixel =	4,
+		.p_panel_shift =	28,
+		.p_vcomh_deselect_level = SSD1322_DEFAULT_VCOMH,
+		.p_fosc =		SSD1322_DEFAULT_FREQUENCY,
+		.p_fosc_div =		SSD1322_DEFAULT_DIVIDER,
+		.p_default_contrast =	SSD1322_DEFAULT_CONTRAST_CURRENT,
+		.p_multiplex_ratio =	0x3f,
+		.p_init =		ssdfb_init_ssd1322,
+		.p_sync =		ssdfb_sync_ssd1322
 	}
 };
 
@@ -198,6 +216,7 @@ static const struct wsdisplay_accessops 
 
 #define SSDFB_CMD1(c) do { cmd[0] = (c); error = sc->sc_cmd(sc->sc_cookie, cmd, 1, usepoll); } while(0)
 #define SSDFB_CMD2(c, a) do { cmd[0] = (c); cmd[1] = (a); error = sc->sc_cmd(sc->sc_cookie, cmd, 2, usepoll); } while(0)
+#define SSDFB_CMD3(c, a, b) do { cmd[0] = (c); cmd[1] = (a); cmd[2] = (b); error = sc->sc_cmd(sc->sc_cookie, cmd, 3, usepoll); } while(0)
 
 void
 ssdfb_attach(struct ssdfb_softc *sc, int flags)
@@ -207,6 +226,7 @@ ssdfb_attach(struct ssdfb_softc *sc, int
 	int error = 0;
 	long defattr;
 	const struct ssdfb_product *p;
+	int kt_flags;
 
 	p = ssdfb_lookup_product(flags & SSDFB_ATTACH_FLAG_PRODUCT_MASK);
 	if (p == NULL) {
@@ -226,7 +246,8 @@ ssdfb_attach(struct ssdfb_softc *sc, int
 	sc->sc_upsidedown = flags & SSDFB_ATTACH_FLAG_UPSIDEDOWN ? true : false;
 	sc->sc_backoff = 1;
 	sc->sc_contrast = sc->sc_p->p_default_contrast;
-	sc->sc_gddram_len = sc->sc_p->p_width * sc->sc_p->p_height / 8;
+	sc->sc_gddram_len = sc->sc_p->p_width * sc->sc_p->p_height
+	    * sc->sc_p->p_bits_per_pixel / 8;
 	sc->sc_gddram = kmem_alloc(sc->sc_gddram_len, KM_SLEEP);
 	if (sc->sc_gddram == NULL)
 		goto out;
@@ -246,13 +267,17 @@ ssdfb_attach(struct ssdfb_softc *sc, int
 		aprint_error_dev(sc->sc_dev, "no font\n");
 		goto out;
 	}
+#ifdef SSDFB_USE_NATIVE_DEPTH
+	ri->ri_depth =	sc->sc_p->p_bits_per_pixel;
+#else
 	ri->ri_depth =	8;
+#endif	
 	ri->ri_font =	sc->sc_font;
 	ri->ri_width =	sc->sc_p->p_width;
 	ri->ri_height =	sc->sc_p->p_height;
 	ri->ri_stride =	ri->ri_width * ri->ri_depth / 8;
 	ri->ri_hw =	sc;
-	ri->ri_flg =	RI_FULLCLEAR;
+	ri->ri_flg =	RI_FULLCLEAR | RI_FORCEMONO;
 	sc->sc_ri_bits_len = round_page(ri->ri_stride * ri->ri_height);
 	ri->ri_bits	= (u_char *)uvm_km_alloc(kernel_map, sc->sc_ri_bits_len,
 						 0, UVM_KMF_WIRED);
@@ -308,9 +333,12 @@ ssdfb_attach(struct ssdfb_softc *sc, int
 
 	mutex_init(&sc->sc_cond_mtx, MUTEX_DEFAULT, IPL_SCHED);
 	cv_init(&sc->sc_cond, "ssdfb");
-	error = kthread_create(PRI_SOFTCLOCK, KTHREAD_MPSAFE | KTHREAD_MUSTJOIN,
-	    NULL, ssdfb_thread, sc, &sc->sc_thread, "%s",
-	    device_xname(sc->sc_dev));
+	kt_flags = KTHREAD_MUSTJOIN;
+	/* XXX spi(4) is not MPSAFE yet. */
+	if (ISSET(flags, SSDFB_ATTACH_FLAG_MPSAFE))
+		kt_flags |= KTHREAD_MPSAFE;
+	error = kthread_create(PRI_SOFTCLOCK, kt_flags, NULL, ssdfb_thread, sc,
+	    &sc->sc_thread, "%s", device_xname(sc->sc_dev));
 	if (error) {
 		cv_destroy(&sc->sc_cond);
 		mutex_destroy(&sc->sc_cond_mtx);
@@ -379,7 +407,10 @@ ssdfb_ioctl(void *v, void *vs, u_long cm
 	struct ssdfb_softc *sc = v;
 	struct wsdisplay_param *wdp;
 	struct wsdisplay_cmap *wc;
-	u_char cmap[] = {0, 0xff};
+	u_char cmap[16];
+	int cmaplen = 1 << sc->sc_p->p_bits_per_pixel;
+	int i;
+	struct wsdisplayio_fbinfo *fbi;
 	int error;
 
 	switch (cmd) {
@@ -391,12 +422,15 @@ ssdfb_ioctl(void *v, void *vs, u_long cm
 			.width =	sc->sc_ri.ri_width,
 			.height =	sc->sc_ri.ri_height,
 			.depth =	sc->sc_ri.ri_depth,
-			.cmsize =	2
+			.cmsize =	cmaplen
 		};
 		return 0;
 	case WSDISPLAYIO_GET_FBINFO:
-		return wsdisplayio_get_fbinfo(&sc->sc_ri,
-			(struct wsdisplayio_fbinfo *)data);
+		fbi = (struct wsdisplayio_fbinfo *)data;
+		error = wsdisplayio_get_fbinfo(&sc->sc_ri, fbi);
+		fbi->fbi_subtype.fbi_cmapinfo.cmap_entries = cmaplen;
+		/* fbi->fbi_pixeltype = WSFB_GREYSCALE */;
+		return error;
 	case WSDISPLAYIO_LINEBYTES:
 		*(u_int *)data = sc->sc_ri.ri_stride;
 		return 0;
@@ -453,9 +487,12 @@ ssdfb_ioctl(void *v, void *vs, u_long cm
 #endif
 	case WSDISPLAYIO_GETCMAP:
 		wc = (struct wsdisplay_cmap *)data;
-		if (wc->index >= __arraycount(cmap) ||
-		    wc->count >  __arraycount(cmap) - wc->index)
+		if (wc->index >= cmaplen ||
+		    wc->count > cmaplen - wc->index)
 			return EINVAL;
+		for(i = 0; i < cmaplen; i++) {
+			cmap[i] = 255 * i / (cmaplen - 1);
+		}
 		error = copyout(&cmap[wc->index], wc->red, wc->count);
 		if (error)
 			return error;
@@ -661,22 +698,152 @@ ssdfb_init_ssd1306(struct ssdfb_softc *s
 		return error;
 
 	/*
-	 * Start charge pump.
+	 * Start charge pumps.
 	 */
-	SSDFB_CMD2(sc->sc_p->p_chargepump_cmd, sc->sc_p->p_chargepump_arg);
-	if (error)
-		return error;
-
 	if (sc->sc_p->p_controller_id == SSDFB_CONTROLLER_SH1106) {
+		SSDFB_CMD1(SH1106_CMD_SET_CHARGE_PUMP_7V4);
+		if (error)
+			return error;
 		SSDFB_CMD2(SH1106_CMD_SET_DC_DC, SH1106_DC_DC_ON);
 		if (error)
 			return error;
+	} else {
+		SSDFB_CMD2(SSD1306_CMD_SET_CHARGE_PUMP,
+		    SSD1306_CHARGE_PUMP_ENABLE);
+		if (error)
+			return error;
 	}
 
 	ssdfb_clear_screen(sc);
+	error = sc->sc_p->p_sync(sc, usepoll);
+	if (error)
+		return error;
+	error = ssdfb_set_display_on(sc, true, usepoll);
+
+	return error;
+}
+
+static int
+ssdfb_init_ssd1322(struct ssdfb_softc *sc)
+{
+	int error;
+	uint8_t cmd[3];
+	bool usepoll = true;
+	uint8_t remap;
+	uint8_t dualcom;
+
+	/*
+	 * Enter sleep.
+	 */
+	SSDFB_CMD2(SSD1322_CMD_SET_COMMAND_LOCK, SSD1322_COMMAND_UNLOCK_MAGIC);
+	if (error)
+		return error;
+	SSDFB_CMD1(SSD1322_CMD_SET_SLEEP_MODE_ON);
+	if (error)
+		return error;
+
+	/*
+	 * Start charge pumps.
+	 */
+	SSDFB_CMD2(SSD1322_CMD_FUNCTION_SELECTION,
+	    SSD1322_FUNCTION_SELECTION_INTERNAL_VDD);
+	if (error)
+		return error;
+	SSDFB_CMD2(SSD1322_CMD_SET_VCOMH, sc->sc_p->p_vcomh_deselect_level);
+	if (error)
+		return error;
+	SSDFB_CMD2(SSD1322_CMD_SET_PRE_CHARGE_VOLTAGE_LEVEL,
+	    SSD1322_DEFAULT_PRE_CHARGE_VOLTAGE_LEVEL);
+	if (error)
+		return error;
+	SSDFB_CMD2(SSD1322_CMD_SET_GPIO,
+	    SSD1322_GPIO0_DISABLED | SSD1322_GPIO1_DISABLED);
+	if (error)
+		return error;
+
+	/*
+	 * Configure timing characteristics.
+	 */
+	SSDFB_CMD2(SSD1322_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(SSD1322_CMD_SET_PHASE_LENGTH,
+	   __SHIFTIN(SSD1322_DEFAULT_PHASE_2,
+	    SSD1322_PHASE_LENGTH_PHASE_2_MASK) |
+	    __SHIFTIN(SSD1322_DEFAULT_PHASE_1,
+	    SSD1322_PHASE_LENGTH_PHASE_1_MASK));
+	if (error)
+		return error;
+	SSDFB_CMD2(SSD1322_CMD_SET_SECOND_PRECHARGE_PERIOD,
+	    SSD1322_DEFAULT_SECOND_PRECHARGE);
+	if (error)
+		return error;
+
+	/*
+	 * Configure physical display panel layout.
+	 */
+	SSDFB_CMD2(SSD1322_CMD_SET_MUX_RATIO, sc->sc_p->p_multiplex_ratio);
+	if (error)
+		return error;
+	if (sc->sc_upsidedown)
+		remap = 0x10;
+	else
+		remap = 0x2;
+	dualcom = 0x1;
+	if (sc->sc_p->p_multiplex_ratio <= 63)
+		dualcom |= 0x10;
+	SSDFB_CMD3(SSD1322_CMD_SET_REMAP_AND_DUAL_COM_LINE_MODE, remap, dualcom);
+	if (error)
+		return error;
+
+	/*
+	 * Contrast settings.
+	 */
+	SSDFB_CMD1(SSD1322_CMD_SET_DEFAULT_GRAY_SCALE_TABLE);
+	if (error)
+		return error;
+	SSDFB_CMD3(SSD1322_CMD_DISPLAY_ENHANCEMENT_A,
+	    SSD1322_DISPLAY_ENHANCEMENT_A_MAGIC1,
+	    SSD1322_DISPLAY_ENHANCEMENT_A_MAGIC2);
+	if (error)
+		return error;
+	SSDFB_CMD3(SSD1322_CMD_DISPLAY_ENHANCEMENT_B,
+	    SSD1322_DISPLAY_ENHANCEMENT_B_MAGIC1,
+	    SSD1322_DISPLAY_ENHANCEMENT_B_MAGIC2);
+	if (error)
+		return error;
+	SSDFB_CMD2(SSD1322_CMD_SET_CONTRAST_CURRENT,
+	    sc->sc_contrast);
+	if (error)
+		return error;
+	SSDFB_CMD2(SSD1322_CMD_MASTER_CONTRAST_CURRENT_CONTROL,
+	    SSD1322_DEFAULT_MASTER_CONTRAST_CURRENT_CONTROL);
+	if (error)
+		return error;
+
+	/*
+	 * Reset display engine state.
+	 */
+	SSDFB_CMD2(SSD1322_CMD_SET_DISPLAY_OFFSET, 0x00);
+	if (error)
+		return error;
+	SSDFB_CMD2(SSD1322_CMD_SET_DISPLAY_START_LINE, 0x00);
+	if (error)
+		return error;
+	SSDFB_CMD1(SSD1322_CMD_NORMAL_DISPLAY + (uint8_t)sc->sc_inverse);
+	if (error)
+		return error;
+	SSDFB_CMD1(SSD1322_CMD_EXIT_PARTIAL_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;
@@ -686,12 +853,17 @@ static int
 ssdfb_set_contrast(struct ssdfb_softc *sc, uint8_t value, bool usepoll)
 {
 	uint8_t cmd[2];
-	int error;
 
-	sc->sc_contrast = value;
-	SSDFB_CMD2(SSDFB_CMD_SET_CONTRAST_CONTROL, value);
+	switch (sc->sc_p->p_controller_id) {
+	case SSDFB_CONTROLLER_SSD1322:
+		cmd[0] = SSD1322_CMD_SET_CONTRAST_CURRENT;
+		break;
+	default:
+		cmd[0] = SSDFB_CMD_SET_CONTRAST_CONTROL;
+	}
+	cmd[1] = sc->sc_contrast = value;
 
-	return error;
+	return sc->sc_cmd(sc->sc_cookie, cmd, sizeof(cmd), usepoll);
 }
 
 static int
@@ -795,8 +967,10 @@ ssdfb_clear_modify(struct ssdfb_softc *s
 	bool ret;
 
 	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
+		mutex_enter(&sc->sc_cond_mtx);
 		ret = sc->sc_modified;
 		sc->sc_modified = false;
+		mutex_exit(&sc->sc_cond_mtx);
 		return ret;
 	}
 
@@ -843,14 +1017,15 @@ ssdfb_thread(void *arg)
 			continue;
 		}
 		sc->sc_backoff = 1;
-		(void) ssdfb_clear_modify(sc);
-		if (sc->sc_usepoll)
-			continue;
 		mutex_exit(&sc->sc_cond_mtx);
-		error = ssdfb_sync(sc, false);
-		if (error)
-			device_printf(sc->sc_dev, "ssdfb_sync: error %d\n",
-			    error);
+		(void) ssdfb_clear_modify(sc);
+		if (!sc->sc_usepoll) {
+			error = ssdfb_sync(sc, false);
+			if (error)
+				device_printf(sc->sc_dev,
+				    "ssdfb_sync: error %d\n",
+				    error);
+		}
 		mutex_enter(&sc->sc_cond_mtx);
 	}
 
@@ -867,6 +1042,12 @@ ssdfb_set_usepoll(struct ssdfb_softc *sc
 static int
 ssdfb_sync(struct ssdfb_softc *sc, bool usepoll)
 {
+	return sc->sc_p->p_sync(sc, usepoll);
+}
+
+static int
+ssdfb_sync_ssd1306(struct ssdfb_softc *sc, bool usepoll)
+{
 	struct rasops_info *ri = &sc->sc_ri;
 	int block_size = 8;
 	int ri_block_stride = ri->ri_stride * block_size;
@@ -888,12 +1069,10 @@ ssdfb_sync(struct ssdfb_softc *sc, bool 
 	y1 = height_in_blocks;
 	y2 = -1;
 	for (y = 0; y < height_in_blocks; y++) {
-		src = &ri->ri_bits[y*ri_block_stride];
+		src = &ri->ri_bits[y * ri_block_stride];
 		blockp = &sc->sc_gddram[y * width_in_blocks];
 		for (x = 0; x < width_in_blocks; x++) {
-			raw_block = (ri->ri_depth == 1)
-			   ? ssdfb_transpose_block_1bpp(src, ri->ri_stride)
-			   : ssdfb_transpose_block_8bpp(src, ri->ri_stride);
+			raw_block = ssdfb_transpose_block(src, ri->ri_stride);
 			if (raw_block != blockp->raw) {
 				blockp->raw = raw_block;
 				if (x1 > x)
@@ -922,10 +1101,86 @@ ssdfb_sync(struct ssdfb_softc *sc, bool 
 	return 0;
 }
 
+static int
+ssdfb_sync_ssd1322(struct ssdfb_softc *sc, bool usepoll)
+{
+	struct rasops_info *ri = &sc->sc_ri;
+	int block_size_w = 4;
+	int width = sc->sc_p->p_width;
+	int height = sc->sc_p->p_height;
+	int width_in_blocks = width / block_size_w;
+	int x, y;
+	uint16_t *blockp;
+	uint16_t raw_block;
+	uint16_t *src;
+	uint32_t *src32;
+	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 = sc->sc_p->p_width;
+	x2 = -1;
+	y1 = sc->sc_p->p_height;
+	y2 = -1;
+	blockp = (uint16_t*)sc->sc_gddram;
+	for (y = 0; y < height; y++) {
+		src = (uint16_t*)&ri->ri_bits[y * ri->ri_stride];
+		src32 = (uint32_t*)src;
+		for (x = 0; x < width_in_blocks; x++) {
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+#  ifdef SSDFB_USE_NATIVE_DEPTH
+			raw_block =
+			    ((*src << 12) & 0xf000) |
+			    ((*src << 4) & 0x0f00) |
+			    ((*src >> 4) & 0x00f0) |
+			    ((*src >> 12) & 0x000f);
+			src++;
+#  else
+			raw_block =
+			    ((*src32 <<  8) & 0x0f00) |
+			    ((*src32 <<  4) & 0xf000) |
+			    ((*src32 >> 16) & 0x000f) |
+			    ((*src32 >> 20) & 0x00f0);
+#  endif
+			src32++;
+#else
+#  error please add big endian host support here
+#endif
+			if (raw_block != *blockp) {
+				*blockp = raw_block;
+				if (x1 > x)
+					x1 = x;
+				if (x2 < x)
+					x2 = x;
+				if (y1 > y)
+					y1 = y;
+				if (y2 < y)
+					y2 = y;
+			}
+			blockp++;
+		}
+	}
+
+	blockp = (uint16_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_in_blocks + x1],
+		    width * sc->sc_p->p_bits_per_pixel / 8,
+		    usepoll);
+	return 0;
+}
+
 static uint64_t
-ssdfb_transpose_block_1bpp(uint8_t *src, size_t src_stride)
+ssdfb_transpose_block(uint8_t *src, size_t src_stride)
 {
 	uint64_t x = 0;
+#ifdef SSDFB_USE_NATIVE_DEPTH
 	uint64_t t;
 	int i;
 
@@ -949,14 +1204,7 @@ ssdfb_transpose_block_1bpp(uint8_t *src,
 	t = (x ^ (x >>  7)) & 0x00AA00AA00AA00AAULL;
 	x = x ^ t ^ (t <<  7);
 	x = bswap64(x);
-
-	return htole64(x);
-}
-
-static uint64_t
-ssdfb_transpose_block_8bpp(uint8_t *src, size_t src_stride)
-{
-	uint64_t x = 0;
+#else
 	int m, n;
 
 	for (m = 0; m < 8; m++) {
@@ -965,7 +1213,7 @@ ssdfb_transpose_block_8bpp(uint8_t *src,
 			x |= src[n * src_stride + m] ? (1ULL << 63) : 0;
 		}
 	}
-
+#endif
 	return htole64(x);
 }
 

Index: src/sys/dev/ic/ssdfbvar.h
diff -u src/sys/dev/ic/ssdfbvar.h:1.4 src/sys/dev/ic/ssdfbvar.h:1.5
--- src/sys/dev/ic/ssdfbvar.h:1.4	Tue Oct 22 22:03:27 2019
+++ src/sys/dev/ic/ssdfbvar.h	Sat Nov  2 14:18:36 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: ssdfbvar.h,v 1.4 2019/10/22 22:03:27 tnn Exp $ */
+/* $NetBSD: ssdfbvar.h,v 1.5 2019/11/02 14:18:36 tnn Exp $ */
 
 /*
  * Copyright (c) 2019 The NetBSD Foundation, Inc.
@@ -36,6 +36,7 @@
 #define SSDFB_ATTACH_FLAG_UPSIDEDOWN		0x00000100
 #define SSDFB_ATTACH_FLAG_INVERSE		0x00000200
 #define SSDFB_ATTACH_FLAG_CONSOLE		0x00000400
+#define SSDFB_ATTACH_FLAG_MPSAFE		0x00000800
 
 /*
  * Fundamental commands
@@ -159,14 +160,14 @@
 #define SSD1322_CMD_ENTIRE_DISPLAY_ON			0xa5
 #define SSD1322_CMD_NORMAL_DISPLAY			0xa6
 #define SSD1322_CMD_INVERSE_DISPLAY			0xa7
+#define SSD1322_CMD_SET_SLEEP_MODE_ON			0xae
+#define SSD1322_CMD_SET_SLEEP_MODE_OFF			0xaf
 
 #define SSD1322_CMD_ENABLE_PARTIAL_DISPLAY		0xa8
 #define SSD1322_CMD_EXIT_PARTIAL_DISPLAY		0xa9
 #define SSD1322_CMD_FUNCTION_SELECTION			0xab
 	#define SSD1322_FUNCTION_SELECTION_EXTERNAL_VDD	0
 	#define SSD1322_FUNCTION_SELECTION_INTERNAL_VDD	__BIT(0)
-#define SSD1322_CMD_SET_SLEEP_MODE_ON			0xae
-#define SSD1322_CMD_SET_SLEEP_MODE_OFF			0xaf
 #define SSD1322_CMD_SET_PHASE_LENGTH			0xb1
 	#define SSD1322_PHASE_LENGTH_PHASE_2_MASK	__BITS(7, 4)
 	#define SSD1322_DEFAULT_PHASE_2			7
@@ -245,6 +246,7 @@ struct ssdfb_product {
 	const char			*p_name;
 	int				p_width;
 	int				p_height;
+	int				p_bits_per_pixel;
 	int				p_panel_shift;
 	uint8_t				p_fosc;
 	uint8_t				p_fosc_div;
@@ -254,9 +256,8 @@ struct ssdfb_product {
 	uint8_t				p_vcomh_deselect_level;
 	uint8_t				p_default_contrast;
 	uint8_t				p_multiplex_ratio;
-	uint8_t				p_chargepump_cmd;
-	uint8_t				p_chargepump_arg;
 	int				(*p_init)(struct ssdfb_softc *);
+	int				(*p_sync)(struct ssdfb_softc *, bool);
 };
 
 struct ssdfb_softc {

Reply via email to