1 /* $OpenBSD: astfb.c,v 1.1 2020/10/01 17:28:14 kettenis Exp $ */ 2 3 /* 4 * Copyright (c) 2020 Mark Kettenis. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/device.h> 21 #include <sys/systm.h> 22 23 #include <machine/bus.h> 24 25 #include <dev/ofw/openfirm.h> 26 27 #include <dev/pci/pcireg.h> 28 #include <dev/pci/pcivar.h> 29 #include <dev/pci/pcidevs.h> 30 31 #include <dev/wscons/wsconsio.h> 32 #include <dev/wscons/wsdisplayvar.h> 33 34 #include <dev/rasops/rasops.h> 35 36 #define ASTFB_PCI_FB 0x10 37 38 struct astfb_softc { 39 struct device sc_dev; 40 bus_space_tag_t sc_iot; 41 bus_space_handle_t sc_ioh; 42 43 bus_addr_t sc_fbaddr; 44 bus_size_t sc_fbsize; 45 46 struct rasops_info sc_ri; 47 struct wsscreen_descr sc_wsd; 48 struct wsscreen_list sc_wsl; 49 struct wsscreen_descr *sc_scrlist[1]; 50 }; 51 52 int astfb_wsioctl(void *, u_long, caddr_t, int, struct proc *); 53 paddr_t astfb_wsmmap(void *, off_t, int); 54 int astfb_alloc_screen(void *, const struct wsscreen_descr *, 55 void **, int *, int *, uint32_t *); 56 57 struct wsdisplay_accessops astfb_accessops = { 58 .ioctl = astfb_wsioctl, 59 .mmap = astfb_wsmmap, 60 .alloc_screen = astfb_alloc_screen, 61 .free_screen = rasops_free_screen, 62 .show_screen = rasops_show_screen, 63 .getchar = rasops_getchar, 64 .load_font = rasops_load_font, 65 .list_font = rasops_list_font, 66 .scrollback = rasops_scrollback 67 }; 68 69 int astfb_match(struct device *, void *, void *); 70 void astfb_attach(struct device *, struct device *, void *); 71 72 struct cfattach astfb_ca = { 73 sizeof(struct astfb_softc), astfb_match, astfb_attach 74 }; 75 76 struct cfdriver astfb_cd = { 77 NULL, "astfb", DV_DULL 78 }; 79 80 int 81 astfb_match(struct device *parent, void *cf, void *aux) 82 { 83 struct pci_attach_args *pa = aux; 84 85 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ASPEED && 86 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ASPEED_AST2000 && 87 PCITAG_NODE(pa->pa_tag) != 0) 88 return 1; 89 90 return 0; 91 } 92 93 void 94 astfb_attach(struct device *parent, struct device *self, void *aux) 95 { 96 struct astfb_softc *sc = (struct astfb_softc *)self; 97 struct pci_attach_args *pa = aux; 98 struct rasops_info *ri = &sc->sc_ri; 99 struct wsemuldisplaydev_attach_args waa; 100 int node = PCITAG_NODE(pa->pa_tag); 101 uint32_t addr[5]; 102 103 if (OF_getpropintarray(node, "assigned-addresses", addr, 104 sizeof(addr)) < sizeof(addr)) { 105 printf(": no framebuffer\n"); 106 return; 107 } 108 109 sc->sc_fbaddr = (bus_addr_t)addr[1] << 32 | addr[2]; 110 sc->sc_fbsize = (bus_size_t)addr[3] << 32 | addr[4]; 111 112 sc->sc_iot = pa->pa_memt; 113 if (bus_space_map(sc->sc_iot, sc->sc_fbaddr, sc->sc_fbsize, 114 BUS_SPACE_MAP_LINEAR, &sc->sc_ioh)) { 115 printf(": can't map framebuffer\n"); 116 return; 117 } 118 119 printf("\n"); 120 121 ri->ri_bits = bus_space_vaddr(sc->sc_iot, sc->sc_ioh); 122 ri->ri_hw = sc; 123 124 ri->ri_width = OF_getpropint(node, "width", 0); 125 ri->ri_height = OF_getpropint(node, "height", 0); 126 ri->ri_depth = OF_getpropint(node, "depth", 0); 127 ri->ri_stride = ri->ri_width * ((ri->ri_depth + 7) / 8); 128 ri->ri_flg = RI_CENTER | RI_CLEAR | RI_FULLCLEAR | RI_WRONLY; 129 130 switch (ri->ri_depth) { 131 case 32: 132 ri->ri_rnum = 8; 133 ri->ri_rpos = 8; 134 ri->ri_gnum = 8; 135 ri->ri_gpos = 16; 136 ri->ri_bnum = 8; 137 ri->ri_bpos = 24; 138 break; 139 case 16: 140 ri->ri_rnum = 5; 141 ri->ri_rpos = 0; 142 ri->ri_gnum = 6; 143 ri->ri_gpos = 6; 144 ri->ri_bnum = 5; 145 ri->ri_bpos = 11; 146 break; 147 } 148 149 printf("%s: %dx%d, %dbpp\n", sc->sc_dev.dv_xname, 150 ri->ri_width, ri->ri_height, ri->ri_depth); 151 152 ri->ri_flg |= RI_VCONS; 153 rasops_init(ri, 160, 160); 154 155 strlcpy(sc->sc_wsd.name, "std", sizeof(sc->sc_wsd.name)); 156 sc->sc_wsd.capabilities = ri->ri_caps; 157 sc->sc_wsd.nrows = ri->ri_rows; 158 sc->sc_wsd.ncols = ri->ri_cols; 159 sc->sc_wsd.textops = &ri->ri_ops; 160 sc->sc_wsd.fontwidth = ri->ri_font->fontwidth; 161 sc->sc_wsd.fontheight = ri->ri_font->fontheight; 162 163 sc->sc_scrlist[0] = &sc->sc_wsd; 164 sc->sc_wsl.nscreens = 1; 165 sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist; 166 167 memset(&waa, 0, sizeof(waa)); 168 waa.scrdata = &sc->sc_wsl; 169 waa.accessops = &astfb_accessops; 170 waa.accesscookie = ri; 171 waa.console = 0; 172 173 config_found_sm(self, &waa, wsemuldisplaydevprint, 174 wsemuldisplaydevsubmatch); 175 } 176 177 int 178 astfb_wsioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p) 179 { 180 struct rasops_info *ri = v; 181 struct wsdisplay_fbinfo *wdf; 182 183 switch (cmd) { 184 case WSDISPLAYIO_GTYPE: 185 *(u_int *)data = WSDISPLAY_TYPE_ASTFB; 186 break; 187 case WSDISPLAYIO_GINFO: 188 wdf = (void *)data; 189 wdf->width = ri->ri_width; 190 wdf->height = ri->ri_height; 191 wdf->depth = ri->ri_depth; 192 wdf->cmsize = 0; /* color map is unavailable */ 193 break; 194 case WSDISPLAYIO_LINEBYTES: 195 *(u_int *)data = ri->ri_stride; 196 break; 197 case WSDISPLAYIO_SMODE: 198 break; 199 case WSDISPLAYIO_GETSUPPORTEDDEPTH: 200 switch (ri->ri_depth) { 201 case 32: 202 *(u_int *)data = WSDISPLAYIO_DEPTH_24_32; 203 break; 204 case 16: 205 *(u_int *)data = WSDISPLAYIO_DEPTH_16; 206 break; 207 default: 208 return -1; 209 } 210 break; 211 default: 212 return -1; 213 } 214 215 return 0; 216 } 217 218 paddr_t 219 astfb_wsmmap(void *v, off_t off, int prot) 220 { 221 struct rasops_info *ri = v; 222 struct astfb_softc *sc = ri->ri_hw; 223 224 if (off < 0 || off >= sc->sc_fbaddr) 225 return -1; 226 227 return (bus_space_mmap(sc->sc_iot, sc->sc_fbaddr, 228 off, prot, BUS_SPACE_MAP_LINEAR)); 229 } 230 231 int 232 astfb_alloc_screen(void *v, const struct wsscreen_descr *type, 233 void **cookiep, int *curxp, int *curyp, uint32_t *attrp) 234 { 235 return rasops_alloc_screen(v, cookiep, curxp, curyp, attrp); 236 } 237