1 1.3 thorpej /* $NetBSD: meson_genfb.c,v 1.3 2025/09/06 22:53:47 thorpej Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2015-2019 Jared 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 "opt_wsdisplay_compat.h" 34 1.1 jmcneill 35 1.1 jmcneill #include <sys/cdefs.h> 36 1.3 thorpej __KERNEL_RCSID(0, "$NetBSD: meson_genfb.c,v 1.3 2025/09/06 22:53:47 thorpej Exp $"); 37 1.1 jmcneill 38 1.1 jmcneill #include <sys/param.h> 39 1.1 jmcneill #include <sys/types.h> 40 1.1 jmcneill #include <sys/systm.h> 41 1.1 jmcneill #include <sys/device.h> 42 1.1 jmcneill #include <sys/conf.h> 43 1.1 jmcneill #include <sys/bus.h> 44 1.1 jmcneill #include <sys/kmem.h> 45 1.1 jmcneill #include <sys/sysctl.h> 46 1.1 jmcneill 47 1.1 jmcneill #include <dev/fdt/fdtvar.h> 48 1.3 thorpej #include <dev/fdt/fdt_console.h> 49 1.1 jmcneill 50 1.1 jmcneill #include <arm/amlogic/meson_canvasreg.h> 51 1.1 jmcneill #include <arm/amlogic/meson_vpureg.h> 52 1.1 jmcneill #include <arm/amlogic/meson_hdmireg.h> 53 1.1 jmcneill 54 1.1 jmcneill #include <dev/wsfb/genfbvar.h> 55 1.1 jmcneill 56 1.2 thorpej static const struct device_compatible_entry compat_data[] = { 57 1.2 thorpej { .compat = "amlogic,meson8b-fb" }, 58 1.2 thorpej DEVICE_COMPAT_EOL 59 1.1 jmcneill }; 60 1.1 jmcneill 61 1.1 jmcneill #define AMLOGIC_GENFB_DEFAULT_DEPTH 16 62 1.1 jmcneill 63 1.1 jmcneill /* Map CEA-861-D video code (VIC) to framebuffer dimensions */ 64 1.1 jmcneill static const struct meson_genfb_vic2mode { 65 1.1 jmcneill u_int vic; 66 1.1 jmcneill u_int width; 67 1.1 jmcneill u_int height; 68 1.1 jmcneill u_int flags; 69 1.1 jmcneill #define INTERLACE __BIT(0) 70 1.1 jmcneill #define DBLSCAN __BIT(1) 71 1.1 jmcneill } meson_genfb_modes[] = { 72 1.1 jmcneill { 1, 640, 480 }, 73 1.1 jmcneill { 2, 720, 480 }, 74 1.1 jmcneill { 3, 720, 480 }, 75 1.1 jmcneill { 4, 1280, 720 }, 76 1.1 jmcneill { 5, 1920, 1080, INTERLACE }, 77 1.1 jmcneill { 6, 720, 480, DBLSCAN | INTERLACE }, 78 1.1 jmcneill { 7, 720, 480, DBLSCAN | INTERLACE }, 79 1.1 jmcneill { 8, 720, 240, DBLSCAN }, 80 1.1 jmcneill { 9, 720, 240, DBLSCAN }, 81 1.1 jmcneill { 16, 1920, 1080 }, 82 1.1 jmcneill { 17, 720, 576 }, 83 1.1 jmcneill { 18, 720, 576 }, 84 1.1 jmcneill { 19, 1280, 720 }, 85 1.1 jmcneill { 20, 1920, 1080, INTERLACE }, 86 1.1 jmcneill { 31, 1920, 1080 }, 87 1.1 jmcneill { 32, 1920, 1080 }, 88 1.1 jmcneill { 33, 1920, 1080 }, 89 1.1 jmcneill { 34, 1920, 1080 }, 90 1.1 jmcneill { 39, 1920, 1080, INTERLACE }, 91 1.1 jmcneill }; 92 1.1 jmcneill 93 1.1 jmcneill struct meson_genfb_softc { 94 1.1 jmcneill struct genfb_softc sc_gen; 95 1.1 jmcneill bus_space_tag_t sc_bst; 96 1.1 jmcneill bus_space_handle_t sc_cav_bsh; 97 1.1 jmcneill bus_space_handle_t sc_hdmi_bsh; 98 1.1 jmcneill bus_space_handle_t sc_vpu_bsh; 99 1.1 jmcneill bus_dma_tag_t sc_dmat; 100 1.1 jmcneill 101 1.1 jmcneill kmutex_t sc_lock; 102 1.1 jmcneill 103 1.1 jmcneill u_int sc_scale; 104 1.1 jmcneill 105 1.1 jmcneill bus_dma_segment_t sc_dmasegs[1]; 106 1.1 jmcneill bus_size_t sc_dmasize; 107 1.1 jmcneill bus_dmamap_t sc_dmamap; 108 1.1 jmcneill void *sc_dmap; 109 1.1 jmcneill 110 1.1 jmcneill uint32_t sc_wstype; 111 1.1 jmcneill 112 1.1 jmcneill struct sysctllog *sc_sysctllog; 113 1.1 jmcneill int sc_node_scale; 114 1.1 jmcneill }; 115 1.1 jmcneill 116 1.1 jmcneill static int meson_genfb_match(device_t, cfdata_t, void *); 117 1.1 jmcneill static void meson_genfb_attach(device_t, device_t, void *); 118 1.1 jmcneill 119 1.1 jmcneill static int meson_genfb_ioctl(void *, void *, u_long, void *, int, lwp_t *); 120 1.1 jmcneill static paddr_t meson_genfb_mmap(void *, void *, off_t, int); 121 1.1 jmcneill static bool meson_genfb_shutdown(device_t, int); 122 1.1 jmcneill 123 1.1 jmcneill static void meson_genfb_canvas_config(struct meson_genfb_softc *); 124 1.1 jmcneill static void meson_genfb_osd_config(struct meson_genfb_softc *); 125 1.1 jmcneill static void meson_genfb_scaler_config(struct meson_genfb_softc *); 126 1.1 jmcneill 127 1.1 jmcneill static void meson_genfb_init(struct meson_genfb_softc *); 128 1.1 jmcneill static int meson_genfb_alloc_videomem(struct meson_genfb_softc *); 129 1.1 jmcneill 130 1.1 jmcneill static int meson_genfb_scale_helper(SYSCTLFN_PROTO); 131 1.1 jmcneill 132 1.1 jmcneill void meson_genfb_set_console_dev(device_t); 133 1.1 jmcneill void meson_genfb_ddb_trap_callback(int); 134 1.1 jmcneill 135 1.1 jmcneill static int meson_genfb_console_phandle = -1; 136 1.1 jmcneill static device_t meson_genfb_console_dev = NULL; 137 1.1 jmcneill 138 1.1 jmcneill CFATTACH_DECL_NEW(meson_genfb, sizeof(struct meson_genfb_softc), 139 1.1 jmcneill meson_genfb_match, meson_genfb_attach, NULL, NULL); 140 1.1 jmcneill 141 1.1 jmcneill static inline uint32_t 142 1.1 jmcneill meson_genfb_hdmi_read_4(struct meson_genfb_softc *sc, uint32_t addr) 143 1.1 jmcneill { 144 1.1 jmcneill bus_space_write_4(sc->sc_bst, sc->sc_hdmi_bsh, HDMI_ADDR_REG, addr); 145 1.1 jmcneill bus_space_write_4(sc->sc_bst, sc->sc_hdmi_bsh, HDMI_ADDR_REG, addr); 146 1.1 jmcneill return bus_space_read_4(sc->sc_bst, sc->sc_hdmi_bsh, HDMI_DATA_REG); 147 1.1 jmcneill } 148 1.1 jmcneill 149 1.1 jmcneill static __unused inline void 150 1.1 jmcneill meson_genfb_hdmi_write_4(struct meson_genfb_softc *sc, uint32_t addr, 151 1.1 jmcneill uint32_t data) 152 1.1 jmcneill { 153 1.1 jmcneill bus_space_write_4(sc->sc_bst, sc->sc_hdmi_bsh, HDMI_ADDR_REG, addr); 154 1.1 jmcneill bus_space_write_4(sc->sc_bst, sc->sc_hdmi_bsh, HDMI_ADDR_REG, addr); 155 1.1 jmcneill bus_space_write_4(sc->sc_bst, sc->sc_hdmi_bsh, HDMI_DATA_REG, data); 156 1.1 jmcneill } 157 1.1 jmcneill 158 1.1 jmcneill #define HDMI_READ meson_genfb_hdmi_read_4 159 1.1 jmcneill #define HDMI_WRITE meson_genfb_hdmi_write_4 160 1.1 jmcneill 161 1.1 jmcneill #define VPU_READ(sc, reg) \ 162 1.1 jmcneill bus_space_read_4((sc)->sc_bst, (sc)->sc_vpu_bsh, (reg)) 163 1.1 jmcneill #define VPU_WRITE(sc, reg, val) \ 164 1.1 jmcneill bus_space_write_4((sc)->sc_bst, (sc)->sc_vpu_bsh, (reg), (val)) 165 1.1 jmcneill 166 1.1 jmcneill #define CAV_READ(sc, reg) \ 167 1.1 jmcneill bus_space_read_4((sc)->sc_bst, (sc)->sc_cav_bsh, (reg)) 168 1.1 jmcneill #define CAV_WRITE(sc, reg, val) \ 169 1.1 jmcneill bus_space_write_4((sc)->sc_bst, (sc)->sc_cav_bsh, (reg), (val)) 170 1.1 jmcneill 171 1.1 jmcneill static int 172 1.1 jmcneill meson_genfb_match(device_t parent, cfdata_t match, void *aux) 173 1.1 jmcneill { 174 1.1 jmcneill struct fdt_attach_args * const faa = aux; 175 1.1 jmcneill 176 1.2 thorpej return of_compatible_match(faa->faa_phandle, compat_data); 177 1.1 jmcneill } 178 1.1 jmcneill 179 1.1 jmcneill static void 180 1.1 jmcneill meson_genfb_attach(device_t parent, device_t self, void *aux) 181 1.1 jmcneill { 182 1.1 jmcneill struct meson_genfb_softc *sc = device_private(self); 183 1.1 jmcneill struct fdt_attach_args * const faa = aux; 184 1.1 jmcneill const int phandle = faa->faa_phandle; 185 1.1 jmcneill prop_dictionary_t dict = device_properties(self); 186 1.1 jmcneill static const struct genfb_ops zero_ops; 187 1.1 jmcneill struct genfb_ops ops = zero_ops; 188 1.1 jmcneill bus_addr_t addr[3]; 189 1.1 jmcneill bus_size_t size[3]; 190 1.1 jmcneill 191 1.1 jmcneill for (int i = 0; i < 3; i++) { 192 1.1 jmcneill if (fdtbus_get_reg(phandle, i, &addr[i], &size[i]) != 0) { 193 1.1 jmcneill aprint_error(": couldn't get register #%d\n", i); 194 1.1 jmcneill return; 195 1.1 jmcneill } 196 1.1 jmcneill } 197 1.1 jmcneill 198 1.1 jmcneill sc->sc_gen.sc_dev = self; 199 1.1 jmcneill sc->sc_bst = faa->faa_bst; 200 1.1 jmcneill sc->sc_dmat = faa->faa_dmat; 201 1.1 jmcneill if (bus_space_map(sc->sc_bst, addr[0], size[0], 0, &sc->sc_cav_bsh) != 0 || 202 1.1 jmcneill bus_space_map(sc->sc_bst, addr[1], size[1], 0, &sc->sc_hdmi_bsh) != 0 || 203 1.1 jmcneill bus_space_map(sc->sc_bst, addr[2], size[2], 0, &sc->sc_vpu_bsh) != 0) { 204 1.1 jmcneill aprint_error(": couldn't map registers\n"); 205 1.1 jmcneill return; 206 1.1 jmcneill } 207 1.1 jmcneill mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 208 1.1 jmcneill 209 1.1 jmcneill meson_genfb_init(sc); 210 1.1 jmcneill 211 1.1 jmcneill sc->sc_wstype = WSDISPLAY_TYPE_MESON; 212 1.1 jmcneill 213 1.1 jmcneill aprint_naive("\n"); 214 1.1 jmcneill aprint_normal("\n"); 215 1.1 jmcneill 216 1.1 jmcneill genfb_init(&sc->sc_gen); 217 1.1 jmcneill 218 1.1 jmcneill if (sc->sc_gen.sc_width == 0 || 219 1.1 jmcneill sc->sc_gen.sc_fbsize == 0) { 220 1.1 jmcneill aprint_normal_dev(self, "disabled\n"); 221 1.1 jmcneill return; 222 1.1 jmcneill } 223 1.1 jmcneill 224 1.1 jmcneill pmf_device_register1(self, NULL, NULL, meson_genfb_shutdown); 225 1.1 jmcneill 226 1.1 jmcneill #ifdef WSDISPLAY_MULTICONS 227 1.1 jmcneill const bool is_console = true; 228 1.1 jmcneill #else 229 1.1 jmcneill const bool is_console = phandle == meson_genfb_console_phandle; 230 1.1 jmcneill if (is_console) 231 1.1 jmcneill aprint_normal_dev(self, "switching to framebuffer console\n"); 232 1.1 jmcneill #endif 233 1.1 jmcneill prop_dictionary_set_bool(dict, "is_console", is_console); 234 1.1 jmcneill 235 1.1 jmcneill memset(&ops, 0, sizeof(ops)); 236 1.1 jmcneill ops.genfb_ioctl = meson_genfb_ioctl; 237 1.1 jmcneill ops.genfb_mmap = meson_genfb_mmap; 238 1.1 jmcneill 239 1.1 jmcneill genfb_attach(&sc->sc_gen, &ops); 240 1.1 jmcneill } 241 1.1 jmcneill 242 1.1 jmcneill static int 243 1.1 jmcneill meson_genfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, lwp_t *l) 244 1.1 jmcneill { 245 1.1 jmcneill struct meson_genfb_softc *sc = v; 246 1.1 jmcneill struct wsdisplayio_bus_id *busid; 247 1.1 jmcneill 248 1.1 jmcneill switch (cmd) { 249 1.1 jmcneill case WSDISPLAYIO_GTYPE: 250 1.1 jmcneill *(u_int *)data = sc->sc_wstype; 251 1.1 jmcneill return 0; 252 1.1 jmcneill case WSDISPLAYIO_GET_BUSID: 253 1.1 jmcneill busid = data; 254 1.1 jmcneill busid->bus_type = WSDISPLAYIO_BUS_SOC; 255 1.1 jmcneill return 0; 256 1.1 jmcneill case WSDISPLAYIO_GET_FBINFO: 257 1.1 jmcneill { 258 1.1 jmcneill struct wsdisplayio_fbinfo *fbi = data; 259 1.1 jmcneill struct rasops_info *ri = &sc->sc_gen.vd.active->scr_ri; 260 1.1 jmcneill int ret; 261 1.1 jmcneill 262 1.1 jmcneill ret = wsdisplayio_get_fbinfo(ri, fbi); 263 1.1 jmcneill fbi->fbi_flags |= WSFB_VRAM_IS_RAM; 264 1.1 jmcneill return ret; 265 1.1 jmcneill } 266 1.1 jmcneill default: 267 1.1 jmcneill return EPASSTHROUGH; 268 1.1 jmcneill } 269 1.1 jmcneill } 270 1.1 jmcneill 271 1.1 jmcneill static paddr_t 272 1.1 jmcneill meson_genfb_mmap(void *v, void *vs, off_t offset, int prot) 273 1.1 jmcneill { 274 1.1 jmcneill struct meson_genfb_softc *sc = v; 275 1.1 jmcneill 276 1.1 jmcneill if (offset < 0 || offset >= sc->sc_dmasegs[0].ds_len) 277 1.1 jmcneill return -1; 278 1.1 jmcneill 279 1.1 jmcneill return bus_dmamem_mmap(sc->sc_dmat, sc->sc_dmasegs, 1, 280 1.1 jmcneill offset, prot, BUS_DMA_PREFETCHABLE); 281 1.1 jmcneill } 282 1.1 jmcneill 283 1.1 jmcneill static bool 284 1.1 jmcneill meson_genfb_shutdown(device_t self, int flags) 285 1.1 jmcneill { 286 1.1 jmcneill genfb_enable_polling(self); 287 1.1 jmcneill return true; 288 1.1 jmcneill } 289 1.1 jmcneill 290 1.1 jmcneill static void 291 1.1 jmcneill meson_genfb_canvas_config(struct meson_genfb_softc *sc) 292 1.1 jmcneill { 293 1.1 jmcneill prop_dictionary_t cfg = device_properties(sc->sc_gen.sc_dev); 294 1.1 jmcneill const paddr_t pa = sc->sc_dmamap->dm_segs[0].ds_addr; 295 1.1 jmcneill uint32_t datal, datah, addr; 296 1.1 jmcneill u_int width, height, depth; 297 1.1 jmcneill 298 1.1 jmcneill prop_dictionary_get_uint32(cfg, "width", &width); 299 1.1 jmcneill prop_dictionary_get_uint32(cfg, "height", &height); 300 1.1 jmcneill prop_dictionary_get_uint32(cfg, "depth", &depth); 301 1.1 jmcneill 302 1.1 jmcneill const uint32_t w = (width * (depth/8)) >> 3; 303 1.1 jmcneill const uint32_t h = height; 304 1.1 jmcneill 305 1.1 jmcneill datal = CAV_READ(sc, DC_CAV_LUT_DATAL_REG); 306 1.1 jmcneill datah = CAV_READ(sc, DC_CAV_LUT_DATAH_REG); 307 1.1 jmcneill addr = CAV_READ(sc, DC_CAV_LUT_ADDR_REG); 308 1.1 jmcneill 309 1.1 jmcneill datal &= ~DC_CAV_LUT_DATAL_WIDTH_L; 310 1.1 jmcneill datal |= __SHIFTIN(w & 7, DC_CAV_LUT_DATAL_WIDTH_L); 311 1.1 jmcneill datal &= ~DC_CAV_LUT_DATAL_FBADDR; 312 1.1 jmcneill datal |= __SHIFTIN(pa >> 3, DC_CAV_LUT_DATAL_FBADDR); 313 1.1 jmcneill CAV_WRITE(sc, DC_CAV_LUT_DATAL_REG, datal); 314 1.1 jmcneill 315 1.1 jmcneill datah &= ~DC_CAV_LUT_DATAH_BLKMODE; 316 1.1 jmcneill datah |= __SHIFTIN(DC_CAV_LUT_DATAH_BLKMODE_LINEAR, 317 1.1 jmcneill DC_CAV_LUT_DATAH_BLKMODE); 318 1.1 jmcneill datah &= ~DC_CAV_LUT_DATAH_WIDTH_H; 319 1.1 jmcneill datah |= __SHIFTIN(w >> 3, DC_CAV_LUT_DATAH_WIDTH_H); 320 1.1 jmcneill datah &= ~DC_CAV_LUT_DATAH_HEIGHT; 321 1.1 jmcneill datah |= __SHIFTIN(h, DC_CAV_LUT_DATAH_HEIGHT); 322 1.1 jmcneill CAV_WRITE(sc, DC_CAV_LUT_DATAH_REG, datah); 323 1.1 jmcneill 324 1.1 jmcneill addr |= DC_CAV_LUT_ADDR_WR_EN; 325 1.1 jmcneill CAV_WRITE(sc, DC_CAV_LUT_ADDR_REG, addr); 326 1.1 jmcneill } 327 1.1 jmcneill 328 1.1 jmcneill static void 329 1.1 jmcneill meson_genfb_osd_config(struct meson_genfb_softc *sc) 330 1.1 jmcneill { 331 1.1 jmcneill prop_dictionary_t cfg = device_properties(sc->sc_gen.sc_dev); 332 1.1 jmcneill uint32_t cs, tc, w0, w1, w2, w3, w4; 333 1.1 jmcneill u_int width, height, depth; 334 1.1 jmcneill bool interlace_p; 335 1.1 jmcneill 336 1.1 jmcneill prop_dictionary_get_uint32(cfg, "width", &width); 337 1.1 jmcneill prop_dictionary_get_uint32(cfg, "height", &height); 338 1.1 jmcneill prop_dictionary_get_uint32(cfg, "depth", &depth); 339 1.1 jmcneill prop_dictionary_get_bool(cfg, "interlace", &interlace_p); 340 1.1 jmcneill 341 1.1 jmcneill cs = VPU_READ(sc, VIU_OSD2_CTRL_STAT_REG); 342 1.1 jmcneill cs |= VIU_OSD_CTRL_STAT_ENABLE; 343 1.1 jmcneill cs &= ~VIU_OSD_CTRL_STAT_GLOBAL_ALPHA; 344 1.1 jmcneill cs |= __SHIFTIN(0xff, VIU_OSD_CTRL_STAT_GLOBAL_ALPHA); 345 1.1 jmcneill cs |= VIU_OSD_CTRL_STAT_BLK0_ENABLE; 346 1.1 jmcneill cs &= ~VIU_OSD_CTRL_STAT_BLK1_ENABLE; 347 1.1 jmcneill cs &= ~VIU_OSD_CTRL_STAT_BLK2_ENABLE; 348 1.1 jmcneill cs &= ~VIU_OSD_CTRL_STAT_BLK3_ENABLE; 349 1.1 jmcneill VPU_WRITE(sc, VIU_OSD2_CTRL_STAT_REG, cs); 350 1.1 jmcneill 351 1.1 jmcneill tc = __SHIFTIN(0, VIU_OSD_TCOLOR_R) | 352 1.1 jmcneill __SHIFTIN(0, VIU_OSD_TCOLOR_G) | 353 1.1 jmcneill __SHIFTIN(0, VIU_OSD_TCOLOR_B) | 354 1.1 jmcneill __SHIFTIN(255, VIU_OSD_TCOLOR_A); 355 1.1 jmcneill VPU_WRITE(sc, VIU_OSD2_TCOLOR_AG0_REG, tc); 356 1.1 jmcneill 357 1.1 jmcneill w0 = VPU_READ(sc, VIU_OSD2_BLK0_CFG_W0_REG); 358 1.1 jmcneill w0 |= VIU_OSD_BLK_CFG_W0_RGB_EN; 359 1.1 jmcneill w0 &= ~VIU_OSD_BLK_CFG_W0_TC_ALPHA_EN; 360 1.1 jmcneill w0 &= ~VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE; 361 1.1 jmcneill w0 &= ~VIU_OSD_BLK_CFG_W0_COLOR_MATRIX; 362 1.1 jmcneill switch (depth) { 363 1.1 jmcneill case 32: 364 1.1 jmcneill w0 |= __SHIFTIN(VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE_32BPP, 365 1.1 jmcneill VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE); 366 1.1 jmcneill w0 |= __SHIFTIN(VIU_OSD_BLK_CFG_W0_COLOR_MATRIX_ARGB, 367 1.1 jmcneill VIU_OSD_BLK_CFG_W0_COLOR_MATRIX); 368 1.1 jmcneill break; 369 1.1 jmcneill case 24: 370 1.1 jmcneill w0 |= __SHIFTIN(VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE_24BPP, 371 1.1 jmcneill VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE); 372 1.1 jmcneill w0 |= __SHIFTIN(VIU_OSD_BLK_CFG_W0_COLOR_MATRIX_RGB, 373 1.1 jmcneill VIU_OSD_BLK_CFG_W0_COLOR_MATRIX); 374 1.1 jmcneill break; 375 1.1 jmcneill case 16: 376 1.1 jmcneill w0 |= __SHIFTIN(VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE_16BPP, 377 1.1 jmcneill VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE); 378 1.1 jmcneill w0 |= __SHIFTIN(VIU_OSD_BLK_CFG_W0_COLOR_MATRIX_RGB565, 379 1.1 jmcneill VIU_OSD_BLK_CFG_W0_COLOR_MATRIX); 380 1.1 jmcneill break; 381 1.1 jmcneill } 382 1.1 jmcneill w0 |= VIU_OSD_BLK_CFG_W0_LITTLE_ENDIAN; 383 1.1 jmcneill w0 &= ~VIU_OSD_BLK_CFG_W0_RPT_Y; 384 1.1 jmcneill w0 &= ~VIU_OSD_BLK_CFG_W0_INTERP_CTRL; 385 1.1 jmcneill if (interlace_p) { 386 1.1 jmcneill w0 |= VIU_OSD_BLK_CFG_W0_INTERLACE_EN; 387 1.1 jmcneill } else { 388 1.1 jmcneill w0 &= ~VIU_OSD_BLK_CFG_W0_INTERLACE_EN; 389 1.1 jmcneill } 390 1.1 jmcneill VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W0_REG, w0); 391 1.1 jmcneill 392 1.1 jmcneill w1 = __SHIFTIN(width - 1, VIU_OSD_BLK_CFG_W1_X_END) | 393 1.1 jmcneill __SHIFTIN(0, VIU_OSD_BLK_CFG_W1_X_START); 394 1.1 jmcneill w2 = __SHIFTIN(height - 1, VIU_OSD_BLK_CFG_W2_Y_END) | 395 1.1 jmcneill __SHIFTIN(0, VIU_OSD_BLK_CFG_W2_Y_START); 396 1.1 jmcneill w3 = __SHIFTIN(width - 1, VIU_OSD_BLK_CFG_W3_H_END) | 397 1.1 jmcneill __SHIFTIN(0, VIU_OSD_BLK_CFG_W3_H_START); 398 1.1 jmcneill w4 = __SHIFTIN(height - 1, VIU_OSD_BLK_CFG_W4_V_END) | 399 1.1 jmcneill __SHIFTIN(0, VIU_OSD_BLK_CFG_W4_V_START); 400 1.1 jmcneill 401 1.1 jmcneill VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W1_REG, w1); 402 1.1 jmcneill VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W2_REG, w2); 403 1.1 jmcneill VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W3_REG, w3); 404 1.1 jmcneill VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W4_REG, w4); 405 1.1 jmcneill } 406 1.1 jmcneill 407 1.1 jmcneill static void 408 1.1 jmcneill meson_genfb_scaler_config(struct meson_genfb_softc *sc) 409 1.1 jmcneill { 410 1.1 jmcneill prop_dictionary_t cfg = device_properties(sc->sc_gen.sc_dev); 411 1.1 jmcneill uint32_t scctl, sci_wh, sco_h, sco_v, hsc, vsc, hps, vps, hip, vip; 412 1.1 jmcneill u_int width, height; 413 1.1 jmcneill bool interlace_p; 414 1.1 jmcneill 415 1.1 jmcneill prop_dictionary_get_uint32(cfg, "width", &width); 416 1.1 jmcneill prop_dictionary_get_uint32(cfg, "height", &height); 417 1.1 jmcneill prop_dictionary_get_bool(cfg, "interlace", &interlace_p); 418 1.1 jmcneill 419 1.1 jmcneill const u_int scale = sc->sc_scale; 420 1.1 jmcneill const u_int dst_w = (width * scale) / 100; 421 1.1 jmcneill const u_int dst_h = (height * scale) / 100; 422 1.1 jmcneill const u_int margin_w = (width - dst_w) / 2; 423 1.1 jmcneill const u_int margin_h = (height - dst_h) / 2; 424 1.1 jmcneill const bool scale_p = scale != 100; 425 1.1 jmcneill 426 1.1 jmcneill VPU_WRITE(sc, VPP_OSD_SC_DUMMY_DATA_REG, 0x00808000); 427 1.1 jmcneill 428 1.1 jmcneill scctl = VPU_READ(sc, VPP_OSD_SC_CTRL0_REG); 429 1.1 jmcneill scctl |= VPP_OSD_SC_CTRL0_OSD_SC_PATH_EN; 430 1.1 jmcneill scctl &= ~VPP_OSD_SC_CTRL0_OSD_SC_SEL; 431 1.1 jmcneill scctl |= __SHIFTIN(1, VPP_OSD_SC_CTRL0_OSD_SC_SEL); /* OSD2 */ 432 1.1 jmcneill scctl &= ~VPP_OSD_SC_CTRL0_DEFAULT_ALPHA; 433 1.1 jmcneill scctl |= __SHIFTIN(0, VPP_OSD_SC_CTRL0_DEFAULT_ALPHA); 434 1.1 jmcneill VPU_WRITE(sc, VPP_OSD_SC_CTRL0_REG, scctl); 435 1.1 jmcneill 436 1.1 jmcneill sci_wh = __SHIFTIN(width - 1, VPP_OSD_SCI_WH_M1_WIDTH) | 437 1.1 jmcneill __SHIFTIN((height >> interlace_p) - 1, VPP_OSD_SCI_WH_M1_HEIGHT); 438 1.1 jmcneill sco_h = __SHIFTIN(margin_w, VPP_OSD_SCO_H_START) | 439 1.1 jmcneill __SHIFTIN(width - margin_w - 1, VPP_OSD_SCO_H_END); 440 1.1 jmcneill sco_v = __SHIFTIN(margin_h >> interlace_p, VPP_OSD_SCO_V_START) | 441 1.1 jmcneill __SHIFTIN(((height - margin_h) >> interlace_p) - 1, 442 1.1 jmcneill VPP_OSD_SCO_V_END); 443 1.1 jmcneill 444 1.1 jmcneill VPU_WRITE(sc, VPP_OSD_SCI_WH_M1_REG, sci_wh); 445 1.1 jmcneill VPU_WRITE(sc, VPP_OSD_SCO_H_REG, sco_h); 446 1.1 jmcneill VPU_WRITE(sc, VPP_OSD_SCO_V_REG, sco_v); 447 1.1 jmcneill 448 1.1 jmcneill /* horizontal scaling */ 449 1.1 jmcneill hsc = VPU_READ(sc, VPP_OSD_HSC_CTRL0_REG); 450 1.1 jmcneill if (scale_p) { 451 1.1 jmcneill hsc &= ~VPP_OSD_HSC_CTRL0_BANK_LENGTH; 452 1.1 jmcneill hsc |= __SHIFTIN(4, VPP_OSD_HSC_CTRL0_BANK_LENGTH); 453 1.1 jmcneill hsc &= ~VPP_OSD_HSC_CTRL0_INI_RCV_NUM0; 454 1.1 jmcneill hsc |= __SHIFTIN(4, VPP_OSD_HSC_CTRL0_INI_RCV_NUM0); 455 1.1 jmcneill hsc &= ~VPP_OSD_HSC_CTRL0_RPT_P0_NUM0; 456 1.1 jmcneill hsc |= __SHIFTIN(1, VPP_OSD_HSC_CTRL0_RPT_P0_NUM0); 457 1.1 jmcneill hsc |= VPP_OSD_HSC_CTRL0_HSCALE_EN; 458 1.1 jmcneill } else { 459 1.1 jmcneill hsc &= ~VPP_OSD_HSC_CTRL0_HSCALE_EN; 460 1.1 jmcneill } 461 1.1 jmcneill VPU_WRITE(sc, VPP_OSD_HSC_CTRL0_REG, hsc); 462 1.1 jmcneill 463 1.1 jmcneill /* vertical scaling */ 464 1.1 jmcneill vsc = VPU_READ(sc, VPP_OSD_VSC_CTRL0_REG); 465 1.1 jmcneill if (scale_p) { 466 1.1 jmcneill vsc &= ~VPP_OSD_VSC_CTRL0_BANK_LENGTH; 467 1.1 jmcneill vsc |= __SHIFTIN(4, VPP_OSD_VSC_CTRL0_BANK_LENGTH); 468 1.1 jmcneill vsc &= ~VPP_OSD_VSC_CTRL0_TOP_INI_RCV_NUM0; 469 1.1 jmcneill vsc |= __SHIFTIN(4, VPP_OSD_VSC_CTRL0_TOP_INI_RCV_NUM0); 470 1.1 jmcneill vsc &= ~VPP_OSD_VSC_CTRL0_TOP_RPT_P0_NUM0; 471 1.1 jmcneill vsc |= __SHIFTIN(1, VPP_OSD_VSC_CTRL0_TOP_RPT_P0_NUM0); 472 1.1 jmcneill vsc &= ~VPP_OSD_VSC_CTRL0_BOT_INI_RCV_NUM0; 473 1.1 jmcneill vsc &= ~VPP_OSD_VSC_CTRL0_BOT_RPT_P0_NUM0; 474 1.1 jmcneill vsc &= ~VPP_OSC_VSC_CTRL0_INTERLACE; 475 1.1 jmcneill if (interlace_p) { 476 1.1 jmcneill /* interlace */ 477 1.1 jmcneill vsc |= VPP_OSC_VSC_CTRL0_INTERLACE; 478 1.1 jmcneill vsc |= __SHIFTIN(6, VPP_OSD_VSC_CTRL0_BOT_INI_RCV_NUM0); 479 1.1 jmcneill vsc |= __SHIFTIN(2, VPP_OSD_VSC_CTRL0_BOT_RPT_P0_NUM0); 480 1.1 jmcneill } 481 1.1 jmcneill vsc |= VPP_OSD_VSC_CTRL0_VSCALE_EN; 482 1.1 jmcneill } else { 483 1.1 jmcneill vsc &= ~VPP_OSD_VSC_CTRL0_VSCALE_EN; 484 1.1 jmcneill } 485 1.1 jmcneill VPU_WRITE(sc, VPP_OSD_VSC_CTRL0_REG, vsc); 486 1.1 jmcneill 487 1.1 jmcneill /* free scale enable */ 488 1.1 jmcneill if (scale_p) { 489 1.1 jmcneill const u_int hf_phase_step = ((width << 18) / dst_w) << 6; 490 1.1 jmcneill const u_int vf_phase_step = ((height << 20) / dst_h) << 4; 491 1.1 jmcneill const u_int bot_ini_phase = 492 1.1 jmcneill interlace_p ? ((vf_phase_step / 2) >> 8) : 0; 493 1.1 jmcneill 494 1.1 jmcneill hps = VPU_READ(sc, VPP_OSD_HSC_PHASE_STEP_REG); 495 1.1 jmcneill hps &= ~VPP_OSD_HSC_PHASE_STEP_FORMAT; 496 1.1 jmcneill hps |= __SHIFTIN(hf_phase_step, VPP_OSD_HSC_PHASE_STEP_FORMAT); 497 1.1 jmcneill VPU_WRITE(sc, VPP_OSD_HSC_PHASE_STEP_REG, hps); 498 1.1 jmcneill 499 1.1 jmcneill hip = VPU_READ(sc, VPP_OSD_HSC_INI_PHASE_REG); 500 1.1 jmcneill hip &= ~VPP_OSD_HSC_INI_PHASE_1; 501 1.1 jmcneill VPU_WRITE(sc, VPP_OSD_HSC_INI_PHASE_REG, hip); 502 1.1 jmcneill 503 1.1 jmcneill vps = VPU_READ(sc, VPP_OSD_VSC_PHASE_STEP_REG); 504 1.1 jmcneill vps &= ~VPP_OSD_VSC_PHASE_STEP_FORMAT; 505 1.1 jmcneill vps |= __SHIFTIN(hf_phase_step, VPP_OSD_VSC_PHASE_STEP_FORMAT); 506 1.1 jmcneill VPU_WRITE(sc, VPP_OSD_VSC_PHASE_STEP_REG, vps); 507 1.1 jmcneill 508 1.1 jmcneill vip = VPU_READ(sc, VPP_OSD_VSC_INI_PHASE_REG); 509 1.1 jmcneill vip &= ~VPP_OSD_VSC_INI_PHASE_1; 510 1.1 jmcneill vip |= __SHIFTIN(0, VPP_OSD_VSC_INI_PHASE_1); 511 1.1 jmcneill vip &= ~VPP_OSD_VSC_INI_PHASE_0; 512 1.1 jmcneill vip |= __SHIFTIN(bot_ini_phase, VPP_OSD_VSC_INI_PHASE_0); 513 1.1 jmcneill VPU_WRITE(sc, VPP_OSD_VSC_INI_PHASE_REG, vip); 514 1.1 jmcneill } 515 1.1 jmcneill } 516 1.1 jmcneill 517 1.1 jmcneill static void 518 1.1 jmcneill meson_genfb_init(struct meson_genfb_softc *sc) 519 1.1 jmcneill { 520 1.1 jmcneill prop_dictionary_t cfg = device_properties(sc->sc_gen.sc_dev); 521 1.1 jmcneill const struct sysctlnode *node, *devnode; 522 1.1 jmcneill u_int width = 0, height = 0, depth, flags, i, scale = 100; 523 1.1 jmcneill int error; 524 1.1 jmcneill 525 1.1 jmcneill /* 526 1.1 jmcneill * Firmware has (maybe) setup HDMI TX for us. Read the VIC from 527 1.1 jmcneill * the HDMI AVI InfoFrame (bits 6:0 in PB4) and map that to a 528 1.1 jmcneill * framebuffer geometry. 529 1.1 jmcneill */ 530 1.1 jmcneill const uint32_t vic = HDMI_READ(sc, HDMITX_AVI_INFO_ADDR + 4) & 0x7f; 531 1.1 jmcneill for (i = 0; i < __arraycount(meson_genfb_modes); i++) { 532 1.1 jmcneill if (meson_genfb_modes[i].vic == vic) { 533 1.1 jmcneill aprint_debug(" [HDMI VIC %d]", vic); 534 1.1 jmcneill width = meson_genfb_modes[i].width; 535 1.1 jmcneill height = meson_genfb_modes[i].height; 536 1.1 jmcneill flags = meson_genfb_modes[i].flags; 537 1.1 jmcneill break; 538 1.1 jmcneill } 539 1.1 jmcneill } 540 1.1 jmcneill if (width == 0 || height == 0) { 541 1.1 jmcneill aprint_error(" [UNSUPPORTED HDMI VIC %d]", vic); 542 1.1 jmcneill return; 543 1.1 jmcneill } 544 1.1 jmcneill 545 1.1 jmcneill depth = AMLOGIC_GENFB_DEFAULT_DEPTH; 546 1.1 jmcneill prop_dictionary_get_uint32(cfg, "depth", &depth); 547 1.1 jmcneill switch (depth) { 548 1.1 jmcneill case 16: 549 1.1 jmcneill case 24: 550 1.1 jmcneill break; 551 1.1 jmcneill default: 552 1.1 jmcneill aprint_error_dev(sc->sc_gen.sc_dev, 553 1.1 jmcneill "unsupported depth %d, using %d\n", depth, 554 1.1 jmcneill AMLOGIC_GENFB_DEFAULT_DEPTH); 555 1.1 jmcneill depth = AMLOGIC_GENFB_DEFAULT_DEPTH; 556 1.1 jmcneill break; 557 1.1 jmcneill } 558 1.1 jmcneill prop_dictionary_set_uint8(cfg, "depth", depth); 559 1.1 jmcneill 560 1.1 jmcneill const uint32_t fbsize = width * height * (depth / 8); 561 1.1 jmcneill sc->sc_dmasize = (fbsize + 3) & ~3; 562 1.1 jmcneill 563 1.1 jmcneill error = meson_genfb_alloc_videomem(sc); 564 1.1 jmcneill if (error) { 565 1.1 jmcneill aprint_error_dev(sc->sc_gen.sc_dev, 566 1.1 jmcneill "failed to allocate %u bytes of video memory: %d\n", 567 1.1 jmcneill (u_int)sc->sc_dmasize, error); 568 1.1 jmcneill return; 569 1.1 jmcneill } 570 1.1 jmcneill 571 1.1 jmcneill prop_dictionary_get_uint32(cfg, "scale", &scale); 572 1.1 jmcneill if (scale > 100) { 573 1.1 jmcneill scale = 100; 574 1.1 jmcneill } else if (scale < 10) { 575 1.1 jmcneill scale = 10; 576 1.1 jmcneill } 577 1.1 jmcneill sc->sc_scale = scale; 578 1.1 jmcneill 579 1.1 jmcneill prop_dictionary_set_uint32(cfg, "width", width); 580 1.1 jmcneill prop_dictionary_set_uint32(cfg, "height", height); 581 1.1 jmcneill prop_dictionary_set_bool(cfg, "dblscan", !!(flags & DBLSCAN)); 582 1.1 jmcneill prop_dictionary_set_bool(cfg, "interlace", !!(flags & INTERLACE)); 583 1.1 jmcneill prop_dictionary_set_uint16(cfg, "linebytes", width * (depth / 8)); 584 1.1 jmcneill prop_dictionary_set_uint32(cfg, "address", 0); 585 1.1 jmcneill prop_dictionary_set_uint32(cfg, "virtual_address", 586 1.1 jmcneill (uintptr_t)sc->sc_dmap); 587 1.1 jmcneill 588 1.1 jmcneill meson_genfb_canvas_config(sc); 589 1.1 jmcneill meson_genfb_osd_config(sc); 590 1.1 jmcneill meson_genfb_scaler_config(sc); 591 1.1 jmcneill 592 1.1 jmcneill /* sysctl setup */ 593 1.1 jmcneill error = sysctl_createv(&sc->sc_sysctllog, 0, NULL, &node, 594 1.1 jmcneill CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL, 595 1.1 jmcneill NULL, 0, NULL, 0, CTL_HW, CTL_EOL); 596 1.1 jmcneill if (error) 597 1.1 jmcneill goto sysctl_failed; 598 1.1 jmcneill error = sysctl_createv(&sc->sc_sysctllog, 0, &node, &devnode, 599 1.1 jmcneill 0, CTLTYPE_NODE, device_xname(sc->sc_gen.sc_dev), NULL, 600 1.1 jmcneill NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 601 1.1 jmcneill if (error) 602 1.1 jmcneill goto sysctl_failed; 603 1.1 jmcneill error = sysctl_createv(&sc->sc_sysctllog, 0, &devnode, &node, 604 1.1 jmcneill CTLFLAG_READWRITE, CTLTYPE_INT, "scale", NULL, 605 1.1 jmcneill meson_genfb_scale_helper, 0, (void *)sc, 0, 606 1.1 jmcneill CTL_CREATE, CTL_EOL); 607 1.1 jmcneill if (error) 608 1.1 jmcneill goto sysctl_failed; 609 1.1 jmcneill sc->sc_node_scale = node->sysctl_num; 610 1.1 jmcneill 611 1.1 jmcneill return; 612 1.1 jmcneill 613 1.1 jmcneill sysctl_failed: 614 1.1 jmcneill aprint_error_dev(sc->sc_gen.sc_dev, 615 1.1 jmcneill "couldn't create sysctl nodes (%d)\n", error); 616 1.1 jmcneill sysctl_teardown(&sc->sc_sysctllog); 617 1.1 jmcneill } 618 1.1 jmcneill 619 1.1 jmcneill static int 620 1.1 jmcneill meson_genfb_scale_helper(SYSCTLFN_ARGS) 621 1.1 jmcneill { 622 1.1 jmcneill struct meson_genfb_softc *sc; 623 1.1 jmcneill struct sysctlnode node; 624 1.1 jmcneill int scale, oldscale, error; 625 1.1 jmcneill 626 1.1 jmcneill node = *rnode; 627 1.1 jmcneill sc = node.sysctl_data; 628 1.1 jmcneill scale = oldscale = sc->sc_scale; 629 1.1 jmcneill node.sysctl_data = &scale; 630 1.1 jmcneill error = sysctl_lookup(SYSCTLFN_CALL(&node)); 631 1.1 jmcneill if (error || newp == NULL) 632 1.1 jmcneill return error; 633 1.1 jmcneill 634 1.1 jmcneill if (scale > 100) { 635 1.1 jmcneill scale = 100; 636 1.1 jmcneill } else if (scale < 10) { 637 1.1 jmcneill scale = 10; 638 1.1 jmcneill } 639 1.1 jmcneill 640 1.1 jmcneill if (scale == oldscale) { 641 1.1 jmcneill return 0; 642 1.1 jmcneill } 643 1.1 jmcneill 644 1.1 jmcneill mutex_enter(&sc->sc_lock); 645 1.1 jmcneill sc->sc_scale = scale; 646 1.1 jmcneill meson_genfb_scaler_config(sc); 647 1.1 jmcneill mutex_exit(&sc->sc_lock); 648 1.1 jmcneill 649 1.1 jmcneill return 0; 650 1.1 jmcneill } 651 1.1 jmcneill 652 1.1 jmcneill static int 653 1.1 jmcneill meson_genfb_alloc_videomem(struct meson_genfb_softc *sc) 654 1.1 jmcneill { 655 1.1 jmcneill int error, nsegs; 656 1.1 jmcneill 657 1.1 jmcneill error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dmasize, 0x1000, 0, 658 1.1 jmcneill sc->sc_dmasegs, 1, &nsegs, BUS_DMA_WAITOK); 659 1.1 jmcneill if (error) 660 1.1 jmcneill return error; 661 1.1 jmcneill error = bus_dmamem_map(sc->sc_dmat, sc->sc_dmasegs, nsegs, 662 1.1 jmcneill sc->sc_dmasize, &sc->sc_dmap, BUS_DMA_WAITOK | BUS_DMA_COHERENT); 663 1.1 jmcneill if (error) 664 1.1 jmcneill goto free; 665 1.1 jmcneill error = bus_dmamap_create(sc->sc_dmat, sc->sc_dmasize, 1, 666 1.1 jmcneill sc->sc_dmasize, 0, BUS_DMA_WAITOK, &sc->sc_dmamap); 667 1.1 jmcneill if (error) 668 1.1 jmcneill goto unmap; 669 1.1 jmcneill error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_dmap, 670 1.1 jmcneill sc->sc_dmasize, NULL, BUS_DMA_WAITOK); 671 1.1 jmcneill if (error) 672 1.1 jmcneill goto destroy; 673 1.1 jmcneill 674 1.1 jmcneill memset(sc->sc_dmap, 0, sc->sc_dmasize); 675 1.1 jmcneill 676 1.1 jmcneill return 0; 677 1.1 jmcneill 678 1.1 jmcneill destroy: 679 1.1 jmcneill bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); 680 1.1 jmcneill unmap: 681 1.1 jmcneill bus_dmamem_unmap(sc->sc_dmat, sc->sc_dmap, sc->sc_dmasize); 682 1.1 jmcneill free: 683 1.1 jmcneill bus_dmamem_free(sc->sc_dmat, sc->sc_dmasegs, nsegs); 684 1.1 jmcneill 685 1.1 jmcneill sc->sc_dmasize = 0; 686 1.1 jmcneill sc->sc_dmap = NULL; 687 1.1 jmcneill 688 1.1 jmcneill return error; 689 1.1 jmcneill } 690 1.1 jmcneill 691 1.1 jmcneill void 692 1.1 jmcneill meson_genfb_set_console_dev(device_t dev) 693 1.1 jmcneill { 694 1.1 jmcneill KASSERT(meson_genfb_console_dev == NULL); 695 1.1 jmcneill meson_genfb_console_dev = dev; 696 1.1 jmcneill } 697 1.1 jmcneill 698 1.1 jmcneill void 699 1.1 jmcneill meson_genfb_ddb_trap_callback(int where) 700 1.1 jmcneill { 701 1.1 jmcneill if (meson_genfb_console_dev == NULL) 702 1.1 jmcneill return; 703 1.1 jmcneill 704 1.1 jmcneill if (where) { 705 1.1 jmcneill genfb_enable_polling(meson_genfb_console_dev); 706 1.1 jmcneill } else { 707 1.1 jmcneill genfb_disable_polling(meson_genfb_console_dev); 708 1.1 jmcneill } 709 1.1 jmcneill } 710 1.1 jmcneill 711 1.1 jmcneill static int 712 1.1 jmcneill meson_genfb_console_match(int phandle) 713 1.1 jmcneill { 714 1.2 thorpej return of_compatible_match(phandle, compat_data); 715 1.1 jmcneill } 716 1.1 jmcneill 717 1.1 jmcneill static void 718 1.1 jmcneill meson_genfb_console_consinit(struct fdt_attach_args *faa, u_int uart_freq) 719 1.1 jmcneill { 720 1.1 jmcneill meson_genfb_console_phandle = faa->faa_phandle; 721 1.1 jmcneill genfb_cnattach(); 722 1.1 jmcneill } 723 1.1 jmcneill 724 1.1 jmcneill static const struct fdt_console meson_genfb_fdt_console = { 725 1.1 jmcneill .match = meson_genfb_console_match, 726 1.1 jmcneill .consinit = meson_genfb_console_consinit, 727 1.1 jmcneill }; 728 1.1 jmcneill 729 1.1 jmcneill FDT_CONSOLE(meson_genfb, &meson_genfb_fdt_console); 730