1*c7fb772bSthorpej /* $NetBSD: clpslcd.c,v 1.3 2021/08/07 16:18:43 thorpej Exp $ */
20514024aSkiyohara /*
30514024aSkiyohara * Copyright (c) 2013 KIYOHARA Takashi
40514024aSkiyohara * All rights reserved.
50514024aSkiyohara *
60514024aSkiyohara * Redistribution and use in source and binary forms, with or without
70514024aSkiyohara * modification, are permitted provided that the following conditions
80514024aSkiyohara * are met:
90514024aSkiyohara * 1. Redistributions of source code must retain the above copyright
100514024aSkiyohara * notice, this list of conditions and the following disclaimer.
110514024aSkiyohara * 2. Redistributions in binary form must reproduce the above copyright
120514024aSkiyohara * notice, this list of conditions and the following disclaimer in the
130514024aSkiyohara * documentation and/or other materials provided with the distribution.
140514024aSkiyohara *
150514024aSkiyohara * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
160514024aSkiyohara * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
170514024aSkiyohara * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
180514024aSkiyohara * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
190514024aSkiyohara * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
200514024aSkiyohara * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
210514024aSkiyohara * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
220514024aSkiyohara * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
230514024aSkiyohara * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
240514024aSkiyohara * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
250514024aSkiyohara * POSSIBILITY OF SUCH DAMAGE.
260514024aSkiyohara */
270514024aSkiyohara #include <sys/cdefs.h>
28*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: clpslcd.c,v 1.3 2021/08/07 16:18:43 thorpej Exp $");
290514024aSkiyohara
300514024aSkiyohara #include "rnd.h"
310514024aSkiyohara
320514024aSkiyohara #include <sys/param.h>
330514024aSkiyohara #include <sys/bus.h>
340514024aSkiyohara #include <sys/device.h>
350514024aSkiyohara #include <sys/errno.h>
360514024aSkiyohara
370514024aSkiyohara #include <uvm/uvm_extern.h>
380514024aSkiyohara
390514024aSkiyohara #include <arm/clps711x/clps711xreg.h>
400514024aSkiyohara #include <arm/clps711x/clpssocvar.h>
410514024aSkiyohara
420514024aSkiyohara #include <dev/cons.h>
430514024aSkiyohara #include <dev/wscons/wsconsio.h>
440514024aSkiyohara #include <dev/wscons/wsdisplayvar.h>
450514024aSkiyohara #include <dev/rasops/rasops.h>
460514024aSkiyohara
470514024aSkiyohara #include "locators.h"
480514024aSkiyohara
490514024aSkiyohara #define CLPSLCD_DEFAULT_DEPTH 4
500514024aSkiyohara
510514024aSkiyohara static int is_console;
520514024aSkiyohara struct clpslcd_softc {
530514024aSkiyohara device_t sc_dev;
540514024aSkiyohara
550514024aSkiyohara bus_space_tag_t sc_iot;
560514024aSkiyohara bus_space_handle_t sc_ioh;
570514024aSkiyohara
580514024aSkiyohara vaddr_t sc_buffer;
590514024aSkiyohara
600514024aSkiyohara struct rasops_info sc_ri;
610514024aSkiyohara };
620514024aSkiyohara
630514024aSkiyohara static int clpslcd_match(device_t, cfdata_t, void *);
640514024aSkiyohara static void clpslcd_attach(device_t, device_t, void *);
650514024aSkiyohara
660514024aSkiyohara /* wsdisplay functions */
670514024aSkiyohara static int clpslcd_ioctl(void *, void *, u_long, void *, int, struct lwp *);
680514024aSkiyohara static paddr_t clpslcd_mmap(void *, void *, off_t, int);
690514024aSkiyohara static int clpslcd_alloc_screen(void *, const struct wsscreen_descr *, void **,
700514024aSkiyohara int *, int *, long *);
710514024aSkiyohara static void clpslcd_free_screen(void *, void *);
720514024aSkiyohara static int clpslcd_show_screen(void *, void *, int,
730514024aSkiyohara void (*)(void *, int, int), void *);
740514024aSkiyohara
750514024aSkiyohara CFATTACH_DECL_NEW(clpslcd, sizeof(struct clpslcd_softc),
760514024aSkiyohara clpslcd_match, clpslcd_attach, NULL, NULL);
770514024aSkiyohara
780514024aSkiyohara
790514024aSkiyohara static struct wsscreen_descr clpslcd_descr = {
800514024aSkiyohara .name = "clpslcd",
810514024aSkiyohara .fontwidth = 8,
820514024aSkiyohara .fontheight = 16,
830514024aSkiyohara .capabilities = WSSCREEN_WSCOLORS,
840514024aSkiyohara };
850514024aSkiyohara static const struct wsscreen_descr *clpslcd_descrs[] = {
860514024aSkiyohara &clpslcd_descr
870514024aSkiyohara };
880514024aSkiyohara
890514024aSkiyohara static const struct wsscreen_list clpslcd_screen_list = {
900514024aSkiyohara .nscreens = __arraycount(clpslcd_descrs),
910514024aSkiyohara .screens = clpslcd_descrs,
920514024aSkiyohara };
930514024aSkiyohara
940514024aSkiyohara struct wsdisplay_accessops clpslcd_accessops = {
950514024aSkiyohara clpslcd_ioctl,
960514024aSkiyohara clpslcd_mmap,
970514024aSkiyohara clpslcd_alloc_screen,
980514024aSkiyohara clpslcd_free_screen,
990514024aSkiyohara clpslcd_show_screen,
1000514024aSkiyohara NULL,
1010514024aSkiyohara NULL,
1020514024aSkiyohara NULL,
1030514024aSkiyohara };
1040514024aSkiyohara
1050514024aSkiyohara /* ARGSUSED */
1060514024aSkiyohara static int
clpslcd_match(device_t parent,cfdata_t match,void * aux)1070514024aSkiyohara clpslcd_match(device_t parent, cfdata_t match, void *aux)
1080514024aSkiyohara {
1090514024aSkiyohara
1100514024aSkiyohara return 1;
1110514024aSkiyohara }
1120514024aSkiyohara
1130514024aSkiyohara /* ARGSUSED */
1140514024aSkiyohara static void
clpslcd_attach(device_t parent,device_t self,void * aux)1150514024aSkiyohara clpslcd_attach(device_t parent, device_t self, void *aux)
1160514024aSkiyohara {
1170514024aSkiyohara struct clpslcd_softc *sc = device_private(self);
1180514024aSkiyohara struct clpssoc_attach_args *aa = aux;
1190514024aSkiyohara struct wsemuldisplaydev_attach_args waa;
1200514024aSkiyohara prop_dictionary_t dict = device_properties(self);
1210514024aSkiyohara struct rasops_info *ri;
1220514024aSkiyohara uint32_t syscon, lcdcon, depth, width, height, addr;
1230514024aSkiyohara int i;
1240514024aSkiyohara
1250514024aSkiyohara aprint_naive("\n");
1260514024aSkiyohara aprint_normal("\n");
1270514024aSkiyohara
1280514024aSkiyohara sc->sc_dev = self;
1290514024aSkiyohara sc->sc_iot = aa->aa_iot;
1300514024aSkiyohara sc->sc_ioh = *aa->aa_ioh;
1310514024aSkiyohara
1320514024aSkiyohara if (!prop_dictionary_get_uint32(dict, "width", &width) ||
1330514024aSkiyohara !prop_dictionary_get_uint32(dict, "height", &height) ||
1340514024aSkiyohara !prop_dictionary_get_uint32(dict, "addr", &addr)) {
1350514024aSkiyohara aprint_error_dev(self, "can't get properties\n");
1360514024aSkiyohara return;
1370514024aSkiyohara }
1380514024aSkiyohara KASSERT(addr == 0xc0000000);
1390514024aSkiyohara
1400514024aSkiyohara sc->sc_buffer = addr;
1410514024aSkiyohara
1420514024aSkiyohara depth = CLPSLCD_DEFAULT_DEPTH;
1430514024aSkiyohara lcdcon =
1440514024aSkiyohara LCDCON_GSEN |
1450514024aSkiyohara LCDCON_ACP(13) |
1460514024aSkiyohara LCDCON_PP(width * height) |
1470514024aSkiyohara LCDCON_LL(width) |
1480514024aSkiyohara LCDCON_VBS(width * height * depth);
1490514024aSkiyohara if (depth == 4)
1500514024aSkiyohara lcdcon |= LCDCON_GSMD;
1510514024aSkiyohara
1520514024aSkiyohara syscon = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PS711X_SYSCON);
1530514024aSkiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, PS711X_SYSCON,
1540514024aSkiyohara syscon | SYSCON_LCDEN);
1550514024aSkiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, PS711X_LCDCON, lcdcon);
1560514024aSkiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, PS711X_PALLSW, 0x54321fc0);
1570514024aSkiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, PS711X_PALMSW, 0xedba9876);
1580514024aSkiyohara
1590514024aSkiyohara aprint_normal_dev(self,
1600514024aSkiyohara ": %dx%d pixels, %d bpp mono\n", width, height, depth);
1610514024aSkiyohara
1620514024aSkiyohara ri = &sc->sc_ri;
1630514024aSkiyohara ri->ri_depth = depth;
1640514024aSkiyohara ri->ri_bits = (void *)addr;
1650514024aSkiyohara ri->ri_width = width;
1660514024aSkiyohara ri->ri_height = height;
1670514024aSkiyohara ri->ri_stride = width * ri->ri_depth / 8/*bits*/;
1680514024aSkiyohara ri->ri_flg = RI_FORCEMONO | RI_CLEAR | RI_CENTER;
1690514024aSkiyohara
1700514024aSkiyohara if (is_console) {
1710514024aSkiyohara long defattr;
1720514024aSkiyohara
1730514024aSkiyohara if (rasops_init(ri, 0, 0) < 0)
1740514024aSkiyohara panic("rasops_init failed");
1750514024aSkiyohara
1760514024aSkiyohara if (ri->ri_depth == 4) {
1770514024aSkiyohara /* XXXXX: Create color map. */
1780514024aSkiyohara ri->ri_devcmap[0] = 0;
1790514024aSkiyohara for (i = 1; i < 15; i++) {
1800514024aSkiyohara ri->ri_devcmap[i] =
1810514024aSkiyohara i | (i << 8) | (i << 16) | (i << 24);
1820514024aSkiyohara }
1830514024aSkiyohara }
1840514024aSkiyohara ri->ri_devcmap[15] = -1;
1850514024aSkiyohara
1860514024aSkiyohara clpslcd_descr.ncols = ri->ri_cols;
1870514024aSkiyohara clpslcd_descr.nrows = ri->ri_rows;
1880514024aSkiyohara clpslcd_descr.textops = &ri->ri_ops;
1890514024aSkiyohara clpslcd_descr.capabilities = ri->ri_caps;
1900514024aSkiyohara
1910514024aSkiyohara if ((ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr) != 0)
1920514024aSkiyohara panic("allocattr failed");
1930514024aSkiyohara wsdisplay_cnattach(&clpslcd_descr, ri, ri->ri_ccol, ri->ri_crow,
1940514024aSkiyohara defattr);
1950514024aSkiyohara }
1960514024aSkiyohara
1970514024aSkiyohara waa.console = is_console;
1980514024aSkiyohara waa.scrdata = &clpslcd_screen_list;
1990514024aSkiyohara waa.accessops = &clpslcd_accessops;
2000514024aSkiyohara waa.accesscookie = sc;
2010514024aSkiyohara
202*c7fb772bSthorpej config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
2030514024aSkiyohara }
2040514024aSkiyohara
2050514024aSkiyohara static int
clpslcd_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)2060514024aSkiyohara clpslcd_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
2070514024aSkiyohara struct lwp *l)
2080514024aSkiyohara {
2090514024aSkiyohara struct clpslcd_softc *sc = v;
2100514024aSkiyohara struct wsdisplay_fbinfo *wsdisp_info;
2110514024aSkiyohara
2120514024aSkiyohara switch (cmd) {
2130514024aSkiyohara case WSDISPLAYIO_GTYPE:
2140514024aSkiyohara *(int *)data = WSDISPLAY_TYPE_CLPS711X;
2150514024aSkiyohara return 0;
2160514024aSkiyohara
2170514024aSkiyohara case WSDISPLAYIO_GINFO:
2180514024aSkiyohara wsdisp_info = (struct wsdisplay_fbinfo *)data;
2190514024aSkiyohara wsdisp_info->height = sc->sc_ri.ri_height;
2200514024aSkiyohara wsdisp_info->width = sc->sc_ri.ri_width;
2210514024aSkiyohara wsdisp_info->depth = sc->sc_ri.ri_depth;
2220514024aSkiyohara wsdisp_info->cmsize = 0;
2230514024aSkiyohara return 0;
2240514024aSkiyohara
2250514024aSkiyohara case WSDISPLAYIO_GVIDEO:
2260514024aSkiyohara if (1) /* XXXX */
2270514024aSkiyohara *(int *)data = WSDISPLAYIO_VIDEO_ON;
2280514024aSkiyohara else
2290514024aSkiyohara *(int *)data = WSDISPLAYIO_VIDEO_OFF;
2300514024aSkiyohara return 0;
2310514024aSkiyohara
2320514024aSkiyohara case WSDISPLAYIO_SVIDEO:
2330514024aSkiyohara if (*(int *)data == WSDISPLAYIO_VIDEO_ON) {
2340514024aSkiyohara /* XXXX: turn on */
2350514024aSkiyohara } else {
2360514024aSkiyohara /* XXXX: turn off */
2370514024aSkiyohara }
2380514024aSkiyohara return 0;
2390514024aSkiyohara
2400514024aSkiyohara case WSDISPLAYIO_LINEBYTES:
2410514024aSkiyohara *(int *)data = sc->sc_ri.ri_stride;
2420514024aSkiyohara return 0;
2430514024aSkiyohara }
2440514024aSkiyohara
2450514024aSkiyohara return EPASSTHROUGH;
2460514024aSkiyohara }
2470514024aSkiyohara
2480514024aSkiyohara static paddr_t
clpslcd_mmap(void * v,void * vs,off_t off,int prot)2490514024aSkiyohara clpslcd_mmap(void *v, void *vs, off_t off, int prot)
2500514024aSkiyohara {
2510514024aSkiyohara struct clpslcd_softc *sc = v;
2520514024aSkiyohara
2530514024aSkiyohara if (off < 0 || sc->sc_ri.ri_stride * sc->sc_ri.ri_height <= off)
2540514024aSkiyohara return -1;
2550514024aSkiyohara
2560514024aSkiyohara return (paddr_t)sc->sc_ri.ri_bits + off;
2570514024aSkiyohara }
2580514024aSkiyohara
2590514024aSkiyohara static int
clpslcd_alloc_screen(void * v,const struct wsscreen_descr * scr,void ** cookiep,int * curxp,int * curyp,long * attrp)2600514024aSkiyohara clpslcd_alloc_screen(void *v, const struct wsscreen_descr *scr, void **cookiep,
2610514024aSkiyohara int *curxp, int *curyp, long *attrp)
2620514024aSkiyohara {
2630514024aSkiyohara printf("%s\n", __func__);
2640514024aSkiyohara return -1;
2650514024aSkiyohara }
2660514024aSkiyohara
2670514024aSkiyohara static void
clpslcd_free_screen(void * v,void * cookie)2680514024aSkiyohara clpslcd_free_screen(void *v, void *cookie)
2690514024aSkiyohara {
2700514024aSkiyohara printf("%s\n", __func__);
2710514024aSkiyohara }
2720514024aSkiyohara
2730514024aSkiyohara static int
clpslcd_show_screen(void * v,void * cookie,int waitok,void (* func)(void *,int,int),void * arg)2740514024aSkiyohara clpslcd_show_screen(void *v, void *cookie, int waitok,
2750514024aSkiyohara void (*func)(void *, int, int), void *arg)
2760514024aSkiyohara {
2770514024aSkiyohara printf("%s\n", __func__);
2780514024aSkiyohara return -1;
2790514024aSkiyohara }
2800514024aSkiyohara
2810514024aSkiyohara int
clpslcd_cnattach(void)2820514024aSkiyohara clpslcd_cnattach(void)
2830514024aSkiyohara {
2840514024aSkiyohara
2850514024aSkiyohara is_console = 1;
2860514024aSkiyohara return 0;
2870514024aSkiyohara }
288