1*d66736b0Sjsg /* $OpenBSD: rkdrm.c,v 1.23 2024/08/21 11:24:12 jsg Exp $ */ 260afa471Spatrick /* $NetBSD: rk_drm.c,v 1.3 2019/12/15 01:00:58 mrg Exp $ */ 360afa471Spatrick /*- 460afa471Spatrick * Copyright (c) 2019 Jared D. McNeill <jmcneill@invisible.ca> 560afa471Spatrick * Copyright (c) 2020 Patrick Wildt <patrick@blueri.se> 660afa471Spatrick * All rights reserved. 760afa471Spatrick * 860afa471Spatrick * Redistribution and use in source and binary forms, with or without 960afa471Spatrick * modification, are permitted provided that the following conditions 1060afa471Spatrick * are met: 1160afa471Spatrick * 1. Redistributions of source code must retain the above copyright 1260afa471Spatrick * notice, this list of conditions and the following disclaimer. 1360afa471Spatrick * 2. Redistributions in binary form must reproduce the above copyright 1460afa471Spatrick * notice, this list of conditions and the following disclaimer in the 1560afa471Spatrick * documentation and/or other materials provided with the distribution. 1660afa471Spatrick * 1760afa471Spatrick * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1860afa471Spatrick * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1960afa471Spatrick * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2060afa471Spatrick * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2160afa471Spatrick * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2260afa471Spatrick * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2360afa471Spatrick * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2460afa471Spatrick * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2560afa471Spatrick * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2660afa471Spatrick * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2760afa471Spatrick * SUCH DAMAGE. 2860afa471Spatrick */ 2960afa471Spatrick 3060afa471Spatrick #include <sys/param.h> 3160afa471Spatrick #include <sys/device.h> 3260afa471Spatrick #include <sys/systm.h> 3360afa471Spatrick 3460afa471Spatrick #include <machine/bus.h> 3560afa471Spatrick #include <machine/fdt.h> 3660afa471Spatrick 3760afa471Spatrick #include <dev/ofw/openfirm.h> 3860afa471Spatrick #include <dev/ofw/ofw_misc.h> 3960afa471Spatrick 40c349dbc7Sjsg #include <drm/drm_atomic_helper.h> 41c349dbc7Sjsg #include <drm/drm_drv.h> 4260afa471Spatrick #include <drm/drm_fb_helper.h> 4360afa471Spatrick #include <drm/drm_gem.h> 4460afa471Spatrick 4560afa471Spatrick #include <dev/fdt/rkdrm.h> 4660afa471Spatrick 4760afa471Spatrick #define RK_DRM_MAX_WIDTH 3840 4860afa471Spatrick #define RK_DRM_MAX_HEIGHT 2160 4960afa471Spatrick 5060afa471Spatrick int rkdrm_match(struct device *, void *, void *); 5160afa471Spatrick void rkdrm_attach(struct device *, struct device *, void *); 5260afa471Spatrick void rkdrm_attachhook(struct device *); 5360afa471Spatrick 5460afa471Spatrick int rkdrm_unload(struct drm_device *); 5560afa471Spatrick 5660afa471Spatrick struct drm_driver rkdrm_driver = { 57c349dbc7Sjsg .driver_features = DRIVER_ATOMIC | DRIVER_MODESET | DRIVER_GEM, 5860afa471Spatrick 591bb76ff1Sjsg .dumb_create = drm_gem_dma_dumb_create, 60c349dbc7Sjsg .dumb_map_offset = drm_gem_dumb_map_offset, 6160afa471Spatrick 621bb76ff1Sjsg .gem_fault = drm_gem_dma_fault, 6360afa471Spatrick 6460afa471Spatrick .name = DRIVER_NAME, 6560afa471Spatrick .desc = DRIVER_DESC, 6660afa471Spatrick .date = DRIVER_DATE, 6760afa471Spatrick .major = DRIVER_MAJOR, 6860afa471Spatrick .minor = DRIVER_MINOR, 6960afa471Spatrick .patchlevel = DRIVER_PATCHLEVEL, 7060afa471Spatrick }; 7160afa471Spatrick 725ca02815Sjsg const struct drm_gem_object_funcs rkdrm_gem_object_funcs = { 731bb76ff1Sjsg .free = drm_gem_dma_free_object, 745ca02815Sjsg }; 755ca02815Sjsg 76471aeecfSnaddy const struct cfattach rkdrm_ca = { 7760afa471Spatrick sizeof (struct rkdrm_softc), rkdrm_match, rkdrm_attach 7860afa471Spatrick }; 7960afa471Spatrick 8060afa471Spatrick struct cfdriver rkdrm_cd = { 8160afa471Spatrick NULL, "rkdrm", DV_DULL 8260afa471Spatrick }; 8360afa471Spatrick 8460afa471Spatrick int 8560afa471Spatrick rkdrm_match(struct device *parent, void *match, void *aux) 8660afa471Spatrick { 8760afa471Spatrick struct fdt_attach_args *faa = aux; 8860afa471Spatrick 8960afa471Spatrick return OF_is_compatible(faa->fa_node, "rockchip,display-subsystem"); 9060afa471Spatrick } 9160afa471Spatrick 9260afa471Spatrick void 9360afa471Spatrick rkdrm_attach(struct device *parent, struct device *self, void *aux) 9460afa471Spatrick { 9560afa471Spatrick struct rkdrm_softc *sc = (struct rkdrm_softc *)self; 9660afa471Spatrick struct fdt_attach_args *faa = aux; 9760afa471Spatrick 9860afa471Spatrick sc->sc_dmat = faa->fa_dmat; 9960afa471Spatrick sc->sc_iot = faa->fa_iot; 10060afa471Spatrick sc->sc_node = faa->fa_node; 10160afa471Spatrick 10260afa471Spatrick printf("\n"); 10360afa471Spatrick 1047dd3f745Skettenis /* 1057dd3f745Skettenis * Update our understanding of the console output node if 1067dd3f745Skettenis * we're using the framebuffer console. 1077dd3f745Skettenis */ 1087dd3f745Skettenis if (OF_is_compatible(stdout_node, "simple-framebuffer")) 1097dd3f745Skettenis stdout_node = sc->sc_node; 1107dd3f745Skettenis 111c349dbc7Sjsg drm_attach_platform(&rkdrm_driver, faa->fa_iot, faa->fa_dmat, self, 112c349dbc7Sjsg &sc->sc_ddev); 11360afa471Spatrick config_mountroot(self, rkdrm_attachhook); 11460afa471Spatrick } 11560afa471Spatrick 11660afa471Spatrick int 11760afa471Spatrick rkdrm_fb_create_handle(struct drm_framebuffer *fb, 11860afa471Spatrick struct drm_file *file, unsigned int *handle) 11960afa471Spatrick { 12060afa471Spatrick struct rkdrm_framebuffer *sfb = to_rkdrm_framebuffer(fb); 12160afa471Spatrick 12260afa471Spatrick return drm_gem_handle_create(file, &sfb->obj->base, handle); 12360afa471Spatrick } 12460afa471Spatrick 12560afa471Spatrick void 12660afa471Spatrick rkdrm_fb_destroy(struct drm_framebuffer *fb) 12760afa471Spatrick { 12860afa471Spatrick struct rkdrm_framebuffer *sfb = to_rkdrm_framebuffer(fb); 12960afa471Spatrick 13060afa471Spatrick drm_framebuffer_cleanup(fb); 131ad8b1aafSjsg drm_gem_object_put(&sfb->obj->base); 13260afa471Spatrick free(sfb, M_DRM, sizeof(*sfb)); 13360afa471Spatrick } 13460afa471Spatrick 13560afa471Spatrick struct drm_framebuffer_funcs rkdrm_framebuffer_funcs = { 13660afa471Spatrick .create_handle = rkdrm_fb_create_handle, 13760afa471Spatrick .destroy = rkdrm_fb_destroy, 13860afa471Spatrick }; 13960afa471Spatrick 14060afa471Spatrick struct drm_framebuffer * 14160afa471Spatrick rkdrm_fb_create(struct drm_device *ddev, struct drm_file *file, 14260afa471Spatrick const struct drm_mode_fb_cmd2 *cmd) 14360afa471Spatrick { 14460afa471Spatrick struct rkdrm_framebuffer *fb; 14560afa471Spatrick struct drm_gem_object *gem_obj; 14660afa471Spatrick int error; 14760afa471Spatrick 14860afa471Spatrick if (cmd->flags) 14960afa471Spatrick return NULL; 15060afa471Spatrick 15160afa471Spatrick gem_obj = drm_gem_object_lookup(file, cmd->handles[0]); 15260afa471Spatrick if (gem_obj == NULL) 15360afa471Spatrick return NULL; 15460afa471Spatrick 15560afa471Spatrick fb = malloc(sizeof(*fb), M_DRM, M_ZERO | M_WAITOK); 15660afa471Spatrick drm_helper_mode_fill_fb_struct(ddev, &fb->base, cmd); 15760afa471Spatrick fb->base.format = drm_format_info(DRM_FORMAT_ARGB8888); 1585ca02815Sjsg fb->base.obj[0] = gem_obj; 1591bb76ff1Sjsg fb->obj = to_drm_gem_dma_obj(gem_obj); 16060afa471Spatrick 16160afa471Spatrick error = drm_framebuffer_init(ddev, &fb->base, &rkdrm_framebuffer_funcs); 16260afa471Spatrick if (error != 0) 16360afa471Spatrick goto dealloc; 16460afa471Spatrick 16560afa471Spatrick return &fb->base; 16660afa471Spatrick 16760afa471Spatrick dealloc: 16860afa471Spatrick drm_framebuffer_cleanup(&fb->base); 16960afa471Spatrick free(fb, M_DRM, sizeof(*fb)); 170ad8b1aafSjsg drm_gem_object_put(gem_obj); 17160afa471Spatrick 17260afa471Spatrick return NULL; 17360afa471Spatrick } 17460afa471Spatrick 175c349dbc7Sjsg struct drm_mode_config_helper_funcs rkdrm_mode_config_helper_funcs = 176c349dbc7Sjsg { 177c349dbc7Sjsg .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, 178c349dbc7Sjsg }; 179c349dbc7Sjsg 18060afa471Spatrick struct drm_mode_config_funcs rkdrm_mode_config_funcs = { 18160afa471Spatrick .fb_create = rkdrm_fb_create, 182c349dbc7Sjsg .atomic_check = drm_atomic_helper_check, 183c349dbc7Sjsg .atomic_commit = drm_atomic_helper_commit, 18460afa471Spatrick }; 18560afa471Spatrick 18660afa471Spatrick int rkdrm_fb_probe(struct drm_fb_helper *, struct drm_fb_helper_surface_size *); 18760afa471Spatrick 18860afa471Spatrick struct drm_fb_helper_funcs rkdrm_fb_helper_funcs = { 18960afa471Spatrick .fb_probe = rkdrm_fb_probe, 19060afa471Spatrick }; 19160afa471Spatrick 19260afa471Spatrick int 19360afa471Spatrick rkdrm_unload(struct drm_device *ddev) 19460afa471Spatrick { 19560afa471Spatrick drm_mode_config_cleanup(ddev); 19660afa471Spatrick 19760afa471Spatrick return 0; 19860afa471Spatrick } 19960afa471Spatrick 20060afa471Spatrick void rkdrm_burner(void *, u_int, u_int); 20160afa471Spatrick int rkdrm_wsioctl(void *, u_long, caddr_t, int, struct proc *); 20260afa471Spatrick paddr_t rkdrm_wsmmap(void *, off_t, int); 20360afa471Spatrick int rkdrm_alloc_screen(void *, const struct wsscreen_descr *, 204e0c3e559Sjsg void **, int *, int *, uint32_t *); 20560afa471Spatrick void rkdrm_free_screen(void *, void *); 20660afa471Spatrick int rkdrm_show_screen(void *, void *, int, 20760afa471Spatrick void (*)(void *, int, int), void *); 20860afa471Spatrick void rkdrm_doswitch(void *); 20960afa471Spatrick void rkdrm_enter_ddb(void *, void *); 21060afa471Spatrick 21160afa471Spatrick struct wsscreen_descr rkdrm_stdscreen = { 21260afa471Spatrick "std", 21360afa471Spatrick 0, 0, 21460afa471Spatrick 0, 21560afa471Spatrick 0, 0, 21660afa471Spatrick WSSCREEN_UNDERLINE | WSSCREEN_HILIT | 21760afa471Spatrick WSSCREEN_REVERSE | WSSCREEN_WSCOLORS 21860afa471Spatrick }; 21960afa471Spatrick 22060afa471Spatrick const struct wsscreen_descr *rkdrm_scrlist[] = { 22160afa471Spatrick &rkdrm_stdscreen, 22260afa471Spatrick }; 22360afa471Spatrick 22460afa471Spatrick struct wsscreen_list rkdrm_screenlist = { 22560afa471Spatrick nitems(rkdrm_scrlist), rkdrm_scrlist 22660afa471Spatrick }; 22760afa471Spatrick 22860afa471Spatrick struct wsdisplay_accessops rkdrm_accessops = { 22960afa471Spatrick .ioctl = rkdrm_wsioctl, 23060afa471Spatrick .mmap = rkdrm_wsmmap, 23160afa471Spatrick .alloc_screen = rkdrm_alloc_screen, 23260afa471Spatrick .free_screen = rkdrm_free_screen, 23360afa471Spatrick .show_screen = rkdrm_show_screen, 23460afa471Spatrick .enter_ddb = rkdrm_enter_ddb, 23560afa471Spatrick .getchar = rasops_getchar, 23660afa471Spatrick .load_font = rasops_load_font, 23760afa471Spatrick .list_font = rasops_list_font, 23860afa471Spatrick .scrollback = rasops_scrollback, 23960afa471Spatrick #ifdef notyet 24060afa471Spatrick .burn_screen = rkdrm_burner 24160afa471Spatrick #endif 24260afa471Spatrick }; 24360afa471Spatrick 24460afa471Spatrick int 24560afa471Spatrick rkdrm_wsioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 24660afa471Spatrick { 24760afa471Spatrick struct rasops_info *ri = v; 24860afa471Spatrick struct wsdisplay_param *dp = (struct wsdisplay_param *)data; 24960afa471Spatrick struct wsdisplay_fbinfo *wdf; 25060afa471Spatrick 25160afa471Spatrick switch (cmd) { 252728f54cfSbmercer case WSDISPLAYIO_GETPARAM: 253728f54cfSbmercer if (ws_get_param) 254728f54cfSbmercer return ws_get_param(dp); 255728f54cfSbmercer return -1; 256728f54cfSbmercer case WSDISPLAYIO_SETPARAM: 257728f54cfSbmercer if (ws_set_param) 258728f54cfSbmercer return ws_set_param(dp); 259728f54cfSbmercer return -1; 26060afa471Spatrick case WSDISPLAYIO_GTYPE: 261aa99957fSkettenis *(u_int *)data = WSDISPLAY_TYPE_KMS; 26260afa471Spatrick return 0; 26360afa471Spatrick case WSDISPLAYIO_GINFO: 26460afa471Spatrick wdf = (struct wsdisplay_fbinfo *)data; 26560afa471Spatrick wdf->width = ri->ri_width; 26660afa471Spatrick wdf->height = ri->ri_height; 26760afa471Spatrick wdf->depth = ri->ri_depth; 26863294167Skettenis wdf->stride = ri->ri_stride; 26963294167Skettenis wdf->offset = 0; 27060afa471Spatrick wdf->cmsize = 0; 27160afa471Spatrick return 0; 27260afa471Spatrick case WSDISPLAYIO_LINEBYTES: 27360afa471Spatrick *(u_int *)data = ri->ri_stride; 27460afa471Spatrick return 0; 275804fcafaSjsg case WSDISPLAYIO_SVIDEO: 276804fcafaSjsg case WSDISPLAYIO_GVIDEO: 277804fcafaSjsg return 0; 27860afa471Spatrick } 27960afa471Spatrick 28060afa471Spatrick return (-1); 28160afa471Spatrick } 28260afa471Spatrick 28360afa471Spatrick paddr_t 28460afa471Spatrick rkdrm_wsmmap(void *v, off_t off, int prot) 28560afa471Spatrick { 28660afa471Spatrick struct rasops_info *ri = v; 28760afa471Spatrick struct rkdrm_softc *sc = ri->ri_hw; 28860afa471Spatrick struct drm_fb_helper *helper = &sc->helper; 28960afa471Spatrick struct rkdrm_framebuffer *sfb = to_rkdrm_framebuffer(helper->fb); 29060afa471Spatrick uint64_t paddr = (uint64_t)sfb->obj->dmamap->dm_segs[0].ds_addr; 29160afa471Spatrick size_t size = sfb->obj->dmamap->dm_segs[0].ds_len; 29260afa471Spatrick 29360afa471Spatrick if (off < 0 || off >= size) 29460afa471Spatrick return -1; 29560afa471Spatrick 29660afa471Spatrick return ((paddr + off) | PMAP_NOCACHE); 29760afa471Spatrick } 29860afa471Spatrick 29960afa471Spatrick int 30060afa471Spatrick rkdrm_alloc_screen(void *v, const struct wsscreen_descr *type, 301e0c3e559Sjsg void **cookiep, int *curxp, int *curyp, uint32_t *attrp) 30260afa471Spatrick { 30360afa471Spatrick return rasops_alloc_screen(v, cookiep, curxp, curyp, attrp); 30460afa471Spatrick } 30560afa471Spatrick 30660afa471Spatrick void 30760afa471Spatrick rkdrm_free_screen(void *v, void *cookie) 30860afa471Spatrick { 30960afa471Spatrick return rasops_free_screen(v, cookie); 31060afa471Spatrick } 31160afa471Spatrick 31260afa471Spatrick int 31360afa471Spatrick rkdrm_show_screen(void *v, void *cookie, int waitok, 31460afa471Spatrick void (*cb)(void *, int, int), void *cbarg) 31560afa471Spatrick { 31660afa471Spatrick struct rasops_info *ri = v; 31760afa471Spatrick struct rkdrm_softc *sc = ri->ri_hw; 31860afa471Spatrick 31960afa471Spatrick if (cookie == ri->ri_active) 32060afa471Spatrick return (0); 32160afa471Spatrick 32260afa471Spatrick sc->switchcb = cb; 32360afa471Spatrick sc->switchcbarg = cbarg; 32460afa471Spatrick sc->switchcookie = cookie; 32560afa471Spatrick if (cb) { 32660afa471Spatrick task_add(systq, &sc->switchtask); 32760afa471Spatrick return (EAGAIN); 32860afa471Spatrick } 32960afa471Spatrick 33060afa471Spatrick rkdrm_doswitch(v); 33160afa471Spatrick 33260afa471Spatrick return (0); 33360afa471Spatrick } 33460afa471Spatrick 33560afa471Spatrick void 33660afa471Spatrick rkdrm_doswitch(void *v) 33760afa471Spatrick { 33860afa471Spatrick struct rasops_info *ri = v; 33960afa471Spatrick struct rkdrm_softc *sc = ri->ri_hw; 34060afa471Spatrick 34160afa471Spatrick rasops_show_screen(ri, sc->switchcookie, 0, NULL, NULL); 34260afa471Spatrick drm_fb_helper_restore_fbdev_mode_unlocked(&sc->helper); 34360afa471Spatrick 34460afa471Spatrick if (sc->switchcb) 34560afa471Spatrick (sc->switchcb)(sc->switchcbarg, 0, 0); 34660afa471Spatrick } 34760afa471Spatrick 34860afa471Spatrick void 34960afa471Spatrick rkdrm_enter_ddb(void *v, void *cookie) 35060afa471Spatrick { 35160afa471Spatrick struct rasops_info *ri = v; 35260afa471Spatrick struct rkdrm_softc *sc = ri->ri_hw; 35360afa471Spatrick struct drm_fb_helper *fb_helper = &sc->helper; 35460afa471Spatrick 35560afa471Spatrick if (cookie == ri->ri_active) 35660afa471Spatrick return; 35760afa471Spatrick 35860afa471Spatrick rasops_show_screen(ri, cookie, 0, NULL, NULL); 359f005ef32Sjsg drm_fb_helper_debug_enter(fb_helper->info); 36060afa471Spatrick } 36160afa471Spatrick 36260afa471Spatrick void 36360afa471Spatrick rkdrm_attachhook(struct device *dev) 36460afa471Spatrick { 36560afa471Spatrick struct rkdrm_softc *sc = (struct rkdrm_softc *)dev; 36660afa471Spatrick struct wsemuldisplaydev_attach_args aa; 36760afa471Spatrick struct drm_fb_helper *helper = &sc->helper; 36860afa471Spatrick struct rasops_info *ri = &sc->ro; 36960afa471Spatrick struct rkdrm_framebuffer *sfb; 37060afa471Spatrick uint32_t *ports; 37160afa471Spatrick int i, portslen, nports; 3727dd3f745Skettenis int console = 0; 373e0c3e559Sjsg uint32_t defattr; 374eebea054Skettenis int error; 37560afa471Spatrick 3767dd3f745Skettenis if (sc->sc_node == stdout_node) 3777dd3f745Skettenis console = 1; 3787dd3f745Skettenis 37960afa471Spatrick portslen = OF_getproplen(sc->sc_node, "ports"); 38060afa471Spatrick if (portslen < 0) { 38160afa471Spatrick printf("%s: no display interface ports specified\n", 38260afa471Spatrick sc->sc_dev.dv_xname); 38360afa471Spatrick return; 38460afa471Spatrick } 38560afa471Spatrick 38660afa471Spatrick drm_mode_config_init(&sc->sc_ddev); 38760afa471Spatrick sc->sc_ddev.mode_config.min_width = 0; 38860afa471Spatrick sc->sc_ddev.mode_config.min_height = 0; 38960afa471Spatrick sc->sc_ddev.mode_config.max_width = RK_DRM_MAX_WIDTH; 39060afa471Spatrick sc->sc_ddev.mode_config.max_height = RK_DRM_MAX_HEIGHT; 39160afa471Spatrick sc->sc_ddev.mode_config.funcs = &rkdrm_mode_config_funcs; 392c349dbc7Sjsg sc->sc_ddev.mode_config.helper_private = 393c349dbc7Sjsg &rkdrm_mode_config_helper_funcs; 39460afa471Spatrick 39560afa471Spatrick nports = 0; 39660afa471Spatrick ports = malloc(portslen, M_TEMP, M_WAITOK); 39760afa471Spatrick OF_getpropintarray(sc->sc_node, "ports", ports, portslen); 39860afa471Spatrick for (i = 0; i < portslen / sizeof(uint32_t); i++) { 399eebea054Skettenis error = device_port_activate(ports[i], &sc->sc_ddev); 400eebea054Skettenis if (error == 0) 40160afa471Spatrick nports++; 40260afa471Spatrick } 40360afa471Spatrick free(ports, M_TEMP, portslen); 40460afa471Spatrick 40560afa471Spatrick if (nports == 0) { 40660afa471Spatrick printf("%s: no display interface ports configured\n", 40760afa471Spatrick sc->sc_dev.dv_xname); 40860afa471Spatrick drm_mode_config_cleanup(&sc->sc_ddev); 40960afa471Spatrick return; 41060afa471Spatrick } 41160afa471Spatrick 412c349dbc7Sjsg drm_mode_config_reset(&sc->sc_ddev); 413c349dbc7Sjsg 414f005ef32Sjsg drm_fb_helper_prepare(&sc->sc_ddev, &sc->helper, 32, 415f005ef32Sjsg &rkdrm_fb_helper_funcs); 416c349dbc7Sjsg if (drm_fb_helper_init(&sc->sc_ddev, &sc->helper)) { 41760afa471Spatrick printf("%s: can't initialize framebuffer helper\n", 41860afa471Spatrick sc->sc_dev.dv_xname); 41960afa471Spatrick drm_mode_config_cleanup(&sc->sc_ddev); 42060afa471Spatrick return; 42160afa471Spatrick } 42260afa471Spatrick 42360afa471Spatrick sc->helper.fb = malloc(sizeof(struct rkdrm_framebuffer), 42460afa471Spatrick M_DRM, M_WAITOK | M_ZERO); 42560afa471Spatrick 426f005ef32Sjsg drm_fb_helper_initial_config(&sc->helper); 42760afa471Spatrick 42860afa471Spatrick task_set(&sc->switchtask, rkdrm_doswitch, ri); 42960afa471Spatrick 43060afa471Spatrick drm_fb_helper_restore_fbdev_mode_unlocked(&sc->helper); 43160afa471Spatrick 43260afa471Spatrick sfb = to_rkdrm_framebuffer(helper->fb); 43360afa471Spatrick ri->ri_bits = sfb->obj->vaddr; 43460afa471Spatrick ri->ri_flg = RI_CENTER | RI_VCONS; 43560afa471Spatrick ri->ri_depth = helper->fb->format->depth; 43660afa471Spatrick ri->ri_width = helper->fb->width; 43760afa471Spatrick ri->ri_height = helper->fb->height; 43860afa471Spatrick ri->ri_stride = ri->ri_width * ri->ri_depth / 8; 4395dc98519Skettenis ri->ri_rnum = 8; /* ARGB8888 */ 4405dc98519Skettenis ri->ri_rpos = 16; 4415dc98519Skettenis ri->ri_gnum = 8; 4425dc98519Skettenis ri->ri_gpos = 8; 4435dc98519Skettenis ri->ri_bnum = 8; 4445dc98519Skettenis ri->ri_bpos = 0; 4455dc98519Skettenis rasops_init(ri, 160, 160); 44660afa471Spatrick ri->ri_hw = sc; 44760afa471Spatrick 44860afa471Spatrick rkdrm_stdscreen.capabilities = ri->ri_caps; 44960afa471Spatrick rkdrm_stdscreen.nrows = ri->ri_rows; 45060afa471Spatrick rkdrm_stdscreen.ncols = ri->ri_cols; 45160afa471Spatrick rkdrm_stdscreen.textops = &ri->ri_ops; 45260afa471Spatrick rkdrm_stdscreen.fontwidth = ri->ri_font->fontwidth; 45360afa471Spatrick rkdrm_stdscreen.fontheight = ri->ri_font->fontheight; 45460afa471Spatrick 4557dd3f745Skettenis if (console) { 456fc223b23Sjsg ri->ri_ops.pack_attr(ri->ri_active, 0, 0, 0, &defattr); 4577dd3f745Skettenis wsdisplay_cnattach(&rkdrm_stdscreen, ri->ri_active, 4587dd3f745Skettenis ri->ri_ccol, ri->ri_crow, defattr); 4597dd3f745Skettenis } 4607dd3f745Skettenis 46160afa471Spatrick memset(&aa, 0, sizeof(aa)); 46260afa471Spatrick aa.scrdata = &rkdrm_screenlist; 46360afa471Spatrick aa.accessops = &rkdrm_accessops; 46460afa471Spatrick aa.accesscookie = ri; 4657dd3f745Skettenis aa.console = console; 46660afa471Spatrick 46760afa471Spatrick printf("%s: %dx%d, %dbpp\n", sc->sc_dev.dv_xname, 46860afa471Spatrick ri->ri_width, ri->ri_height, ri->ri_depth); 46960afa471Spatrick 47060afa471Spatrick config_found_sm(&sc->sc_dev, &aa, wsemuldisplaydevprint, 47160afa471Spatrick wsemuldisplaydevsubmatch); 47260afa471Spatrick 47360afa471Spatrick drm_dev_register(&sc->sc_ddev, 0); 47460afa471Spatrick } 47560afa471Spatrick 47660afa471Spatrick int 47760afa471Spatrick rkdrm_fb_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) 47860afa471Spatrick { 47960afa471Spatrick struct drm_device *ddev = helper->dev; 48060afa471Spatrick struct rkdrm_framebuffer *sfb = to_rkdrm_framebuffer(helper->fb); 48160afa471Spatrick struct drm_mode_fb_cmd2 mode_cmd = { 0 }; 48260afa471Spatrick struct drm_framebuffer *fb = helper->fb; 48360afa471Spatrick unsigned int bytes_per_pixel; 48460afa471Spatrick struct fb_info *info; 48560afa471Spatrick size_t size; 48660afa471Spatrick int error; 48760afa471Spatrick 48860afa471Spatrick bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); 48960afa471Spatrick 49060afa471Spatrick mode_cmd.width = sizes->surface_width; 49160afa471Spatrick mode_cmd.height = sizes->surface_height; 49260afa471Spatrick mode_cmd.pitches[0] = sizes->surface_width * bytes_per_pixel; 49360afa471Spatrick mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, 49460afa471Spatrick sizes->surface_depth); 49560afa471Spatrick 49660afa471Spatrick size = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE); 49760afa471Spatrick 49860afa471Spatrick /* FIXME: CMA pool? */ 49960afa471Spatrick 5001bb76ff1Sjsg sfb->obj = drm_gem_dma_create(ddev, size); 50160afa471Spatrick if (sfb->obj == NULL) { 50260afa471Spatrick DRM_ERROR("failed to allocate memory for framebuffer\n"); 50360afa471Spatrick return -ENOMEM; 50460afa471Spatrick } 50560afa471Spatrick 50660afa471Spatrick drm_helper_mode_fill_fb_struct(ddev, fb, &mode_cmd); 50760afa471Spatrick fb->format = drm_format_info(DRM_FORMAT_ARGB8888); 5085ca02815Sjsg fb->obj[0] = &sfb->obj->base; 50960afa471Spatrick error = drm_framebuffer_init(ddev, fb, &rkdrm_framebuffer_funcs); 51060afa471Spatrick if (error != 0) { 51160afa471Spatrick DRM_ERROR("failed to initialize framebuffer\n"); 51260afa471Spatrick return error; 51360afa471Spatrick } 51460afa471Spatrick 515f005ef32Sjsg info = drm_fb_helper_alloc_info(helper); 51660afa471Spatrick if (IS_ERR(info)) { 51760afa471Spatrick DRM_ERROR("Failed to allocate fb_info\n"); 5188988417bSjsg return PTR_ERR(info); 51960afa471Spatrick } 52060afa471Spatrick info->par = helper; 52160afa471Spatrick return 0; 52260afa471Spatrick } 523