1 /* $OpenBSD: simplefb.c,v 1.1 2017/01/03 19:57:01 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2016 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 22 #include <machine/bus.h> 23 #include <machine/fdt.h> 24 25 #include <dev/ofw/openfirm.h> 26 #include <dev/ofw/fdt.h> 27 28 #include <dev/wscons/wsconsio.h> 29 #include <dev/wscons/wsdisplayvar.h> 30 #include <dev/rasops/rasops.h> 31 32 struct simplefb_format { 33 const char *format; 34 int depth; 35 int rpos, rnum; 36 int gpos, gnum; 37 int bpos, bnum; 38 }; 39 40 /* 41 * Supported pixel formats. Layout ommitted when it matches the 42 * rasops defaults. 43 */ 44 struct simplefb_format simplefb_formats[] = { 45 { "r5g6b5", 16 }, 46 { "x1r5g5b5", 15 }, 47 { "a1r5g5b5", 15 }, 48 { "r8g8b8", 24 }, 49 { "x8r8g8b8", 32 }, 50 { "a8r8g8b8", 32 }, 51 { "a8b8g8r8", 32, 0, 8, 8, 8, 16, 8 } 52 }; 53 54 struct simplefb_softc { 55 struct device sc_dev; 56 bus_space_tag_t sc_iot; 57 bus_space_handle_t sc_ioh; 58 59 struct rasops_info sc_ri; 60 struct wsscreen_descr sc_wsd; 61 struct wsscreen_list sc_wsl; 62 struct wsscreen_descr *sc_scrlist[1]; 63 64 struct simplefb_format *sc_format; 65 paddr_t sc_paddr; 66 psize_t sc_psize; 67 }; 68 69 int simplefb_match(struct device *, void *, void *); 70 void simplefb_attach(struct device *, struct device *, void *); 71 72 struct cfattach simplefb_ca = { 73 sizeof(struct simplefb_softc), simplefb_match, simplefb_attach 74 }; 75 76 struct cfdriver simplefb_cd = { 77 NULL, "simplefb", DV_DULL 78 }; 79 80 int simplefb_wsioctl(void *, u_long, caddr_t, int, struct proc *); 81 paddr_t simplefb_wsmmap(void *, off_t, int); 82 int simplefb_alloc_screen(void *, const struct wsscreen_descr *, 83 void **, int *, int *, long *); 84 85 struct wsdisplay_accessops simplefb_accessops = { 86 .ioctl = simplefb_wsioctl, 87 .mmap = simplefb_wsmmap, 88 .alloc_screen = simplefb_alloc_screen, 89 .free_screen = rasops_free_screen, 90 .show_screen = rasops_show_screen, 91 .getchar = rasops_getchar, 92 .load_font = rasops_load_font, 93 .list_font = rasops_list_font, 94 }; 95 96 int 97 simplefb_match(struct device *parent, void *match, void *aux) 98 { 99 struct fdt_attach_args *faa = aux; 100 101 return OF_is_compatible(faa->fa_node, "simple-framebuffer"); 102 } 103 104 void 105 simplefb_attach(struct device *parent, struct device *self, void *aux) 106 { 107 struct simplefb_softc *sc = (struct simplefb_softc *)self; 108 struct fdt_attach_args *faa = aux; 109 struct rasops_info *ri = &sc->sc_ri; 110 struct wsemuldisplaydev_attach_args waa; 111 char format[16]; 112 int i; 113 114 if (faa->fa_nreg < 1) 115 return; 116 117 format[0] = 0; 118 OF_getprop(faa->fa_node, "format", format, sizeof(format)); 119 format[sizeof(format) - 1] = 0; 120 121 for (i = 0; i < nitems(simplefb_formats); i++) { 122 if (strcmp(format, simplefb_formats[i].format) == 0) { 123 sc->sc_format = &simplefb_formats[i]; 124 break; 125 } 126 } 127 if (sc->sc_format == NULL) { 128 printf(": unsupported format \"%s\"\n", format); 129 return; 130 } 131 132 sc->sc_iot = faa->fa_iot; 133 sc->sc_paddr = faa->fa_reg[0].addr; 134 sc->sc_psize = faa->fa_reg[0].size; 135 if (bus_space_map(sc->sc_iot, sc->sc_paddr, sc->sc_psize, 136 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_ioh)) 137 panic("%s: bus_space_map failed!", __func__); 138 139 ri->ri_width = OF_getpropint(faa->fa_node, "width", 0); 140 ri->ri_height = OF_getpropint(faa->fa_node, "height", 0); 141 ri->ri_stride = OF_getpropint(faa->fa_node, "stride", 0); 142 ri->ri_depth = sc->sc_format->depth; 143 ri->ri_rpos = sc->sc_format->rpos; 144 ri->ri_rnum = sc->sc_format->rnum; 145 ri->ri_gpos = sc->sc_format->gpos; 146 ri->ri_gnum = sc->sc_format->gnum; 147 ri->ri_bpos = sc->sc_format->bpos; 148 ri->ri_bnum = sc->sc_format->bnum; 149 ri->ri_flg = RI_CENTER | RI_CLEAR | RI_FULLCLEAR; 150 ri->ri_flg |= RI_VCONS | RI_WRONLY; 151 ri->ri_bits = bus_space_vaddr(sc->sc_iot, sc->sc_ioh); 152 ri->ri_hw = sc; 153 154 printf(": %dx%d\n", ri->ri_width, ri->ri_height); 155 156 rasops_init(ri, 160, 160); 157 158 strlcpy(sc->sc_wsd.name, "std", sizeof(sc->sc_wsd.name)); 159 sc->sc_wsd.capabilities = ri->ri_caps; 160 sc->sc_wsd.nrows = ri->ri_rows; 161 sc->sc_wsd.ncols = ri->ri_cols; 162 sc->sc_wsd.textops = &ri->ri_ops; 163 sc->sc_wsd.fontwidth = ri->ri_font->fontwidth; 164 sc->sc_wsd.fontheight = ri->ri_font->fontheight; 165 166 sc->sc_scrlist[0] = &sc->sc_wsd; 167 sc->sc_wsl.nscreens = 1; 168 sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist; 169 170 memset(&waa, 0, sizeof(waa)); 171 waa.scrdata = &sc->sc_wsl; 172 waa.accessops = &simplefb_accessops; 173 waa.accesscookie = ri; 174 175 config_found_sm(self, &waa, wsemuldisplaydevprint, 176 wsemuldisplaydevsubmatch); 177 } 178 179 int 180 simplefb_wsioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 181 { 182 struct rasops_info *ri = v; 183 struct wsdisplay_fbinfo *wdf; 184 185 switch (cmd) { 186 case WSDISPLAYIO_GTYPE: 187 *(int *)data = WSDISPLAY_TYPE_EFIFB; 188 return 0; 189 case WSDISPLAYIO_GINFO: 190 wdf = (struct wsdisplay_fbinfo *)data; 191 wdf->width = ri->ri_width; 192 wdf->height = ri->ri_height; 193 wdf->depth = ri->ri_depth; 194 wdf->cmsize = 0; /* color map is unavailable */ 195 break; 196 case WSDISPLAYIO_LINEBYTES: 197 *(u_int *)data = ri->ri_stride; 198 break; 199 case WSDISPLAYIO_SMODE: 200 break; 201 case WSDISPLAYIO_GETSUPPORTEDDEPTH: 202 switch (ri->ri_depth) { 203 case 32: 204 *(u_int *)data = WSDISPLAYIO_DEPTH_24_32; 205 break; 206 case 24: 207 *(u_int *)data = WSDISPLAYIO_DEPTH_24_24; 208 break; 209 case 16: 210 *(u_int *)data = WSDISPLAYIO_DEPTH_16; 211 break; 212 case 15: 213 *(u_int *)data = WSDISPLAYIO_DEPTH_15; 214 break; 215 default: 216 return -1; 217 } 218 break; 219 default: 220 return -1; 221 } 222 223 return 0; 224 } 225 226 paddr_t 227 simplefb_wsmmap(void *v, off_t off, int prot) 228 { 229 struct rasops_info *ri = v; 230 struct simplefb_softc *sc = ri->ri_hw; 231 232 if (off < 0 || off >= sc->sc_psize) 233 return -1; 234 235 return sc->sc_paddr + off; 236 } 237 238 int 239 simplefb_alloc_screen(void *v, const struct wsscreen_descr *type, 240 void **cookiep, int *curxp, int *curyp, long *attrp) 241 { 242 return rasops_alloc_screen(v, cookiep, curxp, curyp, attrp); 243 } 244