87d2359388
Scope of this change is somewhat larger than just converting to INTRNG. The reason for this is that INTRNG support required switching from custom to upstream DTS because custom DTS didn't have interrup routing information. This switch caused rewrite of PCI and CLCD drivers and adding SCM module. List of changes in this commit: - Enable INTRNG and switch to versatile-pb.dts - Add SCM driver that controls various peripheral devices like LCD or PCI controller. Previously registers required for power-up and configuring peripherals were part of their respective nodes. Upstream DTS has dedicated node for SCM - Convert PL190 driver to INTRNG - Convert Versatile SIC (secondary interrupt controller) to INTRNG - Refactor CLCD driver to use SCM API to power up and configuration - Refactor PCI driver to use SCM API to enable controller - Refactor PCI driver to use interrupt map provided in DTS for interrupt routing. As a result it fixes broken IRQ routing and it's no longer required to run QEMU with "-global versatile_pci.broken-irq-mapping=1" command-line arguments
940 lines
21 KiB
C
940 lines
21 KiB
C
/*
|
|
* Copyright (c) 2012-2017 Oleksandr Tymoshenko <gonzo@freebsd.org>
|
|
* All rights reserved.
|
|
*
|
|
* 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 <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/bus.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/module.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/rman.h>
|
|
#include <sys/fbio.h>
|
|
#include <sys/consio.h>
|
|
#include <sys/kdb.h>
|
|
|
|
#include <machine/bus.h>
|
|
#include <machine/cpu.h>
|
|
#include <machine/intr.h>
|
|
|
|
#include <dev/ofw/openfirm.h>
|
|
#include <dev/ofw/ofw_bus.h>
|
|
#include <dev/ofw/ofw_bus_subr.h>
|
|
|
|
#include <dev/fb/fbreg.h>
|
|
#include <dev/syscons/syscons.h>
|
|
|
|
#include <arm/versatile/versatile_scm.h>
|
|
|
|
#include <machine/bus.h>
|
|
|
|
#define PL110_VENDOR_ARM926PXP 1
|
|
|
|
#define CLCD_MODE_RGB888 0x0
|
|
#define CLCD_MODE_RGB555 0x01
|
|
#define CLCD_MODE_RBG565 0x02
|
|
#define CLCD_MODE_RGB565 0x03
|
|
|
|
#define CLCDC_TIMING0 0x00
|
|
#define CLCDC_TIMING1 0x04
|
|
#define CLCDC_TIMING2 0x08
|
|
#define CLCDC_TIMING3 0x0C
|
|
#define CLCDC_TIMING3 0x0C
|
|
#define CLCDC_UPBASE 0x10
|
|
#define CLCDC_LPBASE 0x14
|
|
#ifdef PL110_VENDOR_ARM926PXP
|
|
#define CLCDC_CONTROL 0x18
|
|
#define CLCDC_IMSC 0x1C
|
|
#else
|
|
#define CLCDC_IMSC 0x18
|
|
#define CLCDC_CONTROL 0x1C
|
|
#endif
|
|
#define CONTROL_WATERMARK (1 << 16)
|
|
#define CONTROL_VCOMP_VS (0 << 12)
|
|
#define CONTROL_VCOMP_BP (1 << 12)
|
|
#define CONTROL_VCOMP_SAV (2 << 12)
|
|
#define CONTROL_VCOMP_FP (3 << 12)
|
|
#define CONTROL_PWR (1 << 11)
|
|
#define CONTROL_BEPO (1 << 10)
|
|
#define CONTROL_BEBO (1 << 9)
|
|
#define CONTROL_BGR (1 << 8)
|
|
#define CONTROL_DUAL (1 << 7)
|
|
#define CONTROL_MONO8 (1 << 6)
|
|
#define CONTROL_TFT (1 << 5)
|
|
#define CONTROL_BW (1 << 4)
|
|
#define CONTROL_BPP1 (0x00 << 1)
|
|
#define CONTROL_BPP2 (0x01 << 1)
|
|
#define CONTROL_BPP4 (0x02 << 1)
|
|
#define CONTROL_BPP8 (0x03 << 1)
|
|
#define CONTROL_BPP16 (0x04 << 1)
|
|
#define CONTROL_BPP24 (0x05 << 1)
|
|
#define CONTROL_EN (1 << 0)
|
|
#define CLCDC_RIS 0x20
|
|
#define CLCDC_MIS 0x24
|
|
#define INTR_MBERR (1 << 4)
|
|
#define INTR_VCOMP (1 << 3)
|
|
#define INTR_LNB (1 << 2)
|
|
#define INTR_FUF (1 << 1)
|
|
#define CLCDC_ICR 0x28
|
|
|
|
#ifdef DEBUG
|
|
#define dprintf(fmt, args...) do { printf("%s(): ", __func__); \
|
|
printf(fmt,##args); } while (0)
|
|
#else
|
|
#define dprintf(fmt, args...)
|
|
#endif
|
|
|
|
#define versatile_clcdc_read_4(sc, reg) \
|
|
bus_read_4((sc)->mem_res, (reg))
|
|
#define versatile_clcdc_write_4(sc, reg, val) \
|
|
bus_write_4((sc)->mem_res, (reg), (val))
|
|
|
|
struct versatile_clcdc_softc {
|
|
struct resource* mem_res;
|
|
|
|
struct mtx mtx;
|
|
|
|
int width;
|
|
int height;
|
|
int mode;
|
|
|
|
bus_dma_tag_t dma_tag;
|
|
bus_dmamap_t dma_map;
|
|
bus_addr_t fb_phys;
|
|
uint8_t *fb_base;
|
|
|
|
};
|
|
|
|
struct video_adapter_softc {
|
|
/* Videoadpater part */
|
|
video_adapter_t va;
|
|
int console;
|
|
|
|
intptr_t fb_addr;
|
|
unsigned int fb_size;
|
|
|
|
unsigned int height;
|
|
unsigned int width;
|
|
unsigned int depth;
|
|
unsigned int stride;
|
|
|
|
unsigned int xmargin;
|
|
unsigned int ymargin;
|
|
|
|
unsigned char *font;
|
|
int initialized;
|
|
};
|
|
|
|
struct argb {
|
|
uint8_t a;
|
|
uint8_t r;
|
|
uint8_t g;
|
|
uint8_t b;
|
|
};
|
|
|
|
static struct argb versatilefb_palette[16] = {
|
|
{0x00, 0x00, 0x00, 0x00},
|
|
{0x00, 0x00, 0x00, 0xaa},
|
|
{0x00, 0x00, 0xaa, 0x00},
|
|
{0x00, 0x00, 0xaa, 0xaa},
|
|
{0x00, 0xaa, 0x00, 0x00},
|
|
{0x00, 0xaa, 0x00, 0xaa},
|
|
{0x00, 0xaa, 0x55, 0x00},
|
|
{0x00, 0xaa, 0xaa, 0xaa},
|
|
{0x00, 0x55, 0x55, 0x55},
|
|
{0x00, 0x55, 0x55, 0xff},
|
|
{0x00, 0x55, 0xff, 0x55},
|
|
{0x00, 0x55, 0xff, 0xff},
|
|
{0x00, 0xff, 0x55, 0x55},
|
|
{0x00, 0xff, 0x55, 0xff},
|
|
{0x00, 0xff, 0xff, 0x55},
|
|
{0x00, 0xff, 0xff, 0xff}
|
|
};
|
|
|
|
/* mouse pointer from dev/syscons/scgfbrndr.c */
|
|
static u_char mouse_pointer[16] = {
|
|
0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68,
|
|
0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
#define FB_WIDTH 640
|
|
#define FB_HEIGHT 480
|
|
#define FB_DEPTH 16
|
|
|
|
#define VERSATILE_FONT_HEIGHT 16
|
|
|
|
static struct video_adapter_softc va_softc;
|
|
|
|
static int versatilefb_configure(int);
|
|
static void versatilefb_update_margins(video_adapter_t *adp);
|
|
|
|
static void
|
|
versatile_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
|
|
{
|
|
bus_addr_t *addr;
|
|
|
|
if (err)
|
|
return;
|
|
|
|
addr = (bus_addr_t*)arg;
|
|
*addr = segs[0].ds_addr;
|
|
}
|
|
|
|
static int
|
|
versatile_clcdc_probe(device_t dev)
|
|
{
|
|
|
|
if (!ofw_bus_status_okay(dev))
|
|
return (ENXIO);
|
|
|
|
if (ofw_bus_is_compatible(dev, "arm,pl110")) {
|
|
device_set_desc(dev, "PL110 CLCD controller");
|
|
return (BUS_PROBE_DEFAULT);
|
|
}
|
|
|
|
return (ENXIO);
|
|
}
|
|
|
|
static int
|
|
versatile_clcdc_attach(device_t dev)
|
|
{
|
|
struct versatile_clcdc_softc *sc = device_get_softc(dev);
|
|
struct video_adapter_softc *va_sc = &va_softc;
|
|
int err, rid;
|
|
uint32_t reg;
|
|
int clcdid;
|
|
int dma_size;
|
|
|
|
/* Request memory resources */
|
|
rid = 0;
|
|
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
|
|
if (sc->mem_res == NULL) {
|
|
device_printf(dev, "could not allocate memory resources\n");
|
|
return (ENXIO);
|
|
}
|
|
|
|
err = versatile_scm_reg_read_4(SCM_CLCD, ®);
|
|
if (err) {
|
|
device_printf(dev, "failed to read SCM register\n");
|
|
goto fail;
|
|
}
|
|
clcdid = (reg >> SCM_CLCD_CLCDID_SHIFT) & SCM_CLCD_CLCDID_MASK;
|
|
switch (clcdid) {
|
|
case 31:
|
|
device_printf(dev, "QEMU VGA 640x480\n");
|
|
sc->width = 640;
|
|
sc->height = 480;
|
|
break;
|
|
default:
|
|
device_printf(dev, "Unsupported: %d\n", clcdid);
|
|
goto fail;
|
|
}
|
|
|
|
reg &= ~SCM_CLCD_LCD_MODE_MASK;
|
|
reg |= CLCD_MODE_RGB565;
|
|
sc->mode = CLCD_MODE_RGB565;
|
|
versatile_scm_reg_write_4(SCM_CLCD, reg);
|
|
dma_size = sc->width*sc->height*2;
|
|
|
|
/*
|
|
* Power on LCD
|
|
*/
|
|
reg |= SCM_CLCD_PWR3V5VSWITCH | SCM_CLCD_NLCDIOON;
|
|
versatile_scm_reg_write_4(SCM_CLCD, reg);
|
|
|
|
/*
|
|
* XXX: hardcoded timing for VGA. For other modes/panels
|
|
* we need to keep table of timing register values
|
|
*/
|
|
/*
|
|
* XXX: set SYS_OSC1
|
|
*/
|
|
versatile_clcdc_write_4(sc, CLCDC_TIMING0, 0x3F1F3F9C);
|
|
versatile_clcdc_write_4(sc, CLCDC_TIMING1, 0x090B61DF);
|
|
versatile_clcdc_write_4(sc, CLCDC_TIMING2, 0x067F1800);
|
|
/* XXX: timing 3? */
|
|
|
|
/*
|
|
* Now allocate framebuffer memory
|
|
*/
|
|
err = bus_dma_tag_create(
|
|
bus_get_dma_tag(dev),
|
|
4, 0, /* alignment, boundary */
|
|
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
|
|
BUS_SPACE_MAXADDR, /* highaddr */
|
|
NULL, NULL, /* filter, filterarg */
|
|
dma_size, 1, /* maxsize, nsegments */
|
|
dma_size, 0, /* maxsegsize, flags */
|
|
NULL, NULL, /* lockfunc, lockarg */
|
|
&sc->dma_tag);
|
|
|
|
err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_base,
|
|
0, &sc->dma_map);
|
|
if (err) {
|
|
device_printf(dev, "cannot allocate framebuffer\n");
|
|
goto fail;
|
|
}
|
|
|
|
err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_base,
|
|
dma_size, versatile_fb_dmamap_cb, &sc->fb_phys, BUS_DMA_NOWAIT);
|
|
|
|
if (err) {
|
|
device_printf(dev, "cannot load DMA map\n");
|
|
goto fail;
|
|
}
|
|
|
|
/* Make sure it's blank */
|
|
memset(sc->fb_base, 0x00, dma_size);
|
|
|
|
versatile_clcdc_write_4(sc, CLCDC_UPBASE, sc->fb_phys);
|
|
|
|
err = (sc_attach_unit(device_get_unit(dev),
|
|
device_get_flags(dev) | SC_AUTODETECT_KBD));
|
|
|
|
if (err) {
|
|
device_printf(dev, "failed to attach syscons\n");
|
|
goto fail;
|
|
}
|
|
|
|
/*
|
|
* XXX: hardcoded for VGA
|
|
*/
|
|
reg = CONTROL_VCOMP_BP | CONTROL_TFT | CONTROL_BGR | CONTROL_EN;
|
|
reg |= CONTROL_BPP16;
|
|
versatile_clcdc_write_4(sc, CLCDC_CONTROL, reg);
|
|
DELAY(20);
|
|
reg |= CONTROL_PWR;
|
|
versatile_clcdc_write_4(sc, CLCDC_CONTROL, reg);
|
|
|
|
va_sc->fb_addr = (vm_offset_t)sc->fb_base;
|
|
va_sc->fb_size = dma_size;
|
|
va_sc->width = sc->width;
|
|
va_sc->height = sc->height;
|
|
va_sc->depth = 16;
|
|
va_sc->stride = sc->width * 2;
|
|
versatilefb_update_margins(&va_sc->va);
|
|
|
|
return (0);
|
|
|
|
fail:
|
|
if (sc->fb_base)
|
|
bus_dmamem_free(sc->dma_tag, sc->fb_base, sc->dma_map);
|
|
if (sc->dma_tag)
|
|
bus_dma_tag_destroy(sc->dma_tag);
|
|
return (err);
|
|
}
|
|
|
|
static device_method_t versatile_clcdc_methods[] = {
|
|
DEVMETHOD(device_probe, versatile_clcdc_probe),
|
|
DEVMETHOD(device_attach, versatile_clcdc_attach),
|
|
|
|
DEVMETHOD_END
|
|
};
|
|
|
|
static driver_t versatile_clcdc_driver = {
|
|
"clcdc",
|
|
versatile_clcdc_methods,
|
|
sizeof(struct versatile_clcdc_softc),
|
|
};
|
|
|
|
static devclass_t versatile_clcdc_devclass;
|
|
|
|
DRIVER_MODULE(versatile_clcdc, simplebus, versatile_clcdc_driver, versatile_clcdc_devclass, 0, 0);
|
|
|
|
/*
|
|
* Video driver routines and glue.
|
|
*/
|
|
static vi_probe_t versatilefb_probe;
|
|
static vi_init_t versatilefb_init;
|
|
static vi_get_info_t versatilefb_get_info;
|
|
static vi_query_mode_t versatilefb_query_mode;
|
|
static vi_set_mode_t versatilefb_set_mode;
|
|
static vi_save_font_t versatilefb_save_font;
|
|
static vi_load_font_t versatilefb_load_font;
|
|
static vi_show_font_t versatilefb_show_font;
|
|
static vi_save_palette_t versatilefb_save_palette;
|
|
static vi_load_palette_t versatilefb_load_palette;
|
|
static vi_set_border_t versatilefb_set_border;
|
|
static vi_save_state_t versatilefb_save_state;
|
|
static vi_load_state_t versatilefb_load_state;
|
|
static vi_set_win_org_t versatilefb_set_win_org;
|
|
static vi_read_hw_cursor_t versatilefb_read_hw_cursor;
|
|
static vi_set_hw_cursor_t versatilefb_set_hw_cursor;
|
|
static vi_set_hw_cursor_shape_t versatilefb_set_hw_cursor_shape;
|
|
static vi_blank_display_t versatilefb_blank_display;
|
|
static vi_mmap_t versatilefb_mmap;
|
|
static vi_ioctl_t versatilefb_ioctl;
|
|
static vi_clear_t versatilefb_clear;
|
|
static vi_fill_rect_t versatilefb_fill_rect;
|
|
static vi_bitblt_t versatilefb_bitblt;
|
|
static vi_diag_t versatilefb_diag;
|
|
static vi_save_cursor_palette_t versatilefb_save_cursor_palette;
|
|
static vi_load_cursor_palette_t versatilefb_load_cursor_palette;
|
|
static vi_copy_t versatilefb_copy;
|
|
static vi_putp_t versatilefb_putp;
|
|
static vi_putc_t versatilefb_putc;
|
|
static vi_puts_t versatilefb_puts;
|
|
static vi_putm_t versatilefb_putm;
|
|
|
|
static video_switch_t versatilefbvidsw = {
|
|
.probe = versatilefb_probe,
|
|
.init = versatilefb_init,
|
|
.get_info = versatilefb_get_info,
|
|
.query_mode = versatilefb_query_mode,
|
|
.set_mode = versatilefb_set_mode,
|
|
.save_font = versatilefb_save_font,
|
|
.load_font = versatilefb_load_font,
|
|
.show_font = versatilefb_show_font,
|
|
.save_palette = versatilefb_save_palette,
|
|
.load_palette = versatilefb_load_palette,
|
|
.set_border = versatilefb_set_border,
|
|
.save_state = versatilefb_save_state,
|
|
.load_state = versatilefb_load_state,
|
|
.set_win_org = versatilefb_set_win_org,
|
|
.read_hw_cursor = versatilefb_read_hw_cursor,
|
|
.set_hw_cursor = versatilefb_set_hw_cursor,
|
|
.set_hw_cursor_shape = versatilefb_set_hw_cursor_shape,
|
|
.blank_display = versatilefb_blank_display,
|
|
.mmap = versatilefb_mmap,
|
|
.ioctl = versatilefb_ioctl,
|
|
.clear = versatilefb_clear,
|
|
.fill_rect = versatilefb_fill_rect,
|
|
.bitblt = versatilefb_bitblt,
|
|
.diag = versatilefb_diag,
|
|
.save_cursor_palette = versatilefb_save_cursor_palette,
|
|
.load_cursor_palette = versatilefb_load_cursor_palette,
|
|
.copy = versatilefb_copy,
|
|
.putp = versatilefb_putp,
|
|
.putc = versatilefb_putc,
|
|
.puts = versatilefb_puts,
|
|
.putm = versatilefb_putm,
|
|
};
|
|
|
|
VIDEO_DRIVER(versatilefb, versatilefbvidsw, versatilefb_configure);
|
|
|
|
static vr_init_t clcdr_init;
|
|
static vr_clear_t clcdr_clear;
|
|
static vr_draw_border_t clcdr_draw_border;
|
|
static vr_draw_t clcdr_draw;
|
|
static vr_set_cursor_t clcdr_set_cursor;
|
|
static vr_draw_cursor_t clcdr_draw_cursor;
|
|
static vr_blink_cursor_t clcdr_blink_cursor;
|
|
static vr_set_mouse_t clcdr_set_mouse;
|
|
static vr_draw_mouse_t clcdr_draw_mouse;
|
|
|
|
/*
|
|
* We use our own renderer; this is because we must emulate a hardware
|
|
* cursor.
|
|
*/
|
|
static sc_rndr_sw_t clcdrend = {
|
|
clcdr_init,
|
|
clcdr_clear,
|
|
clcdr_draw_border,
|
|
clcdr_draw,
|
|
clcdr_set_cursor,
|
|
clcdr_draw_cursor,
|
|
clcdr_blink_cursor,
|
|
clcdr_set_mouse,
|
|
clcdr_draw_mouse
|
|
};
|
|
|
|
RENDERER(versatilefb, 0, clcdrend, gfb_set);
|
|
RENDERER_MODULE(versatilefb, gfb_set);
|
|
|
|
static void
|
|
clcdr_init(scr_stat* scp)
|
|
{
|
|
}
|
|
|
|
static void
|
|
clcdr_clear(scr_stat* scp, int c, int attr)
|
|
{
|
|
}
|
|
|
|
static void
|
|
clcdr_draw_border(scr_stat* scp, int color)
|
|
{
|
|
}
|
|
|
|
static void
|
|
clcdr_draw(scr_stat* scp, int from, int count, int flip)
|
|
{
|
|
video_adapter_t* adp = scp->sc->adp;
|
|
int i, c, a;
|
|
|
|
if (!flip) {
|
|
/* Normal printing */
|
|
vidd_puts(adp, from, (uint16_t*)sc_vtb_pointer(&scp->vtb, from), count);
|
|
} else {
|
|
/* This is for selections and such: invert the color attribute */
|
|
for (i = count; i-- > 0; ++from) {
|
|
c = sc_vtb_getc(&scp->vtb, from);
|
|
a = sc_vtb_geta(&scp->vtb, from) >> 8;
|
|
vidd_putc(adp, from, c, (a >> 4) | ((a & 0xf) << 4));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
clcdr_set_cursor(scr_stat* scp, int base, int height, int blink)
|
|
{
|
|
}
|
|
|
|
static void
|
|
clcdr_draw_cursor(scr_stat* scp, int off, int blink, int on, int flip)
|
|
{
|
|
video_adapter_t* adp = scp->sc->adp;
|
|
struct video_adapter_softc *sc;
|
|
int row, col;
|
|
uint8_t *addr;
|
|
int i,j;
|
|
|
|
sc = (struct video_adapter_softc *)adp;
|
|
|
|
if (scp->curs_attr.height <= 0)
|
|
return;
|
|
|
|
if (sc->fb_addr == 0)
|
|
return;
|
|
|
|
if (off >= adp->va_info.vi_width * adp->va_info.vi_height)
|
|
return;
|
|
|
|
/* calculate the coordinates in the video buffer */
|
|
row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
|
|
col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
|
|
|
|
addr = (uint8_t *)sc->fb_addr
|
|
+ (row + sc->ymargin)*(sc->stride)
|
|
+ (sc->depth/8) * (col + sc->xmargin);
|
|
|
|
/* our cursor consists of simply inverting the char under it */
|
|
for (i = 0; i < adp->va_info.vi_cheight; i++) {
|
|
for (j = 0; j < adp->va_info.vi_cwidth; j++) {
|
|
|
|
addr[2*j] ^= 0xff;
|
|
addr[2*j + 1] ^= 0xff;
|
|
}
|
|
|
|
addr += sc->stride;
|
|
}
|
|
}
|
|
|
|
static void
|
|
clcdr_blink_cursor(scr_stat* scp, int at, int flip)
|
|
{
|
|
}
|
|
|
|
static void
|
|
clcdr_set_mouse(scr_stat* scp)
|
|
{
|
|
}
|
|
|
|
static void
|
|
clcdr_draw_mouse(scr_stat* scp, int x, int y, int on)
|
|
{
|
|
vidd_putm(scp->sc->adp, x, y, mouse_pointer, 0xffffffff, 16, 8);
|
|
|
|
}
|
|
|
|
static uint16_t versatilefb_static_window[ROW*COL];
|
|
extern u_char dflt_font_16[];
|
|
|
|
/*
|
|
* Update videoadapter settings after changing resolution
|
|
*/
|
|
static void
|
|
versatilefb_update_margins(video_adapter_t *adp)
|
|
{
|
|
struct video_adapter_softc *sc;
|
|
video_info_t *vi;
|
|
|
|
sc = (struct video_adapter_softc *)adp;
|
|
vi = &adp->va_info;
|
|
|
|
sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
|
|
sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2;
|
|
}
|
|
|
|
static int
|
|
versatilefb_configure(int flags)
|
|
{
|
|
struct video_adapter_softc *va_sc;
|
|
|
|
va_sc = &va_softc;
|
|
|
|
if (va_sc->initialized)
|
|
return (0);
|
|
|
|
va_sc->width = FB_WIDTH;
|
|
va_sc->height = FB_HEIGHT;
|
|
va_sc->depth = FB_DEPTH;
|
|
|
|
versatilefb_init(0, &va_sc->va, 0);
|
|
|
|
va_sc->initialized = 1;
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_init(int unit, video_adapter_t *adp, int flags)
|
|
{
|
|
struct video_adapter_softc *sc;
|
|
video_info_t *vi;
|
|
|
|
sc = (struct video_adapter_softc *)adp;
|
|
vi = &adp->va_info;
|
|
|
|
vid_init_struct(adp, "versatilefb", -1, unit);
|
|
|
|
sc->font = dflt_font_16;
|
|
vi->vi_cheight = VERSATILE_FONT_HEIGHT;
|
|
vi->vi_cwidth = 8;
|
|
|
|
vi->vi_width = sc->width/8;
|
|
vi->vi_height = sc->height/vi->vi_cheight;
|
|
|
|
/*
|
|
* Clamp width/height to syscons maximums
|
|
*/
|
|
if (vi->vi_width > COL)
|
|
vi->vi_width = COL;
|
|
if (vi->vi_height > ROW)
|
|
vi->vi_height = ROW;
|
|
|
|
sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
|
|
sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2;
|
|
|
|
adp->va_window = (vm_offset_t) versatilefb_static_window;
|
|
adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */;
|
|
|
|
vid_register(&sc->va);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
|
|
{
|
|
bcopy(&adp->va_info, info, sizeof(*info));
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_query_mode(video_adapter_t *adp, video_info_t *info)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_set_mode(video_adapter_t *adp, int mode)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_save_font(video_adapter_t *adp, int page, int size, int width,
|
|
u_char *data, int c, int count)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_load_font(video_adapter_t *adp, int page, int size, int width,
|
|
u_char *data, int c, int count)
|
|
{
|
|
struct video_adapter_softc *sc = (struct video_adapter_softc *)adp;
|
|
|
|
sc->font = data;
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_show_font(video_adapter_t *adp, int page)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_save_palette(video_adapter_t *adp, u_char *palette)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_load_palette(video_adapter_t *adp, u_char *palette)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_set_border(video_adapter_t *adp, int border)
|
|
{
|
|
return (versatilefb_blank_display(adp, border));
|
|
}
|
|
|
|
static int
|
|
versatilefb_save_state(video_adapter_t *adp, void *p, size_t size)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_load_state(video_adapter_t *adp, void *p)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_set_win_org(video_adapter_t *adp, off_t offset)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
|
|
{
|
|
*col = *row = 0;
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_set_hw_cursor(video_adapter_t *adp, int col, int row)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
|
|
int celsize, int blink)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_blank_display(video_adapter_t *adp, int mode)
|
|
{
|
|
|
|
struct video_adapter_softc *sc;
|
|
|
|
sc = (struct video_adapter_softc *)adp;
|
|
if (sc && sc->fb_addr)
|
|
memset((void*)sc->fb_addr, 0, sc->fb_size);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
|
|
int prot, vm_memattr_t *memattr)
|
|
{
|
|
struct video_adapter_softc *sc;
|
|
|
|
sc = (struct video_adapter_softc *)adp;
|
|
|
|
/*
|
|
* This might be a legacy VGA mem request: if so, just point it at the
|
|
* framebuffer, since it shouldn't be touched
|
|
*/
|
|
if (offset < sc->stride*sc->height) {
|
|
*paddr = sc->fb_addr + offset;
|
|
return (0);
|
|
}
|
|
|
|
return (EINVAL);
|
|
}
|
|
|
|
static int
|
|
versatilefb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_clear(video_adapter_t *adp)
|
|
{
|
|
|
|
return (versatilefb_blank_display(adp, 0));
|
|
}
|
|
|
|
static int
|
|
versatilefb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_bitblt(video_adapter_t *adp, ...)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_diag(video_adapter_t *adp, int level)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
|
|
int size, int bpp, int bit_ltor, int byte_ltor)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
|
|
{
|
|
struct video_adapter_softc *sc;
|
|
int row;
|
|
int col;
|
|
int i, j, k;
|
|
uint8_t *addr;
|
|
u_char *p;
|
|
uint8_t fg, bg, color;
|
|
uint16_t rgb;
|
|
|
|
sc = (struct video_adapter_softc *)adp;
|
|
|
|
if (sc->fb_addr == 0)
|
|
return (0);
|
|
|
|
if (off >= adp->va_info.vi_width * adp->va_info.vi_height)
|
|
return (0);
|
|
|
|
row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
|
|
col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
|
|
p = sc->font + c*VERSATILE_FONT_HEIGHT;
|
|
addr = (uint8_t *)sc->fb_addr
|
|
+ (row + sc->ymargin)*(sc->stride)
|
|
+ (sc->depth/8) * (col + sc->xmargin);
|
|
|
|
fg = a & 0xf ;
|
|
bg = (a >> 4) & 0xf;
|
|
|
|
for (i = 0; i < VERSATILE_FONT_HEIGHT; i++) {
|
|
for (j = 0, k = 7; j < 8; j++, k--) {
|
|
if ((p[i] & (1 << k)) == 0)
|
|
color = bg;
|
|
else
|
|
color = fg;
|
|
|
|
switch (sc->depth) {
|
|
case 16:
|
|
rgb = (versatilefb_palette[color].r >> 3) << 11;
|
|
rgb |= (versatilefb_palette[color].g >> 2) << 5;
|
|
rgb |= (versatilefb_palette[color].b >> 3);
|
|
addr[2*j] = rgb & 0xff;
|
|
addr[2*j + 1] = (rgb >> 8) & 0xff;
|
|
default:
|
|
/* Not supported yet */
|
|
break;
|
|
}
|
|
}
|
|
|
|
addr += (sc->stride);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < len; i++)
|
|
versatilefb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
versatilefb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
|
|
uint32_t pixel_mask, int size, int width)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Define a stub keyboard driver in case one hasn't been
|
|
* compiled into the kernel
|
|
*/
|
|
#include <sys/kbio.h>
|
|
#include <dev/kbd/kbdreg.h>
|
|
|
|
static int dummy_kbd_configure(int flags);
|
|
|
|
keyboard_switch_t bcmdummysw;
|
|
|
|
static int
|
|
dummy_kbd_configure(int flags)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
KEYBOARD_DRIVER(bcmdummy, bcmdummysw, dummy_kbd_configure);
|