1 1.16 riastrad /* $NetBSD: drmfb.c,v 1.16 2022/09/01 17:54:47 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /*- 4 1.1 riastrad * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 1.1 riastrad * All rights reserved. 6 1.1 riastrad * 7 1.1 riastrad * This code is derived from software contributed to The NetBSD Foundation 8 1.1 riastrad * by Taylor R. Campbell. 9 1.1 riastrad * 10 1.1 riastrad * Redistribution and use in source and binary forms, with or without 11 1.1 riastrad * modification, are permitted provided that the following conditions 12 1.1 riastrad * are met: 13 1.1 riastrad * 1. Redistributions of source code must retain the above copyright 14 1.1 riastrad * notice, this list of conditions and the following disclaimer. 15 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 riastrad * notice, this list of conditions and the following disclaimer in the 17 1.1 riastrad * documentation and/or other materials provided with the distribution. 18 1.1 riastrad * 19 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE. 30 1.1 riastrad */ 31 1.1 riastrad 32 1.1 riastrad /* 33 1.1 riastrad * drmfb: wsdisplay support, via genfb, for any drm device. Use this 34 1.1 riastrad * if you're too lazy to write a hardware-accelerated framebuffer using 35 1.1 riastrad * wsdisplay directly. 36 1.1 riastrad * 37 1.1 riastrad * This doesn't actually do anything interesting -- just hooks up 38 1.1 riastrad * drmkms crap and genfb crap. 39 1.1 riastrad */ 40 1.1 riastrad 41 1.1 riastrad #include <sys/cdefs.h> 42 1.16 riastrad __KERNEL_RCSID(0, "$NetBSD: drmfb.c,v 1.16 2022/09/01 17:54:47 riastradh Exp $"); 43 1.1 riastrad 44 1.1 riastrad #ifdef _KERNEL_OPT 45 1.1 riastrad #include "vga.h" 46 1.1 riastrad #endif 47 1.1 riastrad 48 1.1 riastrad #include <sys/types.h> 49 1.1 riastrad #include <sys/param.h> 50 1.1 riastrad #include <sys/bus.h> 51 1.1 riastrad #include <sys/device.h> 52 1.1 riastrad #include <sys/kauth.h> 53 1.1 riastrad 54 1.1 riastrad #if NVGA > 0 55 1.1 riastrad /* 56 1.1 riastrad * XXX All we really need is vga_is_console from vgavar.h, but the 57 1.1 riastrad * header files are missing their own dependencies, so we need to 58 1.1 riastrad * explicitly drag in the other crap. 59 1.1 riastrad */ 60 1.1 riastrad #include <dev/ic/mc6845reg.h> 61 1.1 riastrad #include <dev/ic/pcdisplayvar.h> 62 1.1 riastrad #include <dev/ic/vgareg.h> 63 1.1 riastrad #include <dev/ic/vgavar.h> 64 1.1 riastrad #endif 65 1.1 riastrad 66 1.1 riastrad #include <dev/wsfb/genfbvar.h> 67 1.1 riastrad 68 1.10 riastrad #include <drm/drm_device.h> 69 1.1 riastrad #include <drm/drm_fb_helper.h> 70 1.1 riastrad #include <drm/drmfb.h> 71 1.1 riastrad 72 1.1 riastrad static int drmfb_genfb_ioctl(void *, void *, unsigned long, void *, int, 73 1.1 riastrad struct lwp *); 74 1.1 riastrad static paddr_t drmfb_genfb_mmap(void *, void *, off_t, int); 75 1.1 riastrad static int drmfb_genfb_enable_polling(void *); 76 1.1 riastrad static int drmfb_genfb_disable_polling(void *); 77 1.1 riastrad static bool drmfb_genfb_setmode(struct genfb_softc *, int); 78 1.1 riastrad 79 1.1 riastrad static const struct genfb_mode_callback drmfb_genfb_mode_callback = { 80 1.1 riastrad .gmc_setmode = drmfb_genfb_setmode, 81 1.1 riastrad }; 82 1.1 riastrad 83 1.1 riastrad int 84 1.1 riastrad drmfb_attach(struct drmfb_softc *sc, const struct drmfb_attach_args *da) 85 1.1 riastrad { 86 1.1 riastrad const struct drm_fb_helper_surface_size *const sizes = da->da_fb_sizes; 87 1.9 riastrad struct drm_connector_list_iter conn_iter; 88 1.9 riastrad struct drm_connector *connector; 89 1.1 riastrad const prop_dictionary_t dict = device_properties(da->da_dev); 90 1.15 riastrad const device_t parent = device_parent(da->da_dev); 91 1.15 riastrad const prop_dictionary_t pdict = device_properties(parent); 92 1.1 riastrad #if NVGA > 0 93 1.1 riastrad struct drm_device *const dev = da->da_fb_helper->dev; 94 1.1 riastrad #endif 95 1.1 riastrad static const struct genfb_ops zero_genfb_ops; 96 1.1 riastrad struct genfb_ops genfb_ops = zero_genfb_ops; 97 1.2 jmcneill bool is_console; 98 1.16 riastrad int error __diagused; 99 1.1 riastrad 100 1.1 riastrad /* genfb requires this. */ 101 1.1 riastrad KASSERTMSG((void *)&sc->sc_genfb == device_private(da->da_dev), 102 1.1 riastrad "drmfb_softc must be first member of device softc"); 103 1.1 riastrad 104 1.1 riastrad sc->sc_da = *da; 105 1.1 riastrad 106 1.1 riastrad prop_dictionary_set_uint32(dict, "width", sizes->surface_width); 107 1.1 riastrad prop_dictionary_set_uint32(dict, "height", sizes->surface_height); 108 1.1 riastrad prop_dictionary_set_uint8(dict, "depth", sizes->surface_bpp); 109 1.3 maya prop_dictionary_set_uint16(dict, "linebytes", da->da_fb_linebytes); 110 1.1 riastrad prop_dictionary_set_uint32(dict, "address", 0); /* XXX >32-bit */ 111 1.1 riastrad CTASSERT(sizeof(uintptr_t) <= sizeof(uint64_t)); 112 1.1 riastrad prop_dictionary_set_uint64(dict, "virtual_address", 113 1.1 riastrad (uint64_t)(uintptr_t)da->da_fb_vaddr); 114 1.1 riastrad 115 1.1 riastrad prop_dictionary_set_uint64(dict, "mode_callback", 116 1.1 riastrad (uint64_t)(uintptr_t)&drmfb_genfb_mode_callback); 117 1.1 riastrad 118 1.16 riastrad /* 119 1.16 riastrad * Determine whether MD firmware logic has set the console to 120 1.16 riastrad * go through this device. 121 1.16 riastrad */ 122 1.15 riastrad if (prop_dictionary_get_bool(pdict, "is_console", &is_console)) { 123 1.16 riastrad /* nothing */ 124 1.16 riastrad } else if (genfb_is_console() && genfb_is_enabled()) { 125 1.16 riastrad is_console = true; 126 1.15 riastrad } else { 127 1.16 riastrad is_console = false; 128 1.16 riastrad } 129 1.16 riastrad 130 1.1 riastrad #if NVGA > 0 131 1.16 riastrad /* 132 1.16 riastrad * Whether or not we were told to be the console, if the 133 1.16 riastrad * console was configured to go through a vga resource that we 134 1.16 riastrad * now own and that vga(4) is not going to take over, kick out 135 1.16 riastrad * the vga console before we take over as genfb console. 136 1.16 riastrad */ 137 1.16 riastrad if ((da->da_params->dp_is_vga_console != NULL) && 138 1.16 riastrad (*da->da_params->dp_is_vga_console)(dev)) { 139 1.16 riastrad vga_cndetach(); 140 1.16 riastrad if (da->da_params->dp_disable_vga) 141 1.16 riastrad (*da->da_params->dp_disable_vga)(dev); 142 1.16 riastrad is_console = true; 143 1.16 riastrad } 144 1.1 riastrad #endif 145 1.16 riastrad 146 1.16 riastrad prop_dictionary_set_bool(dict, "is_console", is_console); 147 1.1 riastrad 148 1.5 jmcneill /* Make the first EDID we find available to wsfb */ 149 1.9 riastrad drm_connector_list_iter_begin(da->da_fb_helper->dev, &conn_iter); 150 1.9 riastrad drm_client_for_each_connector_iter(connector, &conn_iter) { 151 1.5 jmcneill struct drm_property_blob *edid = connector->edid_blob_ptr; 152 1.7 jmcneill if (edid && edid->length) { 153 1.8 jmcneill prop_dictionary_set_data(dict, "EDID", edid->data, 154 1.8 jmcneill edid->length); 155 1.5 jmcneill break; 156 1.5 jmcneill } 157 1.5 jmcneill } 158 1.9 riastrad drm_connector_list_iter_end(&conn_iter); 159 1.5 jmcneill 160 1.1 riastrad sc->sc_genfb.sc_dev = sc->sc_da.da_dev; 161 1.1 riastrad genfb_init(&sc->sc_genfb); 162 1.1 riastrad genfb_ops.genfb_ioctl = drmfb_genfb_ioctl; 163 1.1 riastrad genfb_ops.genfb_mmap = drmfb_genfb_mmap; 164 1.1 riastrad genfb_ops.genfb_enable_polling = drmfb_genfb_enable_polling; 165 1.1 riastrad genfb_ops.genfb_disable_polling = drmfb_genfb_disable_polling; 166 1.1 riastrad 167 1.12 chs KERNEL_LOCK(1, NULL); 168 1.1 riastrad error = genfb_attach(&sc->sc_genfb, &genfb_ops); 169 1.12 chs KERNEL_UNLOCK_ONE(NULL); 170 1.16 riastrad KASSERTMSG(error == 0, "genfb_attach failed, error=%d", error); 171 1.1 riastrad 172 1.1 riastrad /* Success! */ 173 1.1 riastrad return 0; 174 1.1 riastrad } 175 1.1 riastrad 176 1.1 riastrad int 177 1.1 riastrad drmfb_detach(struct drmfb_softc *sc, int flags) 178 1.1 riastrad { 179 1.1 riastrad 180 1.1 riastrad /* XXX genfb detach? */ 181 1.1 riastrad return 0; 182 1.1 riastrad } 183 1.1 riastrad 184 1.1 riastrad static int 185 1.1 riastrad drmfb_genfb_ioctl(void *v, void *vs, unsigned long cmd, void *data, int flag, 186 1.1 riastrad struct lwp *l) 187 1.1 riastrad { 188 1.1 riastrad struct genfb_softc *const genfb = v; 189 1.1 riastrad struct drmfb_softc *const sc = container_of(genfb, struct drmfb_softc, 190 1.1 riastrad sc_genfb); 191 1.1 riastrad int error; 192 1.1 riastrad 193 1.1 riastrad if (sc->sc_da.da_params->dp_ioctl) { 194 1.1 riastrad error = (*sc->sc_da.da_params->dp_ioctl)(sc, cmd, data, flag, 195 1.1 riastrad l); 196 1.1 riastrad if (error != EPASSTHROUGH) 197 1.1 riastrad return error; 198 1.1 riastrad } 199 1.1 riastrad 200 1.1 riastrad switch (cmd) { 201 1.1 riastrad /* 202 1.1 riastrad * Screen blanking ioctls. Not to be confused with backlight 203 1.1 riastrad * (can be disabled while stuff is still drawn on the screen), 204 1.1 riastrad * brightness, or contrast (which we don't support). Backlight 205 1.1 riastrad * and brightness are done through WSDISPLAYIO_{GET,SET}PARAM. 206 1.1 riastrad * This toggles between DPMS ON and DPMS OFF; backlight toggles 207 1.1 riastrad * between DPMS ON and DPMS SUSPEND. 208 1.1 riastrad */ 209 1.1 riastrad case WSDISPLAYIO_GVIDEO: { 210 1.1 riastrad int *onp = (int *)data; 211 1.1 riastrad 212 1.1 riastrad /* XXX Can't really determine a single answer here. */ 213 1.1 riastrad *onp = 1; 214 1.1 riastrad return 0; 215 1.1 riastrad } 216 1.1 riastrad case WSDISPLAYIO_SVIDEO: { 217 1.1 riastrad const int on = *(const int *)data; 218 1.1 riastrad const int dpms_mode = on? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF; 219 1.1 riastrad struct drm_fb_helper *const fb_helper = sc->sc_da.da_fb_helper; 220 1.1 riastrad 221 1.11 riastrad mutex_lock(&fb_helper->lock); 222 1.11 riastrad drm_client_modeset_dpms(&fb_helper->client, dpms_mode); 223 1.11 riastrad mutex_unlock(&fb_helper->lock); 224 1.1 riastrad 225 1.1 riastrad return 0; 226 1.1 riastrad } 227 1.1 riastrad default: 228 1.1 riastrad return EPASSTHROUGH; 229 1.1 riastrad } 230 1.1 riastrad } 231 1.1 riastrad 232 1.1 riastrad static paddr_t 233 1.1 riastrad drmfb_genfb_mmap(void *v, void *vs, off_t offset, int prot) 234 1.1 riastrad { 235 1.1 riastrad struct genfb_softc *const genfb = v; 236 1.1 riastrad struct drmfb_softc *const sc = container_of(genfb, struct drmfb_softc, 237 1.1 riastrad sc_genfb); 238 1.1 riastrad 239 1.1 riastrad KASSERT(0 <= offset); 240 1.1 riastrad 241 1.1 riastrad if (offset < genfb->sc_fbsize) { 242 1.1 riastrad if (sc->sc_da.da_params->dp_mmapfb == NULL) 243 1.1 riastrad return -1; 244 1.1 riastrad return (*sc->sc_da.da_params->dp_mmapfb)(sc, offset, prot); 245 1.1 riastrad } else { 246 1.1 riastrad if (kauth_authorize_machdep(kauth_cred_get(), 247 1.1 riastrad KAUTH_MACHDEP_UNMANAGEDMEM, NULL, NULL, NULL, NULL) 248 1.1 riastrad != 0) 249 1.1 riastrad return -1; 250 1.1 riastrad if (sc->sc_da.da_params->dp_mmap == NULL) 251 1.1 riastrad return -1; 252 1.1 riastrad return (*sc->sc_da.da_params->dp_mmap)(sc, offset, prot); 253 1.1 riastrad } 254 1.1 riastrad } 255 1.1 riastrad 256 1.1 riastrad static int 257 1.1 riastrad drmfb_genfb_enable_polling(void *cookie) 258 1.1 riastrad { 259 1.1 riastrad struct genfb_softc *const genfb = cookie; 260 1.1 riastrad struct drmfb_softc *const sc = container_of(genfb, struct drmfb_softc, 261 1.1 riastrad sc_genfb); 262 1.1 riastrad 263 1.1 riastrad return drm_fb_helper_debug_enter_fb(sc->sc_da.da_fb_helper); 264 1.1 riastrad } 265 1.1 riastrad 266 1.1 riastrad static int 267 1.1 riastrad drmfb_genfb_disable_polling(void *cookie) 268 1.1 riastrad { 269 1.1 riastrad struct genfb_softc *const genfb = cookie; 270 1.1 riastrad struct drmfb_softc *const sc = container_of(genfb, struct drmfb_softc, 271 1.1 riastrad sc_genfb); 272 1.1 riastrad 273 1.1 riastrad return drm_fb_helper_debug_leave_fb(sc->sc_da.da_fb_helper); 274 1.1 riastrad } 275 1.1 riastrad 276 1.1 riastrad static bool 277 1.1 riastrad drmfb_genfb_setmode(struct genfb_softc *genfb, int mode) 278 1.1 riastrad { 279 1.1 riastrad struct drmfb_softc *sc = container_of(genfb, struct drmfb_softc, 280 1.1 riastrad sc_genfb); 281 1.4 riastrad struct drm_fb_helper *fb_helper = sc->sc_da.da_fb_helper; 282 1.1 riastrad 283 1.1 riastrad if (mode == WSDISPLAYIO_MODE_EMUL) 284 1.4 riastrad drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); 285 1.1 riastrad 286 1.1 riastrad return true; 287 1.1 riastrad } 288 1.1 riastrad 289 1.1 riastrad bool 290 1.1 riastrad drmfb_shutdown(struct drmfb_softc *sc, int flags __unused) 291 1.1 riastrad { 292 1.1 riastrad 293 1.1 riastrad genfb_enable_polling(sc->sc_da.da_dev); 294 1.1 riastrad return true; 295 1.1 riastrad } 296