summaryrefslogtreecommitdiffstats
path: root/sys/dev/drm2/drm_fb_helper.c
diff options
context:
space:
mode:
authorray <ray@FreeBSD.org>2013-10-08 11:48:58 +0000
committerray <ray@FreeBSD.org>2013-10-08 11:48:58 +0000
commitb11a0aa7682cca3b3f87769a89baa4ba9c78095f (patch)
tree947fdc2bbc1e0d594e3a07b6c9777ec7c922cbef /sys/dev/drm2/drm_fb_helper.c
parenta1a002ce5c10e22c84d20c25340dc4a4b7c20757 (diff)
downloadFreeBSD-src-b11a0aa7682cca3b3f87769a89baa4ba9c78095f.zip
FreeBSD-src-b11a0aa7682cca3b3f87769a89baa4ba9c78095f.tar.gz
Add Newcons KMS driver. Based on drm_fb_helper functionality.
TODO: Should be moved to separate framebuffer interface. Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'sys/dev/drm2/drm_fb_helper.c')
-rw-r--r--sys/dev/drm2/drm_fb_helper.c183
1 files changed, 179 insertions, 4 deletions
diff --git a/sys/dev/drm2/drm_fb_helper.c b/sys/dev/drm2/drm_fb_helper.c
index 37b50cf..949fab1 100644
--- a/sys/dev/drm2/drm_fb_helper.c
+++ b/sys/dev/drm2/drm_fb_helper.c
@@ -36,6 +36,161 @@ __FBSDID("$FreeBSD$");
#include <dev/drm2/drm_fb_helper.h>
#include <dev/drm2/drm_crtc_helper.h>
+#include <dev/vt/vt.h>
+
+struct vt_kms_softc {
+ intptr_t sc_paddr;
+ intptr_t sc_vaddr;
+ int sc_depth;
+ int sc_stride;
+ int sc_width;
+ int sc_height;
+ struct drm_fb_helper *fb_helper;
+ struct task fb_mode_task;
+};
+
+static vd_init_t vt_kms_init;
+static vd_blank_t vt_kms_blank;
+static vd_bitblt_t vt_kms_bitblt;
+static vd_postswitch_t vt_kms_postswitch;
+static void vt_restore_fbdev_mode(void *, int);
+
+static struct vt_driver vt_vt_kms_driver = {
+ .vd_init = vt_kms_init,
+ .vd_blank = vt_kms_blank,
+ .vd_bitblt = vt_kms_bitblt,
+ .vd_postswitch = vt_kms_postswitch,
+};
+
+static const uint32_t colormap[] = {
+ 0x00000000, /* Black */
+ 0x00ff0000, /* Red */
+ 0x0000ff00, /* Green */
+ 0x00c0c000, /* Brown */
+ 0x000000ff, /* Blue */
+ 0x00c000c0, /* Magenta */
+ 0x0000c0c0, /* Cyan */
+ 0x00c0c0c0, /* Light grey */
+ 0x00808080, /* Dark grey */
+ 0x00ff8080, /* Light red */
+ 0x0080ff80, /* Light green */
+ 0x00ffff80, /* Yellow */
+ 0x008080ff, /* Light blue */
+ 0x00ff80ff, /* Light magenta */
+ 0x0080ffff, /* Light cyan */
+ 0x00ffffff, /* White */
+};
+
+static void
+vt_kms_blank(struct vt_device *vd, term_color_t color)
+{
+ struct vt_kms_softc *sc = vd->vd_softc;
+ u_int ofs;
+ uint32_t c;
+
+ /* TODO handle difference between */
+ switch (sc->sc_depth) {
+ case 8:
+ for (ofs = 0; ofs < (sc->sc_stride * vd->vd_height); ofs++)
+ *(uint8_t *)(sc->sc_vaddr + ofs) = color;
+ break;
+ case 16:
+ /* XXX must be 16bits colormap */
+ for (ofs = 0; ofs < (sc->sc_stride * vd->vd_height); ofs++)
+ *(uint16_t *)(sc->sc_vaddr + 2 * ofs) = color;
+ break;
+ case 24: /* */
+ case 32:
+ c = colormap[color];
+ for (ofs = 0; ofs < (sc->sc_stride * vd->vd_height); ofs++)
+ *(uint32_t *)(sc->sc_vaddr + 4 * ofs) = c;
+ break;
+ default:
+ /* panic? */
+ break;
+ }
+}
+
+static void
+vt_kms_bitblt(struct vt_device *vd, const uint8_t *src,
+ vt_axis_t top, vt_axis_t left, unsigned int width, unsigned int height,
+ term_color_t fg, term_color_t bg)
+{
+ struct vt_kms_softc *sc = vd->vd_softc;
+ u_long line;
+ uint32_t fgc, bgc;
+ int c;
+ uint8_t b = 0;
+
+ fgc = colormap[fg];
+ bgc = colormap[bg];
+
+ line = (sc->sc_stride * top) + left * sc->sc_depth/8;
+ for (; height > 0; height--) {
+ line += sc->sc_stride;
+ for (c = 0; c < width; c++) {
+ if (c % 8 == 0)
+ b = *src++;
+ else
+ b <<= 1;
+ switch(sc->sc_depth) {
+ case 8:
+ *(uint8_t *)(sc->sc_vaddr + line + c) =
+ b & 0x80 ? fg : bg;
+ break;
+ /* TODO 16 */
+ /* TODO 24 */
+ case 32:
+ *(uint32_t *)(sc->sc_vaddr + line + 4*c) =
+ (b & 0x80) ? fgc : bgc;
+ break;
+ default:
+ /* panic? */
+ break;
+ }
+ }
+ }
+}
+
+static int
+vt_kms_init(struct vt_device *vd)
+{
+ struct vt_kms_softc *sc;
+
+ sc = vd->vd_softc;
+
+ vd->vd_height = sc->sc_height;
+ vd->vd_width = sc->sc_width;
+
+ /* Clear the screen. */
+ vt_kms_blank(vd, TC_BLACK);
+
+ TASK_INIT(&sc->fb_mode_task, 0, vt_restore_fbdev_mode, vd);
+
+ return (CN_INTERNAL);
+}
+
+/* Call restore out of vt(9) locks. */
+static void
+vt_restore_fbdev_mode(void *arg, int pending)
+{
+ struct vt_kms_softc *sc;
+ struct vt_device *vd;
+
+ vd = (struct vt_device *)arg;
+ sc = vd->vd_softc;
+ drm_fb_helper_restore_fbdev_mode(sc->fb_helper);
+}
+
+static void
+vt_kms_postswitch(struct vt_device *vd)
+{
+ struct vt_kms_softc *sc;
+
+ sc = vd->vd_softc;
+ taskqueue_enqueue_fast(taskqueue_thread, &sc->fb_mode_task);
+}
+
static DRM_LIST_HEAD(kernel_fb_helper_list);
/* simple single crtc case helper function */
@@ -216,6 +371,10 @@ static int
fb_get_options(const char *connector_name, char **option)
{
+ /*
+ * TODO: store mode options pointer in ${option} for connector with
+ * name ${connector_name}
+ */
return (1);
}
@@ -892,9 +1051,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
int new_fb = 0;
int crtc_count = 0;
int i;
-#if 0
struct fb_info *info;
-#endif
struct drm_fb_helper_surface_size sizes;
int gamma_size = 0;
@@ -973,9 +1130,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
if (new_fb < 0)
return new_fb;
-#if 0
info = fb_helper->fbdev;
-#endif
/* set the fb pointer */
for (i = 0; i < fb_helper->crtc_count; i++) {
@@ -1007,6 +1162,26 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
#endif
+ struct vt_kms_softc *sc = (struct vt_kms_softc *)malloc(sizeof(struct vt_kms_softc), M_TEMP, M_WAITOK);
+ sc->sc_vaddr = info->fb_vbase;
+ sc->sc_paddr = info->fb_pbase;
+
+ sc->sc_depth = fb_helper->fb->bits_per_pixel; /* XXX: fix depth in VT, bpp is pix size, depth is meaning bits size */
+
+ sc->sc_height = fb_helper->fb->height;
+ sc->sc_stride = fb_helper->fb->pitches[0];
+ sc->sc_width = fb_helper->fb->width;
+ /* Save fb_helper (XXX Do we really need it?) */
+ sc->fb_helper = fb_helper;
+
+ drm_fb_helper_restore_fbdev_mode(fb_helper);
+
+ vt_allocate(&vt_vt_kms_driver, sc);
+
+ DRM_DEBUG("Attach VT to %dx%d fb: P %#lx V %#lx\n",
+ fb_helper->fb->width, fb_helper->fb->height,
+ info->fb_pbase, info->fb_vbase);
+
return 0;
}
OpenPOWER on IntegriCloud