versatile_clcd.c revision 244755
1204076Spjd/* 2204076Spjd * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org> 3210886Spjd * All rights reserved. 4204076Spjd * 5204076Spjd * Redistribution and use in source and binary forms, with or without 6204076Spjd * modification, are permitted provided that the following conditions 7204076Spjd * are met: 8204076Spjd * 1. Redistributions of source code must retain the above copyright 9204076Spjd * notice, this list of conditions and the following disclaimer. 10204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 11204076Spjd * notice, this list of conditions and the following disclaimer in the 12204076Spjd * documentation and/or other materials provided with the distribution. 13204076Spjd * 14204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24204076Spjd * SUCH DAMAGE. 25204076Spjd */ 26204076Spjd 27204076Spjd#include <sys/cdefs.h> 28204076Spjd__FBSDID("$FreeBSD: head/sys/arm/versatile/versatile_clcd.c 244755 2012-12-28 00:55:43Z gonzo $"); 29204076Spjd 30204076Spjd#include <sys/param.h> 31204076Spjd#include <sys/systm.h> 32204076Spjd#include <sys/bus.h> 33204076Spjd#include <sys/kernel.h> 34204076Spjd#include <sys/module.h> 35204076Spjd#include <sys/malloc.h> 36204076Spjd#include <sys/rman.h> 37204076Spjd#include <sys/fbio.h> 38204076Spjd#include <sys/consio.h> 39204076Spjd#include <sys/kdb.h> 40204076Spjd 41204076Spjd#include <machine/bus.h> 42204076Spjd#include <machine/cpu.h> 43204076Spjd#include <machine/frame.h> 44204076Spjd#include <machine/intr.h> 45204076Spjd 46204076Spjd#include <dev/fdt/fdt_common.h> 47204076Spjd#include <dev/ofw/openfirm.h> 48204076Spjd#include <dev/ofw/ofw_bus.h> 49211982Spjd#include <dev/ofw/ofw_bus_subr.h> 50204076Spjd 51204076Spjd#include <dev/fb/fbreg.h> 52204076Spjd#include <dev/syscons/syscons.h> 53204076Spjd 54204076Spjd#include <machine/bus.h> 55204076Spjd#include <machine/fdt.h> 56204076Spjd 57204076Spjd#define PL110_VENDOR_ARM926PXP 1 58204076Spjd 59204076Spjd#define MEM_SYS 0 60204076Spjd#define MEM_CLCD 1 61212038Spjd#define MEM_REGIONS 2 62204076Spjd 63204076Spjd#define SYS_CLCD 0x00 64204076Spjd#define SYS_CLCD_CLCDID_SHIFT 0x08 65211886Spjd#define SYS_CLCD_CLCDID_MASK 0x1f 66204076Spjd#define SYS_CLCD_PWR3V5VSWITCH (1 << 4) 67204076Spjd#define SYS_CLCD_VDDPOSSWITCH (1 << 3) 68204076Spjd#define SYS_CLCD_NLCDIOON (1 << 2) 69204076Spjd#define SYS_CLCD_LCD_MODE_MASK 0x03 70204076Spjd 71204076Spjd#define CLCD_MODE_RGB888 0x0 72210886Spjd#define CLCD_MODE_RGB555 0x01 73210886Spjd#define CLCD_MODE_RBG565 0x02 74210886Spjd#define CLCD_MODE_RGB565 0x03 75204076Spjd 76204076Spjd#define CLCDC_TIMING0 0x00 77204076Spjd#define CLCDC_TIMING1 0x04 78204076Spjd#define CLCDC_TIMING2 0x08 79204076Spjd#define CLCDC_TIMING3 0x0C 80204076Spjd#define CLCDC_TIMING3 0x0C 81204076Spjd#define CLCDC_UPBASE 0x10 82204076Spjd#define CLCDC_LPBASE 0x14 83204076Spjd#ifdef PL110_VENDOR_ARM926PXP 84204076Spjd#define CLCDC_CONTROL 0x18 85204076Spjd#define CLCDC_IMSC 0x1C 86204076Spjd#else 87204076Spjd#define CLCDC_IMSC 0x18 88204076Spjd#define CLCDC_CONTROL 0x1C 89204076Spjd#endif 90204076Spjd#define CONTROL_WATERMARK (1 << 16) 91204076Spjd#define CONTROL_VCOMP_VS (0 << 12) 92204076Spjd#define CONTROL_VCOMP_BP (1 << 12) 93204076Spjd#define CONTROL_VCOMP_SAV (2 << 12) 94204076Spjd#define CONTROL_VCOMP_FP (3 << 12) 95204076Spjd#define CONTROL_PWR (1 << 11) 96204076Spjd#define CONTROL_BEPO (1 << 10) 97204076Spjd#define CONTROL_BEBO (1 << 9) 98204076Spjd#define CONTROL_BGR (1 << 8) 99204076Spjd#define CONTROL_DUAL (1 << 7) 100204076Spjd#define CONTROL_MONO8 (1 << 6) 101204076Spjd#define CONTROL_TFT (1 << 5) 102204076Spjd#define CONTROL_BW (1 << 4) 103204076Spjd#define CONTROL_BPP1 (0x00 << 1) 104204076Spjd#define CONTROL_BPP2 (0x01 << 1) 105204076Spjd#define CONTROL_BPP4 (0x02 << 1) 106204076Spjd#define CONTROL_BPP8 (0x03 << 1) 107204076Spjd#define CONTROL_BPP16 (0x04 << 1) 108204076Spjd#define CONTROL_BPP24 (0x05 << 1) 109204076Spjd#define CONTROL_EN (1 << 0) 110204076Spjd#define CLCDC_RIS 0x20 111204076Spjd#define CLCDC_MIS 0x24 112204076Spjd#define INTR_MBERR (1 << 4) 113204076Spjd#define INTR_VCOMP (1 << 3) 114204076Spjd#define INTR_LNB (1 << 2) 115204076Spjd#define INTR_FUF (1 << 1) 116204076Spjd#define CLCDC_ICR 0x28 117204076Spjd 118204076Spjd#ifdef DEBUG 119204076Spjd#define dprintf(fmt, args...) do { printf("%s(): ", __func__); \ 120204076Spjd printf(fmt,##args); } while (0) 121204076Spjd#else 122204076Spjd#define dprintf(fmt, args...) 123204076Spjd#endif 124204076Spjd 125204076Spjd#define versatile_clcdc_sys_read_4(sc, reg) \ 126204076Spjd bus_read_4((sc)->mem_res[MEM_SYS], (reg)) 127204076Spjd#define versatile_clcdc_sys_write_4(sc, reg, val) \ 128204076Spjd bus_write_4((sc)->mem_res[MEM_SYS], (reg), (val)) 129204076Spjd 130204076Spjd#define versatile_clcdc_read_4(sc, reg) \ 131204076Spjd bus_read_4((sc)->mem_res[MEM_CLCD], (reg)) 132204076Spjd#define versatile_clcdc_write_4(sc, reg, val) \ 133204076Spjd bus_write_4((sc)->mem_res[MEM_CLCD], (reg), (val)) 134204076Spjd 135204076Spjdstruct versatile_clcdc_softc { 136204076Spjd struct resource* mem_res[MEM_REGIONS]; 137204076Spjd 138204076Spjd struct mtx mtx; 139204076Spjd 140204076Spjd int width; 141204076Spjd int height; 142204076Spjd int mode; 143204076Spjd 144204076Spjd bus_dma_tag_t dma_tag; 145204076Spjd bus_dmamap_t dma_map; 146204076Spjd bus_addr_t fb_phys; 147204076Spjd uint8_t *fb_base; 148204076Spjd 149204076Spjd}; 150204076Spjd 151204076Spjdstruct video_adapter_softc { 152204076Spjd /* Videoadpater part */ 153204076Spjd video_adapter_t va; 154204076Spjd int console; 155211982Spjd 156204076Spjd intptr_t fb_addr; 157211982Spjd unsigned int fb_size; 158204076Spjd 159204076Spjd unsigned int height; 160204076Spjd unsigned int width; 161204076Spjd unsigned int depth; 162204076Spjd unsigned int stride; 163204076Spjd 164204076Spjd unsigned int xmargin; 165204076Spjd unsigned int ymargin; 166204076Spjd 167204076Spjd unsigned char *font; 168204076Spjd int initialized; 169204076Spjd}; 170204076Spjd 171204076Spjdstruct argb { 172204076Spjd uint8_t a; 173204076Spjd uint8_t r; 174204076Spjd uint8_t g; 175204076Spjd uint8_t b; 176204076Spjd}; 177204076Spjd 178204076Spjdstatic struct argb versatilefb_palette[16] = { 179204076Spjd {0x00, 0x00, 0x00, 0x00}, 180204076Spjd {0x00, 0x00, 0x00, 0xaa}, 181204076Spjd {0x00, 0x00, 0xaa, 0x00}, 182204076Spjd {0x00, 0x00, 0xaa, 0xaa}, 183214692Spjd {0x00, 0xaa, 0x00, 0x00}, 184214692Spjd {0x00, 0xaa, 0x00, 0xaa}, 185214692Spjd {0x00, 0xaa, 0x55, 0x00}, 186204076Spjd {0x00, 0xaa, 0xaa, 0xaa}, 187214692Spjd {0x00, 0x55, 0x55, 0x55}, 188214692Spjd {0x00, 0x55, 0x55, 0xff}, 189214692Spjd {0x00, 0x55, 0xff, 0x55}, 190214692Spjd {0x00, 0x55, 0xff, 0xff}, 191214692Spjd {0x00, 0xff, 0x55, 0x55}, 192214692Spjd {0x00, 0xff, 0x55, 0xff}, 193204076Spjd {0x00, 0xff, 0xff, 0x55}, 194214692Spjd {0x00, 0xff, 0xff, 0xff} 195214692Spjd}; 196214692Spjd 197214692Spjd/* mouse pointer from dev/syscons/scgfbrndr.c */ 198204076Spjdstatic u_char mouse_pointer[16] = { 199204076Spjd 0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68, 200204076Spjd 0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00 201204076Spjd}; 202204076Spjd 203204076Spjd#define FB_WIDTH 640 204204076Spjd#define FB_HEIGHT 480 205204076Spjd#define FB_DEPTH 16 206204076Spjd 207204076Spjd#define VERSATILE_FONT_HEIGHT 16 208204076Spjd 209204076Spjdstatic struct video_adapter_softc va_softc; 210209183Spjd 211209183Spjdstatic struct resource_spec versatile_clcdc_mem_spec[] = { 212209183Spjd { SYS_RES_MEMORY, 0, RF_ACTIVE }, 213209183Spjd { SYS_RES_MEMORY, 1, RF_ACTIVE }, 214204076Spjd { -1, 0, 0 } 215204076Spjd}; 216204076Spjd 217204076Spjdstatic int versatilefb_configure(int); 218204076Spjdstatic void versatilefb_update_margins(video_adapter_t *adp); 219204076Spjd 220204076Spjdstatic void 221204076Spjdversatile_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 222204076Spjd{ 223204076Spjd bus_addr_t *addr; 224204076Spjd 225204076Spjd if (err) 226204076Spjd return; 227204076Spjd 228204076Spjd addr = (bus_addr_t*)arg; 229204076Spjd *addr = segs[0].ds_addr; 230204076Spjd} 231204076Spjd 232204076Spjdstatic int 233204076Spjdversatile_clcdc_probe(device_t dev) 234204076Spjd{ 235204076Spjd 236211982Spjd if (ofw_bus_is_compatible(dev, "arm,pl110")) { 237204076Spjd device_set_desc(dev, "PL110 CLCD controller"); 238204076Spjd return (BUS_PROBE_DEFAULT); 239204076Spjd } 240204076Spjd 241204076Spjd return (ENXIO); 242204076Spjd} 243204076Spjd 244204076Spjdstatic int 245204076Spjdversatile_clcdc_attach(device_t dev) 246204076Spjd{ 247204076Spjd struct versatile_clcdc_softc *sc = device_get_softc(dev); 248213533Spjd struct video_adapter_softc *va_sc = &va_softc; 249204076Spjd int err; 250204076Spjd uint32_t reg; 251204076Spjd int clcdid; 252204076Spjd int dma_size; 253213531Spjd 254213531Spjd /* Request memory resources */ 255204076Spjd err = bus_alloc_resources(dev, versatile_clcdc_mem_spec, 256204076Spjd sc->mem_res); 257204076Spjd if (err) { 258204076Spjd device_printf(dev, "Error: could not allocate memory resources\n"); 259204076Spjd return (ENXIO); 260204076Spjd } 261204076Spjd 262204076Spjd reg = versatile_clcdc_sys_read_4(sc, SYS_CLCD); 263204076Spjd clcdid = (reg >> SYS_CLCD_CLCDID_SHIFT) & SYS_CLCD_CLCDID_MASK; 264212899Spjd switch (clcdid) { 265204076Spjd case 31: 266204076Spjd device_printf(dev, "QEMU VGA 640x480\n"); 267204076Spjd sc->width = 640; 268204076Spjd sc->height = 480; 269204076Spjd break; 270204076Spjd default: 271204076Spjd device_printf(dev, "Unsupported: %d\n", clcdid); 272204076Spjd goto fail; 273204076Spjd } 274204076Spjd 275204076Spjd reg &= ~SYS_CLCD_LCD_MODE_MASK; 276204076Spjd reg |= CLCD_MODE_RGB565; 277212899Spjd sc->mode = CLCD_MODE_RGB565; 278204076Spjd versatile_clcdc_sys_write_4(sc, SYS_CLCD, reg); 279204076Spjd dma_size = sc->width*sc->height*2; 280204076Spjd 281204076Spjd /* 282204076Spjd * Power on LCD 283204076Spjd */ 284204076Spjd reg |= SYS_CLCD_PWR3V5VSWITCH | SYS_CLCD_NLCDIOON; 285204076Spjd versatile_clcdc_sys_write_4(sc, SYS_CLCD, reg); 286204076Spjd 287204076Spjd /* 288204076Spjd * XXX: hardcoded timing for VGA. For other modes/panels 289204076Spjd * we need to keep table of timing register values 290204076Spjd */ 291204076Spjd /* 292204076Spjd * XXX: set SYS_OSC1 293204076Spjd */ 294204076Spjd versatile_clcdc_write_4(sc, CLCDC_TIMING0, 0x3F1F3F9C); 295204076Spjd versatile_clcdc_write_4(sc, CLCDC_TIMING1, 0x090B61DF); 296204076Spjd versatile_clcdc_write_4(sc, CLCDC_TIMING2, 0x067F1800); 297204076Spjd /* XXX: timing 3? */ 298204076Spjd 299204076Spjd /* 300204076Spjd * Now allocate framebuffer memory 301204076Spjd */ 302204076Spjd err = bus_dma_tag_create( 303204076Spjd bus_get_dma_tag(dev), 304204076Spjd 4, 0, /* alignment, boundary */ 305204076Spjd BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 306204076Spjd BUS_SPACE_MAXADDR, /* highaddr */ 307210881Spjd NULL, NULL, /* filter, filterarg */ 308210881Spjd dma_size, 1, /* maxsize, nsegments */ 309210881Spjd dma_size, 0, /* maxsegsize, flags */ 310210881Spjd NULL, NULL, /* lockfunc, lockarg */ 311210881Spjd &sc->dma_tag); 312210881Spjd 313210881Spjd err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_base, 314204076Spjd 0, &sc->dma_map); 315204076Spjd if (err) { 316204076Spjd device_printf(dev, "cannot allocate framebuffer\n"); 317204076Spjd goto fail; 318204076Spjd } 319204076Spjd 320204076Spjd err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_base, 321204076Spjd dma_size, versatile_fb_dmamap_cb, &sc->fb_phys, BUS_DMA_NOWAIT); 322204076Spjd 323204076Spjd if (err) { 324204076Spjd device_printf(dev, "cannot load DMA map\n"); 325204076Spjd goto fail; 326204076Spjd } 327204076Spjd 328204076Spjd /* Make sure it's blank */ 329204076Spjd memset(sc->fb_base, 0x00, dma_size); 330204076Spjd 331204076Spjd versatile_clcdc_write_4(sc, CLCDC_UPBASE, sc->fb_phys); 332204076Spjd 333204076Spjd err = (sc_attach_unit(device_get_unit(dev), 334204076Spjd device_get_flags(dev) | SC_AUTODETECT_KBD)); 335204076Spjd 336204076Spjd if (err) { 337204076Spjd device_printf(dev, "failed to attach syscons\n"); 338204076Spjd goto fail; 339204076Spjd } 340204076Spjd 341204076Spjd /* 342204076Spjd * XXX: hardcoded for VGA 343204076Spjd */ 344204076Spjd reg = CONTROL_VCOMP_BP | CONTROL_TFT | CONTROL_BGR | CONTROL_EN; 345204076Spjd reg |= CONTROL_BPP16; 346204076Spjd versatile_clcdc_write_4(sc, CLCDC_CONTROL, reg); 347204076Spjd DELAY(20); 348204076Spjd reg |= CONTROL_PWR; 349204076Spjd versatile_clcdc_write_4(sc, CLCDC_CONTROL, reg); 350204076Spjd 351204076Spjd va_sc->fb_addr = (vm_offset_t)sc->fb_base; 352204076Spjd va_sc->fb_size = dma_size; 353204076Spjd va_sc->width = sc->width; 354204076Spjd va_sc->height = sc->height; 355204076Spjd va_sc->depth = 16; 356204076Spjd va_sc->stride = sc->width * 2; 357204076Spjd versatilefb_update_margins(&va_sc->va); 358204076Spjd 359204076Spjd return (0); 360204076Spjd 361204076Spjdfail: 362204076Spjd if (sc->fb_base) 363204076Spjd bus_dmamem_free(sc->dma_tag, sc->fb_base, sc->dma_map); 364204076Spjd if (sc->dma_map) 365204076Spjd bus_dmamap_destroy(sc->dma_tag, sc->dma_map); 366204076Spjd if (sc->dma_tag) 367204076Spjd bus_dma_tag_destroy(sc->dma_tag); 368204076Spjd return (err); 369204076Spjd} 370204076Spjd 371204076Spjdstatic device_method_t versatile_clcdc_methods[] = { 372204076Spjd DEVMETHOD(device_probe, versatile_clcdc_probe), 373204076Spjd DEVMETHOD(device_attach, versatile_clcdc_attach), 374204076Spjd 375204076Spjd DEVMETHOD_END 376204076Spjd}; 377204076Spjd 378204076Spjdstatic driver_t versatile_clcdc_driver = { 379204076Spjd "clcdc", 380204076Spjd versatile_clcdc_methods, 381204076Spjd sizeof(struct versatile_clcdc_softc), 382204076Spjd}; 383204076Spjd 384204076Spjdstatic devclass_t versatile_clcdc_devclass; 385204076Spjd 386204076SpjdDRIVER_MODULE(versatile_clcdc, simplebus, versatile_clcdc_driver, versatile_clcdc_devclass, 0, 0); 387204076Spjd 388204076Spjd/* 389204076Spjd * Video driver routines and glue. 390204076Spjd */ 391204076Spjdstatic vi_probe_t versatilefb_probe; 392204076Spjdstatic vi_init_t versatilefb_init; 393204076Spjdstatic vi_get_info_t versatilefb_get_info; 394204076Spjdstatic vi_query_mode_t versatilefb_query_mode; 395204076Spjdstatic vi_set_mode_t versatilefb_set_mode; 396204076Spjdstatic vi_save_font_t versatilefb_save_font; 397204076Spjdstatic vi_load_font_t versatilefb_load_font; 398204076Spjdstatic vi_show_font_t versatilefb_show_font; 399204076Spjdstatic vi_save_palette_t versatilefb_save_palette; 400204076Spjdstatic vi_load_palette_t versatilefb_load_palette; 401204076Spjdstatic vi_set_border_t versatilefb_set_border; 402204076Spjdstatic vi_save_state_t versatilefb_save_state; 403204076Spjdstatic vi_load_state_t versatilefb_load_state; 404204076Spjdstatic vi_set_win_org_t versatilefb_set_win_org; 405204076Spjdstatic vi_read_hw_cursor_t versatilefb_read_hw_cursor; 406204076Spjdstatic vi_set_hw_cursor_t versatilefb_set_hw_cursor; 407204076Spjdstatic vi_set_hw_cursor_shape_t versatilefb_set_hw_cursor_shape; 408204076Spjdstatic vi_blank_display_t versatilefb_blank_display; 409204076Spjdstatic vi_mmap_t versatilefb_mmap; 410204076Spjdstatic vi_ioctl_t versatilefb_ioctl; 411204076Spjdstatic vi_clear_t versatilefb_clear; 412204076Spjdstatic vi_fill_rect_t versatilefb_fill_rect; 413204076Spjdstatic vi_bitblt_t versatilefb_bitblt; 414204076Spjdstatic vi_diag_t versatilefb_diag; 415204076Spjdstatic vi_save_cursor_palette_t versatilefb_save_cursor_palette; 416204076Spjdstatic vi_load_cursor_palette_t versatilefb_load_cursor_palette; 417204076Spjdstatic vi_copy_t versatilefb_copy; 418204076Spjdstatic vi_putp_t versatilefb_putp; 419204076Spjdstatic vi_putc_t versatilefb_putc; 420204076Spjdstatic vi_puts_t versatilefb_puts; 421204076Spjdstatic vi_putm_t versatilefb_putm; 422204076Spjd 423204076Spjdstatic video_switch_t versatilefbvidsw = { 424204076Spjd .probe = versatilefb_probe, 425204076Spjd .init = versatilefb_init, 426204076Spjd .get_info = versatilefb_get_info, 427214284Spjd .query_mode = versatilefb_query_mode, 428214284Spjd .set_mode = versatilefb_set_mode, 429214284Spjd .save_font = versatilefb_save_font, 430214284Spjd .load_font = versatilefb_load_font, 431214284Spjd .show_font = versatilefb_show_font, 432214284Spjd .save_palette = versatilefb_save_palette, 433214284Spjd .load_palette = versatilefb_load_palette, 434214284Spjd .set_border = versatilefb_set_border, 435214284Spjd .save_state = versatilefb_save_state, 436214284Spjd .load_state = versatilefb_load_state, 437214284Spjd .set_win_org = versatilefb_set_win_org, 438214284Spjd .read_hw_cursor = versatilefb_read_hw_cursor, 439214284Spjd .set_hw_cursor = versatilefb_set_hw_cursor, 440214284Spjd .set_hw_cursor_shape = versatilefb_set_hw_cursor_shape, 441214284Spjd .blank_display = versatilefb_blank_display, 442214284Spjd .mmap = versatilefb_mmap, 443214284Spjd .ioctl = versatilefb_ioctl, 444214284Spjd .clear = versatilefb_clear, 445204076Spjd .fill_rect = versatilefb_fill_rect, 446204076Spjd .bitblt = versatilefb_bitblt, 447204076Spjd .diag = versatilefb_diag, 448204076Spjd .save_cursor_palette = versatilefb_save_cursor_palette, 449204076Spjd .load_cursor_palette = versatilefb_load_cursor_palette, 450204076Spjd .copy = versatilefb_copy, 451204076Spjd .putp = versatilefb_putp, 452204076Spjd .putc = versatilefb_putc, 453204076Spjd .puts = versatilefb_puts, 454204076Spjd .putm = versatilefb_putm, 455204076Spjd}; 456204076Spjd 457204076SpjdVIDEO_DRIVER(versatilefb, versatilefbvidsw, versatilefb_configure); 458204076Spjd 459204076Spjdstatic vr_init_t clcdr_init; 460204076Spjdstatic vr_clear_t clcdr_clear; 461204076Spjdstatic vr_draw_border_t clcdr_draw_border; 462204076Spjdstatic vr_draw_t clcdr_draw; 463204076Spjdstatic vr_set_cursor_t clcdr_set_cursor; 464204076Spjdstatic vr_draw_cursor_t clcdr_draw_cursor; 465204076Spjdstatic vr_blink_cursor_t clcdr_blink_cursor; 466204076Spjdstatic vr_set_mouse_t clcdr_set_mouse; 467204076Spjdstatic vr_draw_mouse_t clcdr_draw_mouse; 468204076Spjd 469204076Spjd/* 470204076Spjd * We use our own renderer; this is because we must emulate a hardware 471204076Spjd * cursor. 472204076Spjd */ 473204076Spjdstatic sc_rndr_sw_t clcdrend = { 474204076Spjd clcdr_init, 475204076Spjd clcdr_clear, 476209181Spjd clcdr_draw_border, 477204076Spjd clcdr_draw, 478204076Spjd clcdr_set_cursor, 479204076Spjd clcdr_draw_cursor, 480214284Spjd clcdr_blink_cursor, 481214284Spjd clcdr_set_mouse, 482214284Spjd clcdr_draw_mouse 483214284Spjd}; 484214284Spjd 485204076SpjdRENDERER(versatilefb, 0, clcdrend, gfb_set); 486204076SpjdRENDERER_MODULE(versatilefb, gfb_set); 487204076Spjd 488204076Spjdstatic void 489204076Spjdclcdr_init(scr_stat* scp) 490204076Spjd{ 491204076Spjd} 492205738Spjd 493205738Spjdstatic void 494205738Spjdclcdr_clear(scr_stat* scp, int c, int attr) 495204076Spjd{ 496205738Spjd} 497204076Spjd 498204076Spjdstatic void 499204076Spjdclcdr_draw_border(scr_stat* scp, int color) 500204076Spjd{ 501204076Spjd} 502204076Spjd 503204076Spjdstatic void 504204076Spjdclcdr_draw(scr_stat* scp, int from, int count, int flip) 505204076Spjd{ 506205738Spjd video_adapter_t* adp = scp->sc->adp; 507210881Spjd int i, c, a; 508205738Spjd 509205738Spjd if (!flip) { 510211983Spjd /* Normal printing */ 511205738Spjd vidd_puts(adp, from, (uint16_t*)sc_vtb_pointer(&scp->vtb, from), count); 512204076Spjd } else { 513205738Spjd /* This is for selections and such: invert the color attribute */ 514215331Spjd for (i = count; i-- > 0; ++from) { 515215331Spjd c = sc_vtb_getc(&scp->vtb, from); 516204076Spjd a = sc_vtb_geta(&scp->vtb, from) >> 8; 517204076Spjd vidd_putc(adp, from, c, (a >> 4) | ((a & 0xf) << 4)); 518204076Spjd } 519205738Spjd } 520204076Spjd} 521204076Spjd 522204076Spjdstatic void 523204076Spjdclcdr_set_cursor(scr_stat* scp, int base, int height, int blink) 524207371Spjd{ 525207371Spjd} 526207371Spjd 527204076Spjdstatic void 528204076Spjdclcdr_draw_cursor(scr_stat* scp, int off, int blink, int on, int flip) 529204076Spjd{ 530204076Spjd video_adapter_t* adp = scp->sc->adp; 531204076Spjd struct video_adapter_softc *sc; 532204076Spjd int row, col; 533204076Spjd uint8_t *addr; 534204076Spjd int i,j; 535204076Spjd 536204076Spjd sc = (struct video_adapter_softc *)adp; 537204076Spjd 538204076Spjd if (scp->curs_attr.height <= 0) 539204076Spjd return; 540205738Spjd 541204076Spjd if (sc->fb_addr == 0) 542204076Spjd return; 543204076Spjd 544204076Spjd if (off >= adp->va_info.vi_width * adp->va_info.vi_height) 545204076Spjd return; 546204076Spjd 547204076Spjd /* calculate the coordinates in the video buffer */ 548205738Spjd row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight; 549204076Spjd col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth; 550204076Spjd 551204076Spjd addr = (uint8_t *)sc->fb_addr 552204076Spjd + (row + sc->ymargin)*(sc->stride) 553204076Spjd + (sc->depth/8) * (col + sc->xmargin); 554204076Spjd 555204076Spjd /* our cursor consists of simply inverting the char under it */ 556204076Spjd for (i = 0; i < adp->va_info.vi_cheight; i++) { 557204076Spjd for (j = 0; j < adp->va_info.vi_cwidth; j++) { 558204076Spjd 559204076Spjd addr[2*j] ^= 0xff; 560204076Spjd addr[2*j + 1] ^= 0xff; 561204076Spjd } 562204076Spjd 563204076Spjd addr += sc->stride; 564204076Spjd } 565204076Spjd} 566204076Spjd 567204076Spjdstatic void 568204076Spjdclcdr_blink_cursor(scr_stat* scp, int at, int flip) 569204076Spjd{ 570204076Spjd} 571204076Spjd 572204076Spjdstatic void 573204076Spjdclcdr_set_mouse(scr_stat* scp) 574204076Spjd{ 575204076Spjd} 576204076Spjd 577204076Spjdstatic void 578204076Spjdclcdr_draw_mouse(scr_stat* scp, int x, int y, int on) 579204076Spjd{ 580205738Spjd vidd_putm(scp->sc->adp, x, y, mouse_pointer, 0xffffffff, 16, 8); 581215331Spjd 582215331Spjd} 583204076Spjd 584204076Spjdstatic uint16_t versatilefb_static_window[ROW*COL]; 585204076Spjdextern u_char dflt_font_16[]; 586205738Spjd 587204076Spjd/* 588204076Spjd * Update videoadapter settings after changing resolution 589204076Spjd */ 590204076Spjdstatic void 591207371Spjdversatilefb_update_margins(video_adapter_t *adp) 592207371Spjd{ 593207371Spjd struct video_adapter_softc *sc; 594204076Spjd video_info_t *vi; 595204076Spjd 596204076Spjd sc = (struct video_adapter_softc *)adp; 597204076Spjd vi = &adp->va_info; 598214284Spjd 599214284Spjd sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2; 600214284Spjd sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2; 601214284Spjd} 602214284Spjd 603214284Spjdstatic int 604214284Spjdversatilefb_configure(int flags) 605214284Spjd{ 606214284Spjd struct video_adapter_softc *va_sc; 607214284Spjd 608214284Spjd va_sc = &va_softc; 609214284Spjd 610214284Spjd if (va_sc->initialized) 611204076Spjd return (0); 612204076Spjd 613204076Spjd va_sc->width = FB_WIDTH; 614204076Spjd va_sc->height = FB_HEIGHT; 615204076Spjd va_sc->depth = FB_DEPTH; 616204076Spjd 617204076Spjd versatilefb_init(0, &va_sc->va, 0); 618204076Spjd 619204076Spjd va_sc->initialized = 1; 620204076Spjd 621205738Spjd return (0); 622204076Spjd} 623204076Spjd 624204076Spjdstatic int 625204076Spjdversatilefb_probe(int unit, video_adapter_t **adp, void *arg, int flags) 626204076Spjd{ 627204076Spjd 628204076Spjd return (0); 629205738Spjd} 630204076Spjd 631204076Spjdstatic int 632204076Spjdversatilefb_init(int unit, video_adapter_t *adp, int flags) 633204076Spjd{ 634204076Spjd struct video_adapter_softc *sc; 635204076Spjd video_info_t *vi; 636204076Spjd 637204076Spjd sc = (struct video_adapter_softc *)adp; 638204076Spjd vi = &adp->va_info; 639204076Spjd 640204076Spjd vid_init_struct(adp, "versatilefb", -1, unit); 641204076Spjd 642204076Spjd sc->font = dflt_font_16; 643204076Spjd vi->vi_cheight = VERSATILE_FONT_HEIGHT; 644204076Spjd vi->vi_cwidth = 8; 645204076Spjd 646204076Spjd vi->vi_width = sc->width/8; 647204076Spjd vi->vi_height = sc->height/vi->vi_cheight; 648204076Spjd 649204076Spjd /* 650204076Spjd * Clamp width/height to syscons maximums 651204076Spjd */ 652204076Spjd if (vi->vi_width > COL) 653204076Spjd vi->vi_width = COL; 654204076Spjd if (vi->vi_height > ROW) 655204076Spjd vi->vi_height = ROW; 656204076Spjd 657204076Spjd sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2; 658204076Spjd sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2; 659204076Spjd 660204076Spjd 661204076Spjd adp->va_window = (vm_offset_t) versatilefb_static_window; 662204076Spjd adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */; 663204076Spjd 664204076Spjd vid_register(&sc->va); 665204076Spjd 666204076Spjd return (0); 667204076Spjd} 668204076Spjd 669204076Spjdstatic int 670204076Spjdversatilefb_get_info(video_adapter_t *adp, int mode, video_info_t *info) 671204076Spjd{ 672205738Spjd bcopy(&adp->va_info, info, sizeof(*info)); 673204076Spjd return (0); 674204076Spjd} 675204076Spjd 676204076Spjdstatic int 677204076Spjdversatilefb_query_mode(video_adapter_t *adp, video_info_t *info) 678204076Spjd{ 679204076Spjd return (0); 680204076Spjd} 681204076Spjd 682204076Spjdstatic int 683204076Spjdversatilefb_set_mode(video_adapter_t *adp, int mode) 684204076Spjd{ 685204076Spjd return (0); 686204076Spjd} 687204076Spjd 688204076Spjdstatic int 689204076Spjdversatilefb_save_font(video_adapter_t *adp, int page, int size, int width, 690204076Spjd u_char *data, int c, int count) 691214274Spjd{ 692204076Spjd return (0); 693205738Spjd} 694205738Spjd 695205738Spjdstatic int 696205738Spjdversatilefb_load_font(video_adapter_t *adp, int page, int size, int width, 697205738Spjd u_char *data, int c, int count) 698205738Spjd{ 699205738Spjd struct video_adapter_softc *sc = (struct video_adapter_softc *)adp; 700212038Spjd 701205738Spjd sc->font = data; 702205738Spjd 703211983Spjd return (0); 704212038Spjd} 705205738Spjd 706205738Spjdstatic int 707205738Spjdversatilefb_show_font(video_adapter_t *adp, int page) 708205738Spjd{ 709205738Spjd return (0); 710205738Spjd} 711205738Spjd 712205738Spjdstatic int 713205738Spjdversatilefb_save_palette(video_adapter_t *adp, u_char *palette) 714205738Spjd{ 715204076Spjd return (0); 716204076Spjd} 717204076Spjd 718204076Spjdstatic int 719204076Spjdversatilefb_load_palette(video_adapter_t *adp, u_char *palette) 720204076Spjd{ 721204076Spjd return (0); 722211878Spjd} 723211878Spjd 724211878Spjdstatic int 725211878Spjdversatilefb_set_border(video_adapter_t *adp, int border) 726211878Spjd{ 727211878Spjd return (versatilefb_blank_display(adp, border)); 728211878Spjd} 729211878Spjd 730211878Spjdstatic int 731211878Spjdversatilefb_save_state(video_adapter_t *adp, void *p, size_t size) 732204076Spjd{ 733204076Spjd return (0); 734204076Spjd} 735204076Spjd 736204076Spjdstatic int 737204076Spjdversatilefb_load_state(video_adapter_t *adp, void *p) 738204076Spjd{ 739204076Spjd return (0); 740204076Spjd} 741204076Spjd 742204076Spjdstatic int 743204076Spjdversatilefb_set_win_org(video_adapter_t *adp, off_t offset) 744204076Spjd{ 745204076Spjd return (0); 746204076Spjd} 747213533Spjd 748204076Spjdstatic int 749204076Spjdversatilefb_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 750204076Spjd{ 751204076Spjd *col = *row = 0; 752206669Spjd 753204076Spjd return (0); 754204076Spjd} 755204076Spjd 756204076Spjdstatic int 757204076Spjdversatilefb_set_hw_cursor(video_adapter_t *adp, int col, int row) 758204076Spjd{ 759204076Spjd 760204076Spjd return (0); 761204076Spjd} 762204076Spjd 763204076Spjdstatic int 764204076Spjdversatilefb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 765204076Spjd int celsize, int blink) 766204076Spjd{ 767204076Spjd return (0); 768204076Spjd} 769204076Spjd 770204076Spjdstatic int 771204076Spjdversatilefb_blank_display(video_adapter_t *adp, int mode) 772204076Spjd{ 773204076Spjd 774213533Spjd struct video_adapter_softc *sc; 775204076Spjd 776204076Spjd sc = (struct video_adapter_softc *)adp; 777204076Spjd if (sc && sc->fb_addr) 778204076Spjd memset((void*)sc->fb_addr, 0, sc->fb_size); 779204076Spjd 780204076Spjd return (0); 781204076Spjd} 782204076Spjd 783204076Spjdstatic int 784204076Spjdversatilefb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, 785204076Spjd int prot, vm_memattr_t *memattr) 786204076Spjd{ 787204076Spjd struct video_adapter_softc *sc; 788204076Spjd 789204076Spjd sc = (struct video_adapter_softc *)adp; 790204076Spjd 791204076Spjd /* 792204076Spjd * This might be a legacy VGA mem request: if so, just point it at the 793218043Spjd * framebuffer, since it shouldn't be touched 794204076Spjd */ 795204076Spjd if (offset < sc->stride*sc->height) { 796204076Spjd *paddr = sc->fb_addr + offset; 797204076Spjd return (0); 798204076Spjd } 799218042Spjd 800204076Spjd return (EINVAL); 801212034Spjd} 802204076Spjd 803204076Spjdstatic int 804212038Spjdversatilefb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data) 805212038Spjd{ 806212038Spjd 807212038Spjd return (0); 808218042Spjd} 809212038Spjd 810212038Spjdstatic int 811212038Spjdversatilefb_clear(video_adapter_t *adp) 812212038Spjd{ 813204076Spjd 814204076Spjd return (versatilefb_blank_display(adp, 0)); 815204076Spjd} 816218042Spjd 817204076Spjdstatic int 818212034Spjdversatilefb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 819204076Spjd{ 820204076Spjd 821204076Spjd return (0); 822204076Spjd} 823212038Spjd 824212038Spjdstatic int 825218043Spjdversatilefb_bitblt(video_adapter_t *adp, ...) 826218043Spjd{ 827204076Spjd 828204076Spjd return (0); 829204076Spjd} 830211977Spjd 831211984Spjdstatic int 832218043Spjdversatilefb_diag(video_adapter_t *adp, int level) 833211984Spjd{ 834218043Spjd 835218043Spjd return (0); 836218043Spjd} 837218043Spjd 838218043Spjdstatic int 839204076Spjdversatilefb_save_cursor_palette(video_adapter_t *adp, u_char *palette) 840218043Spjd{ 841218043Spjd 842204076Spjd return (0); 843204076Spjd} 844204076Spjd 845213007Spjdstatic int 846213007Spjdversatilefb_load_cursor_palette(video_adapter_t *adp, u_char *palette) 847217784Spjd{ 848213007Spjd 849213530Spjd return (0); 850213530Spjd} 851213530Spjd 852213530Spjdstatic int 853213530Spjdversatilefb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n) 854213530Spjd{ 855213007Spjd 856213007Spjd return (0); 857213007Spjd} 858213007Spjd 859213007Spjdstatic int 860213007Spjdversatilefb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a, 861213007Spjd int size, int bpp, int bit_ltor, int byte_ltor) 862213007Spjd{ 863213007Spjd 864210881Spjd return (0); 865205738Spjd} 866204076Spjd 867204076Spjdstatic int 868204076Spjdversatilefb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a) 869204076Spjd{ 870204076Spjd struct video_adapter_softc *sc; 871204076Spjd int row; 872204076Spjd int col; 873204076Spjd int i, j, k; 874204076Spjd uint8_t *addr; 875204076Spjd u_char *p; 876213530Spjd uint8_t fg, bg, color; 877204076Spjd uint16_t rgb; 878204076Spjd 879204076Spjd sc = (struct video_adapter_softc *)adp; 880204076Spjd 881204076Spjd if (sc->fb_addr == 0) 882204076Spjd return (0); 883204076Spjd 884204076Spjd if (off >= adp->va_info.vi_width * adp->va_info.vi_height) 885204076Spjd return (0); 886204076Spjd 887204076Spjd row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight; 888204076Spjd col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth; 889204076Spjd p = sc->font + c*VERSATILE_FONT_HEIGHT; 890204076Spjd addr = (uint8_t *)sc->fb_addr 891204076Spjd + (row + sc->ymargin)*(sc->stride) 892204076Spjd + (sc->depth/8) * (col + sc->xmargin); 893204076Spjd 894204076Spjd fg = a & 0xf ; 895204076Spjd bg = (a >> 8) & 0xf; 896204076Spjd 897204076Spjd for (i = 0; i < VERSATILE_FONT_HEIGHT; i++) { 898204076Spjd for (j = 0, k = 7; j < 8; j++, k--) { 899204076Spjd if ((p[i] & (1 << k)) == 0) 900204076Spjd color = bg; 901204076Spjd else 902204076Spjd color = fg; 903204076Spjd 904204076Spjd switch (sc->depth) { 905204076Spjd case 16: 906204076Spjd rgb = (versatilefb_palette[color].r >> 3) << 11; 907204076Spjd rgb |= (versatilefb_palette[color].g >> 2) << 5; 908204076Spjd rgb |= (versatilefb_palette[color].b >> 3); 909204076Spjd addr[2*j] = rgb & 0xff; 910204076Spjd addr[2*j + 1] = (rgb >> 8) & 0xff; 911204076Spjd default: 912204076Spjd /* Not supported yet */ 913204076Spjd break; 914204076Spjd } 915204076Spjd } 916204076Spjd 917204076Spjd addr += (sc->stride); 918204076Spjd } 919204076Spjd 920204076Spjd return (0); 921204076Spjd} 922204076Spjd 923204076Spjdstatic int 924204076Spjdversatilefb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len) 925204076Spjd{ 926204076Spjd int i; 927204076Spjd 928204076Spjd for (i = 0; i < len; i++) 929204076Spjd versatilefb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8); 930204076Spjd 931204076Spjd return (0); 932204076Spjd} 933204076Spjd 934204076Spjdstatic int 935204076Spjdversatilefb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image, 936204076Spjd uint32_t pixel_mask, int size, int width) 937211881Spjd{ 938204076Spjd 939204076Spjd return (0); 940204076Spjd} 941211881Spjd 942204076Spjd/* 943204076Spjd * Define a stub keyboard driver in case one hasn't been 944204076Spjd * compiled into the kernel 945204076Spjd */ 946204076Spjd#include <sys/kbio.h> 947204076Spjd#include <dev/kbd/kbdreg.h> 948211881Spjd 949211881Spjdstatic int dummy_kbd_configure(int flags); 950204076Spjd 951204076Spjdkeyboard_switch_t bcmdummysw; 952204076Spjd 953211878Spjdstatic int 954211984Spjddummy_kbd_configure(int flags) 955212038Spjd{ 956204076Spjd 957204076Spjd return (0); 958204076Spjd} 959204076SpjdKEYBOARD_DRIVER(bcmdummy, bcmdummysw, dummy_kbd_configure); 960204076Spjd