diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 05b78c4b74a..23a46a82277 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1887,9 +1887,7 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper, #ifdef __FreeBSD__ info->fb_bsddev = fb_helper->dev->dev->bsddev; - struct vt_kms_softc *sc = (struct vt_kms_softc *)info->fbio.fb_priv; - if (sc) - sc->fb_helper = fb_helper; + info->fbio.fb_priv = fb_helper; #endif /* Need to drop locks to avoid recursive deadlock in diff --git a/drivers/gpu/drm/drm_os_freebsd.c b/drivers/gpu/drm/drm_os_freebsd.c index 422302f5bf0..2da980dc446 100644 --- a/drivers/gpu/drm/drm_os_freebsd.c +++ b/drivers/gpu/drm/drm_os_freebsd.c @@ -33,7 +33,7 @@ SYSCTL_NODE(_dev, OID_AUTO, drm, CTLFLAG_RW, 0, "DRM args (compat)"); SYSCTL_INT(_dev_drm, OID_AUTO, __drm_debug, CTLFLAG_RWTUN, &__drm_debug, 0, "drm debug flags (compat)"); SYSCTL_NODE(_hw, OID_AUTO, dri, CTLFLAG_RW, 0, "DRI args"); SYSCTL_INT(_hw_dri, OID_AUTO, __drm_debug, CTLFLAG_RWTUN, &__drm_debug, 0, "drm debug flags"); -static int skip_ddb; +int skip_ddb; SYSCTL_INT(_dev_drm, OID_AUTO, skip_ddb, CTLFLAG_RWTUN, &skip_ddb, 0, "go straight to dumping core (compat)"); SYSCTL_INT(_hw_dri, OID_AUTO, skip_ddb, CTLFLAG_RWTUN, &skip_ddb, 0, "go straight to dumping core"); #if defined(DRM_DEBUG_LOG_ALL) @@ -44,8 +44,6 @@ int drm_debug_persist = 0; SYSCTL_INT(_dev_drm, OID_AUTO, drm_debug_persist, CTLFLAG_RWTUN, &drm_debug_persist, 0, "keep drm debug flags post-load (compat)"); SYSCTL_INT(_hw_dri, OID_AUTO, drm_debug_persist, CTLFLAG_RWTUN, &drm_debug_persist, 0, "keep drm debug flags post-load"); -static bool already_switching_inside_panic = false; - static struct callout reset_debug_log_handle; static void @@ -83,60 +81,6 @@ sysctl_pci_id(SYSCTL_HANDLER_ARGS) /* Framebuffer related code */ -/* Call restore out of vt(9) locks. */ -void -vt_restore_fbdev_mode(void *arg, int pending) -{ - struct drm_fb_helper *fb_helper; - struct vt_kms_softc *sc; - struct mm_struct mm; - - sc = (struct vt_kms_softc *)arg; - fb_helper = sc->fb_helper; - linux_set_current(curthread); - if(!fb_helper) { - DRM_DEBUG("fb helper is null!\n"); - return; - } - drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); -} - -int -vt_kms_postswitch(void *arg) -{ - struct vt_kms_softc *sc; - - sc = (struct vt_kms_softc *)arg; - - if (!kdb_active && !KERNEL_PANICKED()) { - taskqueue_enqueue(taskqueue_thread, &sc->fb_mode_task); - - /* XXX the VT_ACTIVATE IOCTL must be synchronous */ - if (curthread->td_proc->p_pid != 0 && - taskqueue_member(taskqueue_thread, curthread) == 0) - taskqueue_drain(taskqueue_thread, &sc->fb_mode_task); - } else { -#ifdef DDB - db_trace_self_depth(10); - mdelay(1000); -#endif - if (already_switching_inside_panic || skip_ddb) { - spinlock_enter(); - doadump(false); - EVENTHANDLER_INVOKE(shutdown_final, RB_NOSYNC); - } - linux_set_current(curthread); - if(!sc->fb_helper) { - DRM_DEBUG("fb helper is null!\n"); - return -1; - } - already_switching_inside_panic = true; - drm_fb_helper_restore_fbdev_mode_unlocked(sc->fb_helper); - already_switching_inside_panic = false; - } - return (0); -} - int drm_dev_alias(struct device *ldev, struct drm_minor *minor, const char *minor_str) { diff --git a/drivers/gpu/drm/drm_os_freebsd.h b/drivers/gpu/drm/drm_os_freebsd.h index a61f70e603d..d0ecefd9d2d 100644 --- a/drivers/gpu/drm/drm_os_freebsd.h +++ b/drivers/gpu/drm/drm_os_freebsd.h @@ -20,11 +20,6 @@ __FBSDID("$FreeBSD$"); #define DRM_DEV_UID UID_ROOT #define DRM_DEV_GID GID_VIDEO -struct vt_kms_softc { - struct drm_fb_helper *fb_helper; - struct task fb_mode_task; -}; - /* XXXKIB what is the right code for the FreeBSD ? */ /* kib@ used ENXIO here -- dumbbell@ */ #define EREMOTEIO EIO @@ -37,14 +32,12 @@ MALLOC_DECLARE(DRM_MEM_DRIVER); MALLOC_DECLARE(DRM_MEM_KMS); extern devclass_t drm_devclass; +extern int skip_ddb; struct drm_minor; int drm_dev_alias(struct device *dev, struct drm_minor *minor, const char *minor_str); void cancel_reset_debug_log(void); -void vt_restore_fbdev_mode(void *arg, int pending); -int vt_kms_postswitch(void *arg); - #if 0 struct linux_fb_info; static inline void vga_switcheroo_unregister_client(struct pci_dev *pdev) {} diff --git a/drivers/gpu/drm/linux_fb.c b/drivers/gpu/drm/linux_fb.c index 92a4c0c3b90..66120acab9e 100644 --- a/drivers/gpu/drm/linux_fb.c +++ b/drivers/gpu/drm/linux_fb.c @@ -43,7 +43,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include "vt_drmfb.h" #include #include @@ -118,14 +118,8 @@ struct linux_fb_info * framebuffer_alloc(size_t size, struct device *dev) { struct linux_fb_info *info; - struct vt_kms_softc *sc; info = malloc(sizeof(*info) + size, LKPI_FB_MEM, M_WAITOK | M_ZERO); - sc = malloc(sizeof(*sc), LKPI_FB_MEM, M_WAITOK | M_ZERO); - TASK_INIT(&sc->fb_mode_task, 0, vt_restore_fbdev_mode, sc); - - info->fbio.fb_priv = sc; - info->fbio.enter = &vt_kms_postswitch; if (size) info->par = info + 1; @@ -138,14 +132,9 @@ framebuffer_alloc(size_t size, struct device *dev) void framebuffer_release(struct linux_fb_info *info) { - struct vt_kms_softc *sc; - if (info == NULL) return; - if (info->fbio.fb_priv) - sc = info->fbio.fb_priv; kfree(info->apertures); - free(info->fbio.fb_priv, LKPI_FB_MEM); free(info, LKPI_FB_MEM); } @@ -211,8 +200,7 @@ __register_framebuffer(struct linux_fb_info *fb_info) VM_MEMATTR_UNCACHEABLE); #endif - fb_helper = - ((struct vt_kms_softc *)fb_info->fbio.fb_priv)->fb_helper; + fb_helper = (struct drm_fb_helper *)fb_info->fbio.fb_priv; fb_info->fbio.fb_video_dev = device_get_parent(fb_helper->dev->dev->bsddev); fb_info->fbio.fb_name = @@ -232,14 +220,14 @@ __register_framebuffer(struct linux_fb_info *fb_info) fb_info->fbio.fb_fbd_dev = device_add_child(fb_info->fb_bsddev, "fbd", device_get_unit(fb_info->fb_bsddev)); - /* tell vt_fb to initialize color map */ + /* tell vt_drmfb to initialize color map */ fb_info->fbio.fb_cmsize = 0; if (fb_info->fbio.fb_bpp == 0) { device_printf(fb_info->fbio.fb_fbd_dev, "fb_bpp not set, setting to 8\n"); fb_info->fbio.fb_bpp = 32; } - if ((err = vt_fb_attach(&fb_info->fbio)) != 0) { + if ((err = vt_drmfb_attach(&fb_info->fbio)) != 0) { switch (err) { case EEXIST: device_printf(fb_info->fbio.fb_fbd_dev, @@ -283,7 +271,7 @@ __unregister_framebuffer(struct linux_fb_info *fb_info) mtx_unlock(&Giant); fb_info->fbio.fb_fbd_dev = NULL; } - vt_fb_detach(&fb_info->fbio); + vt_drmfb_detach(&fb_info->fbio); if (fb_info->fbops->fb_destroy) fb_info->fbops->fb_destroy(fb_info); @@ -333,40 +321,165 @@ linux_fb_get_options(const char *connector_name, char **option) return (*option != NULL ? 0 : -ENOENT); } +/* + * Routines to write to the framebuffer. They are used to implement Linux' + * fbdev equivalent functions below. + * + * Copied from `sys/dev/vt/hw/fb/vt_fb.c`. + */ + +static void +fb_mem_wr1(struct linux_fb_info *info, uint32_t offset, uint8_t value) +{ + KASSERT( + (offset < info->screen_size), + ("Offset %#08x out of framebuffer size", offset)); + *(uint8_t *)(info->screen_base + offset) = value; +} + +static void +fb_mem_wr2(struct linux_fb_info *info, uint32_t offset, uint16_t value) +{ + KASSERT( + (offset < info->screen_size), + ("Offset %#08x out of framebuffer size", offset)); + *(uint16_t *)(info->screen_base + offset) = value; +} + +static void +fb_mem_wr4(struct linux_fb_info *info, uint32_t offset, uint32_t value) +{ + KASSERT( + (offset < info->screen_size), + ("Offset %#08x out of framebuffer size", offset)); + *(uint32_t *)(info->screen_base + offset) = value; +} + +static void +fb_setpixel(struct linux_fb_info *info, uint32_t x, uint32_t y, + uint32_t color) +{ + uint32_t bytes_per_pixel; + unsigned int offset; + + bytes_per_pixel = info->var.bits_per_pixel / 8; + offset = info->fix.line_length * y + x * bytes_per_pixel; + + KASSERT((info->screen_base != 0), ("Unmapped framebuffer")); + + switch (bytes_per_pixel) { + case 1: + fb_mem_wr1(info, offset, color); + break; + case 2: + fb_mem_wr2(info, offset, color); + break; + case 3: + fb_mem_wr1(info, offset, (color >> 16) & 0xff); + fb_mem_wr1(info, offset + 1, (color >> 8) & 0xff); + fb_mem_wr1(info, offset + 2, color & 0xff); + break; + case 4: + fb_mem_wr4(info, offset, color); + break; + default: + /* panic? */ + return; + } +} + void cfb_fillrect(struct linux_fb_info *info, const struct fb_fillrect *rect) { + uint32_t x, y; + + if (info->fbio.fb_flags & FB_FLAG_NOWRITE) + return; + + KASSERT( + (rect->rop == ROP_COPY), + ("`rect->rop=%u` is unsupported in cfb_fillrect()", rect->rop)); + + for (y = rect->dy; y < rect->height; ++y) { + for (x = rect->dx; x < rect->width; ++x) { + fb_setpixel(info, x, y, rect->color); + } + } } void cfb_copyarea(struct linux_fb_info *info, const struct fb_copyarea *area) { + panic("Not implemented"); } void cfb_imageblit(struct linux_fb_info *info, const struct fb_image *image) { + uint32_t x, y, width, height, xi, yi; + uint32_t bytes_per_img_line, bit, byte, color; + + if (info->fbio.fb_flags & FB_FLAG_NOWRITE) + return; + + KASSERT( + (image->depth == 1), + ("`image->depth=%u` is unsupported in cfb_imageblit()", + image->depth)); + + bytes_per_img_line = (image->width + 7) / 8; + + x = image->dx; + y = image->dy; + width = image->width; + height = image->height; + + if (x + width > info->var.xres) { + if (x >= info->var.xres) + return; + width = info->var.xres - x; + } + if (y + height > info->var.yres) { + if (y >= info->var.yres) + return; + height = info->var.yres - y; + } + + for (yi = 0; yi < height; ++yi) { + for (xi = 0; xi < width; ++xi) { + byte = yi * bytes_per_img_line + xi / 8; + bit = 0x80 >> (xi % 8); + color = image->data[byte] & bit ? + image->fg_color : image->bg_color; + + fb_setpixel(info, x + xi, y + yi, color); + } + } } void sys_fillrect(struct linux_fb_info *info, const struct fb_fillrect *rect) { + cfb_fillrect(info, rect); } void sys_copyarea(struct linux_fb_info *info, const struct fb_copyarea *area) { + cfb_copyarea(info, area); } void sys_imageblit(struct linux_fb_info *info, const struct fb_image *image) { + cfb_imageblit(info, image); } ssize_t fb_sys_read(struct linux_fb_info *info, char __user *buf, size_t count, loff_t *ppos) { + panic("Not implemented"); return (0); } @@ -374,5 +487,6 @@ ssize_t fb_sys_write(struct linux_fb_info *info, const char __user *buf, size_t count, loff_t *ppos) { + panic("Not implemented"); return (0); } diff --git a/drivers/gpu/drm/vt_drmfb.c b/drivers/gpu/drm/vt_drmfb.c new file mode 100644 index 00000000000..116121e14fb --- /dev/null +++ b/drivers/gpu/drm/vt_drmfb.c @@ -0,0 +1,393 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2013 The FreeBSD Foundation + * Copyright (c) 2023 Jean-Sébastien Pédron + * + * This initial software `sys/dev/vt/hw/vt_fb.c` was developed by Aleksandr + * Rybalko under sponsorship from the FreeBSD Foundation. + * This file is a copy of the initial file and is modified by Jean-Sébastien + * Pédron. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include + +#include + +/* + * `drm_fb_helper.h` redefines `fb_info` to be `linux_fb_info` to manage the + * name conflict between the Linux and FreeBSD structures, while avoiding a + * extensive rewrite and use of macros in the original drm_fb_helper.[ch] + * files. + * + * We need to undo this here because we use both structures. + */ +#undef fb_info + +#include + +#include "vt_drmfb.h" + +#define to_drm_fb_helper(fbio) ((struct drm_fb_helper *)fbio->fb_priv) +#define to_linux_fb_info(fbio) (to_drm_fb_helper(fbio)->fbdev) + +static struct vt_driver vt_drmfb_driver = { + .vd_name = "drmfb", + .vd_init = vt_drmfb_init, + .vd_fini = vt_drmfb_fini, + .vd_blank = vt_drmfb_blank, + .vd_bitblt_text = vt_drmfb_bitblt_text, + .vd_bitblt_bmp = vt_drmfb_bitblt_bitmap, + .vd_drawrect = vt_drmfb_drawrect, + .vd_setpixel = vt_drmfb_setpixel, + .vd_postswitch = vt_drmfb_postswitch, + .vd_priority = VD_PRIORITY_GENERIC+20, + .vd_suspend = vt_drmfb_suspend, + .vd_resume = vt_drmfb_resume, + + /* Use vt_fb implementation */ + .vd_invalidate_text = vt_fb_invalidate_text, + .vd_fb_ioctl = vt_fb_ioctl, + .vd_fb_mmap = vt_fb_mmap, +}; + +static bool already_switching_inside_panic = false; + +VT_DRIVER_DECLARE(vt_drmfb, vt_drmfb_driver); + +void +vt_drmfb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) +{ + vt_drmfb_drawrect(vd, x, y, x, y, 1, color); +} + +void +vt_drmfb_drawrect( + struct vt_device *vd, + int x1, int y1, int x2, int y2, int fill, + term_color_t color) +{ + struct fb_info *fbio; + struct linux_fb_info *info; + struct fb_fillrect rect; + + fbio = vd->vd_softc; + info = to_linux_fb_info(fbio); + if (info->fbops->fb_fillrect == NULL) { + log(LOG_ERR, "No fb_fillrect callback defined\n"); + return; + } + + KASSERT( + (x2 >= x1), + ("Invalid rectangle X coordinates passed to vd_drawrect: " + "x1=%d > x2=%d", x1, x2)); + KASSERT( + (y2 >= y1), + ("Invalid rectangle Y coordinates passed to vd_drawrect: " + "y1=%d > y2=%d", y1, y2)); + KASSERT( + (fill != 0), + ("`fill=0` argument to vd_drawrect unsupported in vt_drmfb")); + + rect.dx = x1; + rect.dy = y1; + rect.width = x2 - x1 + 1; + rect.height = y2 - y1 + 1; + rect.color = fbio->fb_cmap[color]; + rect.rop = ROP_COPY; + + info->fbops->fb_fillrect(info, &rect); +} + +void +vt_drmfb_blank(struct vt_device *vd, term_color_t color) +{ + struct fb_info *fbio; + struct linux_fb_info *info; + int x1, y1, x2, y2; + + fbio = vd->vd_softc; + info = to_linux_fb_info(fbio); + + x1 = info->var.xoffset; + y1 = info->var.yoffset; + x2 = info->var.xres - 1; + y2 = info->var.yres - 1; + + vt_drmfb_drawrect(vd, x1, y1, x2, y2, 1, color); +} + +void +vt_drmfb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, + const uint8_t *pattern, const uint8_t *mask, + unsigned int width, unsigned int height, + unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) +{ + struct fb_info *fbio; + struct linux_fb_info *info; + struct fb_image image; + + KASSERT( + (mask != NULL), + ("`mask!=NULL` argument to vd_bitblt_bitmap unsupported in " + "vt_drmfb")); + + fbio = vd->vd_softc; + info = to_linux_fb_info(fbio); + if (info->fbops->fb_imageblit == NULL) { + log(LOG_ERR, "No fb_imageblit callback defined\n"); + return; + } + + image.dx = x; + image.dy = y; + image.width = width; + image.height = height; + image.fg_color = fbio->fb_cmap[fg]; + image.bg_color = fbio->fb_cmap[bg]; + image.depth = 1; + image.data = pattern; + + info->fbops->fb_imageblit(info, &image); +} + +void +vt_drmfb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, + const term_rect_t *area) +{ + unsigned int col, row, x, y; + struct vt_font *vf; + term_char_t c; + term_color_t fg, bg; + const uint8_t *pattern; + size_t z; + + vf = vw->vw_font; + + for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { + for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; + ++col) { + x = col * vf->vf_width + + vw->vw_draw_area.tr_begin.tp_col; + y = row * vf->vf_height + + vw->vw_draw_area.tr_begin.tp_row; + + c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); + pattern = vtfont_lookup(vf, c); + vt_determine_colors(c, + VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); + + z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; + if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * + PIXEL_WIDTH(VT_FB_MAX_WIDTH)) + continue; + if (vd->vd_drawn && (vd->vd_drawn[z] == c) && + vd->vd_drawnfg && (vd->vd_drawnfg[z] == fg) && + vd->vd_drawnbg && (vd->vd_drawnbg[z] == bg)) + continue; + + vt_drmfb_bitblt_bitmap(vd, vw, + pattern, NULL, vf->vf_width, vf->vf_height, + x, y, fg, bg); + + if (vd->vd_drawn) + vd->vd_drawn[z] = c; + if (vd->vd_drawnfg) + vd->vd_drawnfg[z] = fg; + if (vd->vd_drawnbg) + vd->vd_drawnbg[z] = bg; + } + } + +#ifndef SC_NO_CUTPASTE + if (!vd->vd_mshown) + return; + + term_rect_t drawn_area; + + drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; + drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; + drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; + drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; + + if (vt_is_cursor_in_area(vd, &drawn_area)) { + vt_drmfb_bitblt_bitmap(vd, vw, + vd->vd_mcursor->map, vd->vd_mcursor->mask, + vd->vd_mcursor->width, vd->vd_mcursor->height, + vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, + vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, + vd->vd_mcursor_fg, vd->vd_mcursor_bg); + } +#endif +} + +void +vt_drmfb_postswitch(struct vt_device *vd) +{ + struct fb_info *fbio; + struct linux_fb_info *info; + + fbio = vd->vd_softc; + info = to_linux_fb_info(fbio); + if (info->fbops->fb_set_par == NULL) { + log(LOG_ERR, "No fb_set_par callback defined\n"); + return; + } + + if (!kdb_active && !KERNEL_PANICKED()) { + linux_set_current(curthread); + info->fbops->fb_set_par(info); + } else { +#ifdef DDB + db_trace_self_depth(10); + mdelay(1000); +#endif + if (already_switching_inside_panic || skip_ddb) { + spinlock_enter(); + doadump(false); + EVENTHANDLER_INVOKE(shutdown_final, RB_NOSYNC); + } + + already_switching_inside_panic = true; + linux_set_current(curthread); + info->fbops->fb_set_par(info); + already_switching_inside_panic = false; + } +} + +static int +vt_drmfb_init_colors(struct fb_info *info) +{ + + switch (FBTYPE_GET_BPP(info)) { + case 8: + return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, + 0x7, 5, 0x7, 2, 0x3, 0)); + case 15: + return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, + 0x1f, 10, 0x1f, 5, 0x1f, 0)); + case 16: + return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, + 0x1f, 11, 0x3f, 5, 0x1f, 0)); + case 24: + case 32: /* Ignore alpha. */ + return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, + 0xff, 16, 0xff, 8, 0xff, 0)); + default: + return (1); + } +} + +int +vt_drmfb_init(struct vt_device *vd) +{ + struct fb_info *info; + u_int margin; + int bg, err; + term_color_t c; + + info = vd->vd_softc; + vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_height); + margin = (info->fb_height - vd->vd_height) >> 1; + vd->vd_transpose = margin * info->fb_stride; + vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_width); + margin = (info->fb_width - vd->vd_width) >> 1; + vd->vd_transpose += margin * (info->fb_bpp / NBBY); + vd->vd_video_dev = info->fb_video_dev; + + if (info->fb_size == 0) + return (CN_DEAD); + + if (info->fb_pbase == 0 && info->fb_vbase == 0) + info->fb_flags |= FB_FLAG_NOMMAP; + + if (info->fb_cmsize <= 0) { + err = vt_drmfb_init_colors(info); + if (err) + return (CN_DEAD); + info->fb_cmsize = 16; + } + + c = TC_BLACK; + if (TUNABLE_INT_FETCH("teken.bg_color", &bg) != 0) { + if (bg == TC_WHITE) + bg |= TC_LIGHT; + c = bg; + } + /* Clear the screen. */ + vd->vd_driver->vd_blank(vd, c); + + /* Wakeup screen. KMS need this. */ + vt_drmfb_postswitch(vd); + + return (CN_INTERNAL); +} + +void +vt_drmfb_fini(struct vt_device *vd, void *softc) +{ + vd->vd_video_dev = NULL; +} + +int +vt_drmfb_attach(struct fb_info *info) +{ + int ret; + + ret = vt_allocate(&vt_drmfb_driver, info); + + return (ret); +} + +int +vt_drmfb_detach(struct fb_info *info) +{ + int ret; + + ret = vt_deallocate(&vt_drmfb_driver, info); + + return (ret); +} + +void +vt_drmfb_suspend(struct vt_device *vd) +{ + vt_suspend(vd); +} + +void +vt_drmfb_resume(struct vt_device *vd) +{ + vt_resume(vd); +} diff --git a/drivers/gpu/drm/vt_drmfb.h b/drivers/gpu/drm/vt_drmfb.h new file mode 100644 index 00000000000..68a41416b21 --- /dev/null +++ b/drivers/gpu/drm/vt_drmfb.h @@ -0,0 +1,53 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2013 The FreeBSD Foundation + * Copyright (c) 2023 Jean-Sébastien Pédron + * + * This initial software `sys/dev/vt/hw/vt_fb.h` was developed by Aleksandr + * Rybalko under sponsorship from the FreeBSD Foundation. + * This file is a copy of the initial file and is modified by Jean-Sébastien + * Pédron. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_VT_HW_FB_VT_DRMFB_H_ +#define _DEV_VT_HW_FB_VT_DRMFB_H_ +/* Generic framebuffer interface call vt_drmfb_attach to init VT(9) */ +int vt_drmfb_attach(struct fb_info *info); +void vt_drmfb_resume(struct vt_device *vd); +void vt_drmfb_suspend(struct vt_device *vd); +int vt_drmfb_detach(struct fb_info *info); + +vd_init_t vt_drmfb_init; +vd_fini_t vt_drmfb_fini; +vd_blank_t vt_drmfb_blank; +vd_bitblt_text_t vt_drmfb_bitblt_text; +vd_bitblt_bmp_t vt_drmfb_bitblt_bitmap; +vd_drawrect_t vt_drmfb_drawrect; +vd_setpixel_t vt_drmfb_setpixel; +vd_postswitch_t vt_drmfb_postswitch; + +#endif /* _DEV_VT_HW_FB_VT_DRMFB_H_ */ diff --git a/drm/Makefile b/drm/Makefile index dc173a53767..ba072b8a5ea 100644 --- a/drm/Makefile +++ b/drm/Makefile @@ -68,7 +68,8 @@ SRCS= drm_atomic.c \ drm_vblank.c \ drm_vblank_work.c \ drm_vma_manager.c \ - linux_fb.c + linux_fb.c \ + vt_drmfb.c .if !empty(KCONFIG:MDRM_FBDEV_EMULATION) SRCS+= drm_fb_helper.c