From afb9146375bcd625a277f562ca4118fbf63f824a Mon Sep 17 00:00:00 2001 From: Patrick Wildt Date: Fri, 22 Feb 2019 09:39:34 +0000 Subject: Allow ssdfb(4) to be mmap(2)-able so that we can use its framebuffer from the userland. Also allow changing the brightness levels so that it can even be turned off to save power and to prevent burn in. --- sys/dev/fdt/ssdfb.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 6 deletions(-) (limited to 'sys/dev') diff --git a/sys/dev/fdt/ssdfb.c b/sys/dev/fdt/ssdfb.c index cd741876d7f..105592d6194 100644 --- a/sys/dev/fdt/ssdfb.c +++ b/sys/dev/fdt/ssdfb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssdfb.c,v 1.9 2019/01/17 13:33:51 patrick Exp $ */ +/* $OpenBSD: ssdfb.c,v 1.10 2019/02/22 09:39:33 patrick Exp $ */ /* * Copyright (c) 2018 Patrick Wildt * @@ -22,8 +22,11 @@ #include #include +#include + #include #include +#include #include #include @@ -74,6 +77,9 @@ struct ssdfb_softc { struct wsdisplay_emulops sc_riops; int (*sc_ri_do_cursor)(struct rasops_info *); + uint8_t sc_brightness; + int sc_mode; + uint8_t sc_column_range[2]; uint8_t sc_page_range[2]; @@ -294,9 +300,11 @@ ssdfb_attach(struct ssdfb_softc *sc) 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_fbsize = round_page((sc->sc_width * sc->sc_height) / 8); sc->sc_fb = malloc(sc->sc_fbsize, M_DEVBUF, M_WAITOK | M_ZERO); + sc->sc_brightness = 223; + ri = &sc->sc_rinfo; ri->ri_bits = malloc(sc->sc_fbsize, M_DEVBUF, M_WAITOK | M_ZERO); ri->ri_bs = mallocarray(sc->sc_width * sc->sc_height, @@ -405,7 +413,7 @@ ssdfb_init(struct ssdfb_softc *sc) reg[1] |= 1 << 5; ssdfb_write_command(sc, reg, 2); reg[0] = SSDFB_SET_CONTRAST_CONTROL; - reg[1] = 223; + reg[1] = sc->sc_brightness; ssdfb_write_command(sc, reg, 2); reg[0] = SSDFB_SET_PRE_CHARGE_PERIOD; reg[1] = (OF_getpropint(sc->sc_node, "solomon,prechargep1", 2) & 0xf) << 0; @@ -582,14 +590,44 @@ ssdfb_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) { struct ssdfb_softc *sc = v; struct rasops_info *ri = &sc->sc_rinfo; + struct wsdisplay_param *dp = (struct wsdisplay_param *)data; struct wsdisplay_fbinfo *wdf; + struct udl_ioctl_damage *d; + int mode; + uint8_t reg[2]; switch (cmd) { case WSDISPLAYIO_GETPARAM: + switch (dp->param) { + case WSDISPLAYIO_PARAM_BRIGHTNESS: + dp->min = 0; + dp->max = 255; + dp->curval = sc->sc_brightness; + break; + default: + return (-1); + } + break; case WSDISPLAYIO_SETPARAM: - return (-1); + switch (dp->param) { + case WSDISPLAYIO_PARAM_BRIGHTNESS: + if (dp->curval == 0) { + reg[0] = SSDFB_SET_DISPLAY_OFF; + ssdfb_write_command(sc, reg, 1); + } else if (sc->sc_brightness == 0) { + reg[0] = SSDFB_SET_DISPLAY_ON; + ssdfb_write_command(sc, reg, 1); + } + reg[0] = SSDFB_SET_CONTRAST_CONTROL; + reg[1] = sc->sc_brightness = dp->curval; + ssdfb_write_command(sc, reg, 2); + break; + default: + return (-1); + } + break; case WSDISPLAYIO_GTYPE: - *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; + *(u_int *)data = WSDISPLAY_TYPE_DL; break; case WSDISPLAYIO_GINFO: wdf = (struct wsdisplay_fbinfo *)data; @@ -602,10 +640,37 @@ ssdfb_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) *(u_int *)data = ri->ri_stride; break; case WSDISPLAYIO_SMODE: + mode = *(u_int *)data; + switch (mode) { + case WSDISPLAYIO_MODE_EMUL: + if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) { + memset(ri->ri_bits, 0, sc->sc_fbsize); + ssdfb_partial(sc, 0, sc->sc_width, + 0, sc->sc_height); + sc->sc_mode = mode; + } + break; + case WSDISPLAYIO_MODE_DUMBFB: + if (sc->sc_mode != WSDISPLAYIO_MODE_DUMBFB) { + memset(ri->ri_bits, 0, sc->sc_fbsize); + ssdfb_partial(sc, 0, sc->sc_width, + 0, sc->sc_height); + sc->sc_mode = mode; + } + break; + case WSDISPLAYIO_MODE_MAPPED: + default: + return (-1); + } break; case WSDISPLAYIO_GETSUPPORTEDDEPTH: *(u_int *)data = WSDISPLAYIO_DEPTH_1; break; + case UDLIO_DAMAGE: + d = (struct udl_ioctl_damage *)data; + d->status = UDLIO_STATUS_OK; + ssdfb_partial(sc, d->x1, d->x2, d->y1, d->y2); + break; default: return (-1); } @@ -616,7 +681,17 @@ ssdfb_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) paddr_t ssdfb_mmap(void *v, off_t off, int prot) { - return -1; + struct ssdfb_softc *sc = v; + struct rasops_info *ri = &sc->sc_rinfo; + paddr_t pa; + + if (off >= sc->sc_fbsize || off < 0) + return (-1); + + if (!pmap_extract(pmap_kernel(), (vaddr_t)ri->ri_bits, &pa)) + return (-1); + + return (pa + off); } int -- cgit v1.2.3