1 1.12 thorpej /* $NetBSD: bcm2835_genfb.c,v 1.12 2021/01/27 03:10:19 thorpej Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2013 Jared D. McNeill <jmcneill (at) invisible.ca> 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 8 1.1 jmcneill * modification, are permitted provided that the following conditions 9 1.1 jmcneill * are met: 10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 11 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 14 1.1 jmcneill * documentation and/or other materials provided with the distribution. 15 1.1 jmcneill * 16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 jmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 jmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 jmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 jmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 jmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 jmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 jmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 jmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 jmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 jmcneill * POSSIBILITY OF SUCH DAMAGE. 27 1.1 jmcneill */ 28 1.1 jmcneill 29 1.1 jmcneill /* 30 1.1 jmcneill * Generic framebuffer console driver 31 1.1 jmcneill */ 32 1.1 jmcneill 33 1.1 jmcneill #include <sys/cdefs.h> 34 1.12 thorpej __KERNEL_RCSID(0, "$NetBSD: bcm2835_genfb.c,v 1.12 2021/01/27 03:10:19 thorpej Exp $"); 35 1.1 jmcneill 36 1.1 jmcneill #include <sys/param.h> 37 1.1 jmcneill #include <sys/types.h> 38 1.10 rin #include <sys/bus.h> 39 1.10 rin #include <sys/conf.h> 40 1.1 jmcneill #include <sys/device.h> 41 1.11 rin #include <sys/endian.h> 42 1.1 jmcneill #include <sys/kmem.h> 43 1.10 rin #include <sys/systm.h> 44 1.1 jmcneill 45 1.8 skrll #include <dev/fdt/fdtvar.h> 46 1.1 jmcneill 47 1.1 jmcneill #include <dev/wsfb/genfbvar.h> 48 1.1 jmcneill 49 1.1 jmcneill struct bcmgenfb_softc { 50 1.1 jmcneill struct genfb_softc sc_gen; 51 1.1 jmcneill bus_space_tag_t sc_iot; 52 1.1 jmcneill bus_space_handle_t sc_ioh; 53 1.2 jmcneill 54 1.2 jmcneill uint32_t sc_wstype; 55 1.1 jmcneill }; 56 1.1 jmcneill 57 1.1 jmcneill static int bcmgenfb_match(device_t, cfdata_t, void *); 58 1.1 jmcneill static void bcmgenfb_attach(device_t, device_t, void *); 59 1.1 jmcneill 60 1.1 jmcneill static int bcmgenfb_ioctl(void *, void *, u_long, void *, int, lwp_t *); 61 1.1 jmcneill static paddr_t bcmgenfb_mmap(void *, void *, off_t, int); 62 1.5 skrll static bool bcmgenfb_shutdown(device_t, int); 63 1.5 skrll 64 1.5 skrll void bcmgenfb_set_console_dev(device_t); 65 1.7 macallan void bcmgenfb_set_ioctl(int(*)(void *, void *, u_long, void *, int, struct lwp *)); 66 1.5 skrll void bcmgenfb_ddb_trap_callback(int); 67 1.5 skrll 68 1.5 skrll static device_t bcmgenfb_console_dev = NULL; 69 1.7 macallan int (*bcmgenfb_ioctl_handler)(void *, void *, u_long, void *, int, struct lwp *) = NULL; 70 1.1 jmcneill 71 1.1 jmcneill CFATTACH_DECL_NEW(bcmgenfb, sizeof(struct bcmgenfb_softc), 72 1.1 jmcneill bcmgenfb_match, bcmgenfb_attach, NULL, NULL); 73 1.1 jmcneill 74 1.12 thorpej static const struct device_compatible_entry compat_data[] = { 75 1.12 thorpej { .compat = "brcm,bcm2835-fb" }, 76 1.12 thorpej DEVICE_COMPAT_EOL 77 1.12 thorpej }; 78 1.12 thorpej 79 1.1 jmcneill static int 80 1.1 jmcneill bcmgenfb_match(device_t parent, cfdata_t match, void *aux) 81 1.1 jmcneill { 82 1.8 skrll struct fdt_attach_args * const faa = aux; 83 1.1 jmcneill 84 1.12 thorpej return of_compatible_match(faa->faa_phandle, compat_data); 85 1.1 jmcneill } 86 1.1 jmcneill 87 1.1 jmcneill static void 88 1.1 jmcneill bcmgenfb_attach(device_t parent, device_t self, void *aux) 89 1.1 jmcneill { 90 1.1 jmcneill struct bcmgenfb_softc *sc = device_private(self); 91 1.8 skrll struct fdt_attach_args * const faa = aux; 92 1.2 jmcneill prop_dictionary_t dict = device_properties(self); 93 1.6 riastrad static const struct genfb_ops zero_ops; 94 1.6 riastrad struct genfb_ops ops = zero_ops; 95 1.3 jmcneill bool is_console = false; 96 1.1 jmcneill int error; 97 1.1 jmcneill 98 1.1 jmcneill sc->sc_gen.sc_dev = self; 99 1.8 skrll sc->sc_iot = faa->faa_bst; 100 1.1 jmcneill 101 1.2 jmcneill sc->sc_wstype = WSDISPLAY_TYPE_VC4; 102 1.2 jmcneill prop_dictionary_get_uint32(dict, "wsdisplay_type", &sc->sc_wstype); 103 1.3 jmcneill prop_dictionary_get_bool(dict, "is_console", &is_console); 104 1.11 rin #if BYTE_ORDER == BIG_ENDIAN 105 1.11 rin prop_dictionary_set_bool(dict, "is_swapped", true); 106 1.11 rin #endif 107 1.2 jmcneill 108 1.1 jmcneill genfb_init(&sc->sc_gen); 109 1.1 jmcneill 110 1.1 jmcneill if (sc->sc_gen.sc_width == 0 || 111 1.1 jmcneill sc->sc_gen.sc_fbsize == 0) { 112 1.1 jmcneill aprint_normal(": disabled\n"); 113 1.1 jmcneill return; 114 1.1 jmcneill } 115 1.1 jmcneill 116 1.5 skrll pmf_device_register1(self, NULL, NULL, bcmgenfb_shutdown); 117 1.5 skrll 118 1.1 jmcneill error = bus_space_map(sc->sc_iot, sc->sc_gen.sc_fboffset, 119 1.1 jmcneill sc->sc_gen.sc_fbsize, 120 1.1 jmcneill BUS_SPACE_MAP_LINEAR|BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_ioh); 121 1.1 jmcneill if (error) { 122 1.1 jmcneill aprint_error_dev(self, "couldn't map framebuffer (%d)\n", 123 1.1 jmcneill error); 124 1.1 jmcneill return; 125 1.1 jmcneill } 126 1.1 jmcneill sc->sc_gen.sc_fbaddr = bus_space_vaddr(sc->sc_iot, sc->sc_ioh); 127 1.1 jmcneill 128 1.1 jmcneill ops.genfb_ioctl = bcmgenfb_ioctl; 129 1.1 jmcneill ops.genfb_mmap = bcmgenfb_mmap; 130 1.1 jmcneill 131 1.1 jmcneill aprint_naive("\n"); 132 1.3 jmcneill 133 1.3 jmcneill if (is_console) 134 1.3 jmcneill aprint_normal(": switching to framebuffer console\n"); 135 1.3 jmcneill else 136 1.3 jmcneill aprint_normal("\n"); 137 1.1 jmcneill 138 1.1 jmcneill genfb_attach(&sc->sc_gen, &ops); 139 1.1 jmcneill } 140 1.1 jmcneill 141 1.1 jmcneill static int 142 1.1 jmcneill bcmgenfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, lwp_t *l) 143 1.1 jmcneill { 144 1.2 jmcneill struct bcmgenfb_softc *sc = v; 145 1.1 jmcneill struct wsdisplayio_bus_id *busid; 146 1.1 jmcneill 147 1.1 jmcneill switch (cmd) { 148 1.1 jmcneill case WSDISPLAYIO_GTYPE: 149 1.2 jmcneill *(u_int *)data = sc->sc_wstype; 150 1.1 jmcneill return 0; 151 1.1 jmcneill case WSDISPLAYIO_GET_BUSID: 152 1.1 jmcneill busid = data; 153 1.1 jmcneill busid->bus_type = WSDISPLAYIO_BUS_SOC; 154 1.1 jmcneill return 0; 155 1.4 macallan case WSDISPLAYIO_GET_FBINFO: 156 1.4 macallan { 157 1.4 macallan struct wsdisplayio_fbinfo *fbi = data; 158 1.4 macallan struct rasops_info *ri = &sc->sc_gen.vd.active->scr_ri; 159 1.4 macallan int ret; 160 1.4 macallan 161 1.4 macallan ret = wsdisplayio_get_fbinfo(ri, fbi); 162 1.4 macallan fbi->fbi_flags |= WSFB_VRAM_IS_RAM; 163 1.4 macallan return ret; 164 1.4 macallan } 165 1.1 jmcneill default: 166 1.7 macallan if (bcmgenfb_ioctl_handler != NULL) 167 1.7 macallan return bcmgenfb_ioctl_handler(v, vs, cmd, data, flag, l); 168 1.1 jmcneill return EPASSTHROUGH; 169 1.1 jmcneill } 170 1.1 jmcneill } 171 1.1 jmcneill 172 1.1 jmcneill static paddr_t 173 1.1 jmcneill bcmgenfb_mmap(void *v, void *vs, off_t offset, int prot) 174 1.1 jmcneill { 175 1.1 jmcneill struct bcmgenfb_softc *sc = v; 176 1.1 jmcneill 177 1.1 jmcneill if (offset < 0 || offset >= sc->sc_gen.sc_fbsize) 178 1.1 jmcneill return -1; 179 1.1 jmcneill 180 1.1 jmcneill return bus_space_mmap(sc->sc_iot, sc->sc_gen.sc_fboffset, offset, 181 1.1 jmcneill prot, BUS_SPACE_MAP_LINEAR|BUS_SPACE_MAP_PREFETCHABLE); 182 1.1 jmcneill } 183 1.5 skrll 184 1.5 skrll static bool 185 1.5 skrll bcmgenfb_shutdown(device_t self, int flags) 186 1.5 skrll { 187 1.5 skrll genfb_enable_polling(self); 188 1.5 skrll return true; 189 1.5 skrll } 190 1.5 skrll void 191 1.5 skrll bcmgenfb_set_console_dev(device_t dev) 192 1.5 skrll { 193 1.9 ryo /* skip if already set. called from each genfb0,genfb1,... */ 194 1.9 ryo if (bcmgenfb_console_dev != NULL) 195 1.9 ryo return; 196 1.9 ryo 197 1.5 skrll bcmgenfb_console_dev = dev; 198 1.5 skrll } 199 1.5 skrll 200 1.5 skrll void 201 1.7 macallan bcmgenfb_set_ioctl(int(*boo)(void *, void *, u_long, void *, int, struct lwp *)) 202 1.7 macallan { 203 1.7 macallan bcmgenfb_ioctl_handler = boo; 204 1.7 macallan } 205 1.7 macallan 206 1.7 macallan void 207 1.5 skrll bcmgenfb_ddb_trap_callback(int where) 208 1.5 skrll { 209 1.5 skrll if (bcmgenfb_console_dev == NULL) 210 1.5 skrll return; 211 1.5 skrll 212 1.5 skrll if (where) { 213 1.5 skrll genfb_enable_polling(bcmgenfb_console_dev); 214 1.5 skrll } else { 215 1.5 skrll genfb_disable_polling(bcmgenfb_console_dev); 216 1.5 skrll } 217 1.5 skrll } 218