133965Sjdp/* $NetBSD: vidcvideo.c,v 1.50 2022/09/27 06:36:42 skrll Exp $ */ 2218822Sdim 3218822Sdim/* 433965Sjdp * Copyright (c) 2001 Reinoud Zandijk 533965Sjdp * Copyright (c) 1998, 1999 Tohru Nishimura. All rights reserved. 633965Sjdp * 733965Sjdp * Redistribution and use in source and binary forms, with or without 833965Sjdp * modification, are permitted provided that the following conditions 933965Sjdp * are met: 1033965Sjdp * 1. Redistributions of source code must retain the above copyright 1133965Sjdp * notice, this list of conditions and the following disclaimer. 1233965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1333965Sjdp * notice, this list of conditions and the following disclaimer in the 1433965Sjdp * documentation and/or other materials provided with the distribution. 1533965Sjdp * 1633965Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1733965Sjdp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1833965Sjdp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19218822Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20218822Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2133965Sjdp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2233965Sjdp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2333965Sjdp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24130561Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25130561Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26130561Sobrien * 27130561Sobrien * Created vidcvideo.c from /dev/tc/cfb.c to fit the Acorn/ARM VIDC1 and VIDC20 chips 2833965Sjdp * 2977298Sobrien */ 30130561Sobrien 3133965Sjdp#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 32130561Sobrien 33130561Sobrien__KERNEL_RCSID(0, "$NetBSD: vidcvideo.c,v 1.50 2022/09/27 06:36:42 skrll Exp $"); 34130561Sobrien 35130561Sobrien#include <sys/param.h> 36130561Sobrien#include <sys/systm.h> 37130561Sobrien#include <sys/kernel.h> 38130561Sobrien#include <sys/device.h> 39130561Sobrien#include <sys/buf.h> 40130561Sobrien#include <sys/ioctl.h> 41130561Sobrien 42130561Sobrien#include <arm/mainbus/mainbus.h> 43130561Sobrien#include <sys/bus.h> 44130561Sobrien#include <machine/intr.h> 45130561Sobrien 46130561Sobrien#include <dev/wscons/wsconsio.h> 47130561Sobrien#include <dev/wscons/wsdisplayvar.h> 48130561Sobrien 49130561Sobrien#include <dev/rasops/rasops.h> 50130561Sobrien#include <dev/wsfont/wsfont.h> 51130561Sobrien 52130561Sobrien#include <dev/wscons/wsdisplay_vconsvar.h> 53130561Sobrien 54130561Sobrien#include <uvm/uvm_extern.h> 55130561Sobrien#include <arm/arm32/pmap.h> 56130561Sobrien#include <arm/cpufunc.h> 57130561Sobrien 58130561Sobrien/* for vidc_mode ... needs to be MI independent one day */ 59130561Sobrien#include <arm/iomd/vidc.h> 60130561Sobrien#include <arm/iomd/vidc20config.h> 61130561Sobrien#include <arm/iomd/vidcvideo.h> 62130561Sobrien#include <machine/bootconfig.h> 63130561Sobrien 64130561Sobrien/* FOR DEBUG */ 6533965Sjdpextern videomemory_t videomemory; 66130561Sobrien 6733965Sjdpstruct hwcmap256 { 6833965Sjdp#define CMAP_SIZE 256 /* 256 R/G/B entries */ 69130561Sobrien uint8_t r[CMAP_SIZE]; 7033965Sjdp uint8_t g[CMAP_SIZE]; 7133965Sjdp uint8_t b[CMAP_SIZE]; 7233965Sjdp}; 7333965Sjdp 7433965Sjdp 7533965Sjdp/* XXX for CURSOR_MAX_WIDTH = 32 */ 7633965Sjdpstruct hwcursor32 { 7733965Sjdp struct wsdisplay_curpos cc_pos; 7833965Sjdp struct wsdisplay_curpos cc_hot; 7933965Sjdp struct wsdisplay_curpos cc_size; 8033965Sjdp uint8_t cc_color[6]; /* how many? */ 8133965Sjdp uint32_t cc_image[(CURSOR_MAX_WIDTH/4) * CURSOR_MAX_HEIGHT]; 8260484Sobrien uint32_t cc_mask[(CURSOR_MAX_WIDTH/4) * CURSOR_MAX_HEIGHT]; 8333965Sjdp}; 8433965Sjdp 8577298Sobrien 8677298Sobrienstruct fb_devconfig { 8733965Sjdp vaddr_t dc_vaddr; /* memory space virtual base address */ 8877298Sobrien paddr_t dc_paddr; /* memory space physical base address */ 89130561Sobrien vsize_t dc_size; /* size of slot memory */ 9033965Sjdp int dc_width; /* width of frame buffer */ 91130561Sobrien int dc_height; /* height of frame buffer */ 9233965Sjdp int dc_log2_depth; /* log2 of bits per pixel */ 9333965Sjdp int dc_depth; /* depth, bits per pixel */ 9433965Sjdp int dc_rowbytes; /* bytes in a FB scan line */ 9577298Sobrien vaddr_t dc_videobase; /* base of flat frame buffer */ 9633965Sjdp int dc_blanked; /* currently has video disabled */ 9733965Sjdp void *dc_hwscroll_cookie; /* cookie for hardware scroll */ 9833965Sjdp void *dc_ih; /* interrupt handler for dc */ 9977298Sobrien 100130561Sobrien int dc_curenb; /* is cursor sprite enabled ? */ 10133965Sjdp int _internal_dc_changed; /* need update of hardware */ 102130561Sobrien int dc_writeback_delay; /* Screenarea write back vsync counter */ 10333965Sjdp#define WSDISPLAY_CMAP_DOLUT 0x20 10433965Sjdp#define WSDISPLAY_VIDEO_ONOFF 0x40 10533965Sjdp#define WSDISPLAY_WB_COUNTER 0x80 10633965Sjdp 10733965Sjdp struct hwcmap256 dc_cmap; /* software copy of colormap */ 108130561Sobrien struct hwcursor32 dc_cursor; /* software copy of cursor */ 10933965Sjdp 11033965Sjdp struct vidc_mode mode_info; 11133965Sjdp 11233965Sjdp struct wsdisplay_emulops orig_ri_ops; /* Rasops functions for deligation */ 11333965Sjdp 11433965Sjdp /* virtual console support */ 11533965Sjdp struct vcons_data dc_vd; 11633965Sjdp struct vcons_screen dc_console; 11733965Sjdp}; 11833965Sjdp 11977298Sobrien 12077298Sobrienstruct vidcvideo_softc { 12177298Sobrien device_t sc_dev; 12277298Sobrien struct fb_devconfig *sc_dc; /* device configuration */ 12377298Sobrien}; 12433965Sjdp 12533965Sjdp 12677298Sobrien/* Function prototypes for glue */ 12777298Sobrienstatic int vidcvideo_match(device_t , cfdata_t , void *); 12833965Sjdpstatic void vidcvideo_attach(device_t , device_t , void *); 12933965Sjdp 13033965Sjdp 13133965Sjdp/* config glue */ 13233965SjdpCFATTACH_DECL_NEW(vidcvideo, sizeof(struct vidcvideo_softc), 13333965Sjdp vidcvideo_match, vidcvideo_attach, NULL, NULL); 13433965Sjdp 13533965Sjdpstatic struct fb_devconfig vidcvideo_console_dc; 13677298Sobrienstatic bool vidcvideo_is_console = false; 13733965Sjdp 13877298Sobrien 13933965Sjdpstatic struct wsscreen_descr vidcvideo_stdscreen = { 14033965Sjdp "std", 0, 0, 14133965Sjdp NULL, /* textops */ 14233965Sjdp 8, 16, 14333965Sjdp WSSCREEN_WSCOLORS | WSSCREEN_HILIT, 14433965Sjdp NULL 14533965Sjdp}; 14633965Sjdp 14733965Sjdpstatic const struct wsscreen_descr *_vidcvideo_scrlist[] = { 14833965Sjdp &vidcvideo_stdscreen, 14933965Sjdp}; 15077298Sobrien 15133965Sjdpstatic const struct wsscreen_list vidcvideo_screenlist = { 15233965Sjdp sizeof(_vidcvideo_scrlist) / sizeof(struct wsscreen_descr *), 15333965Sjdp _vidcvideo_scrlist 15433965Sjdp}; 15533965Sjdp 156130561Sobrienstatic int vidcvideoioctl(void *, void *, u_long, void *, int, 15733965Sjdp struct lwp *); 15833965Sjdpstatic paddr_t vidcvideommap(void *, void *, off_t, int); 15933965Sjdpstatic void vidcvideoinit_screen(void *, struct vcons_screen *, int, long *); 16033965Sjdp 16133965Sjdpstatic void vidcvideo_queue_dc_change(struct fb_devconfig*, int); 16233965Sjdpstatic int flush_dc_changes_to_screen(struct fb_devconfig*); 16333965Sjdp 16433965Sjdpstatic struct wsdisplay_accessops vidcvideo_accessops = { 16533965Sjdp vidcvideoioctl, 16660484Sobrien vidcvideommap, 16733965Sjdp NULL, /* alloc_screen */ 16833965Sjdp NULL, /* free_screen */ 16933965Sjdp NULL, /* show_screen */ 17033965Sjdp NULL, /* load_font */ 17133965Sjdp NULL, /* pollc */ 17233965Sjdp NULL /* scroll */ 17333965Sjdp}; 17477298Sobrien 17577298Sobrien 17677298Sobrien/* Function prototypes */ 17777298Sobrienint vidcvideo_cnattach(vaddr_t); 17877298Sobrienstatic void vidcvideo_colourmap_and_cursor_init(struct fb_devconfig *); 17933965Sjdp 18033965Sjdpstatic int get_cmap(struct vidcvideo_softc *, struct wsdisplay_cmap *); 18177298Sobrienstatic int set_cmap(struct vidcvideo_softc *, struct wsdisplay_cmap *); 18277298Sobrienstatic int set_cursor(struct vidcvideo_softc *, struct wsdisplay_cursor *); 18333965Sjdpstatic int get_cursor(struct vidcvideo_softc *, struct wsdisplay_cursor *); 18433965Sjdpstatic void set_curpos(struct vidcvideo_softc *, struct wsdisplay_curpos *); 18538889Sjdpstatic void vidcvideo_getdevconfig(vaddr_t, u_int, struct fb_devconfig *); 18633965Sjdp 18733965Sjdpstatic int vidcvideointr(void *); 18833965Sjdp 18933965Sjdp/* Acceleration function prototypes */ 190218822Sdimstatic void vv_copyrows(void *, int, int, int); 19133965Sjdpstatic void vv_eraserows(void *, int, int, long); 19233965Sjdpstatic void vv_putchar(void *c, int row, int col, u_int uc, long attr); 19333965Sjdp 19477298Sobrien 19533965Sjdpstatic int 19677298Sobrienvidcvideo_match(device_t parent, cfdata_t match, void *aux) 19733965Sjdp{ 19833965Sjdp 19933965Sjdp /* Can't probe AFAIK ; how ? */ 20033965Sjdp return 1; 20133965Sjdp} 20238889Sjdp 20333965Sjdp 20433965Sjdpstatic void 20533965Sjdpvidcvideo_getdevconfig(vaddr_t dense_addr, u_int mem_size, 20633965Sjdp struct fb_devconfig *dc) 207218822Sdim{ 20833965Sjdp 20933965Sjdp dc->dc_vaddr = dense_addr; 21033965Sjdp (void) pmap_extract(pmap_kernel(), dc->dc_vaddr, &(dc->dc_paddr)); 21177298Sobrien 21233965Sjdp vidcvideo_getmode(&dc->mode_info); 21333965Sjdp 21477298Sobrien dc->dc_width = dc->mode_info.timings.hdisplay; 21577298Sobrien dc->dc_height = dc->mode_info.timings.vdisplay; 21677298Sobrien dc->dc_log2_depth = dc->mode_info.log2_bpp; 21733965Sjdp dc->dc_depth = 1 << dc->dc_log2_depth; 21833965Sjdp dc->dc_videobase = dc->dc_vaddr; 21977298Sobrien dc->dc_blanked = 0; 22077298Sobrien 22133965Sjdp /* this should/could be done somewhat more elegant! */ 22233965Sjdp switch (dc->dc_depth) { 22338889Sjdp case 1: 22433965Sjdp dc->dc_rowbytes = dc->dc_width / 8; 22533965Sjdp break; 22633965Sjdp case 2: 22733965Sjdp dc->dc_rowbytes = dc->dc_width / 4; 228218822Sdim break; 22933965Sjdp case 4: 23033965Sjdp dc->dc_rowbytes = dc->dc_width / 2; 23133965Sjdp break; 23277298Sobrien case 8: 23333965Sjdp dc->dc_rowbytes = dc->dc_width; 23477298Sobrien break; 23533965Sjdp case 16: 23633965Sjdp dc->dc_rowbytes = dc->dc_width * 2; 23733965Sjdp break; 23833965Sjdp case 32: 23933965Sjdp dc->dc_rowbytes = dc->dc_width * 4; 24033965Sjdp break; 24133965Sjdp default: 24238889Sjdp printf("Unknown colour depth %d ... what to do ?", dc->dc_depth); 24333965Sjdp break; 24433965Sjdp } 24533965Sjdp 24633965Sjdp /* setup the correct size */ 247218822Sdim dc->dc_size = mem_size; 24833965Sjdp 24933965Sjdp /* initialize colormap and cursor resource */ 25033965Sjdp vidcvideo_colourmap_and_cursor_init(dc); 25177298Sobrien 25233965Sjdp /* blank the memory */ 25333965Sjdp memset((void*)dc->dc_vaddr, 0, dc->dc_size); 25433965Sjdp 25533965Sjdp /* intitialise miscelanious */ 25633965Sjdp dc->dc_writeback_delay = 0; 257130561Sobrien} 25833965Sjdp 25933965Sjdpstatic void 26033965Sjdpvidcvideoinit_screen(void *cookie, struct vcons_screen *scr, 26133965Sjdp int existing, long *defattr) 26233965Sjdp{ 26333965Sjdp struct rasops_info *ri = &scr->scr_ri; 26433965Sjdp struct fb_devconfig *dc = cookie; 26533965Sjdp 26633965Sjdp if ((scr == &dc->dc_console) && (dc->dc_vd.active != NULL)) 26760484Sobrien return; 26833965Sjdp 26933965Sjdp ri->ri_flg = RI_NO_AUTO; /* RI_CENTER | RI_FULLCLEAR; */ 27033965Sjdp ri->ri_depth = dc->dc_depth; 27133965Sjdp ri->ri_bits = (void *) dc->dc_videobase; 27233965Sjdp ri->ri_width = dc->dc_width; 27333965Sjdp ri->ri_height = dc->dc_height; 27433965Sjdp ri->ri_stride = dc->dc_rowbytes; 27577298Sobrien ri->ri_hw = &dc->dc_console; /* link back */ 27677298Sobrien 27777298Sobrien rasops_init(ri, 27877298Sobrien ri->ri_height / 8, 27977298Sobrien ri->ri_width / 8); 28033965Sjdp 28133965Sjdp ri->ri_caps = WSSCREEN_WSCOLORS; 28277298Sobrien 28377298Sobrien rasops_reconfig(ri, 28433965Sjdp ri->ri_height / ri->ri_font->fontheight, 28533965Sjdp ri->ri_width / ri->ri_font->fontwidth); 28638889Sjdp 28733965Sjdp /* 28833965Sjdp * Provide a hook for the acceleration functions and make a copy of the 289218822Sdim * original rasops functions for passing on calls 29033965Sjdp */ 29133965Sjdp memcpy(&(dc->orig_ri_ops), &(ri->ri_ops), 29233965Sjdp sizeof(struct wsdisplay_emulops)); 29333965Sjdp 29433965Sjdp /* add our accelerated functions */ 29533965Sjdp ri->ri_ops.eraserows = vv_eraserows; 29677298Sobrien ri->ri_ops.copyrows = vv_copyrows; 29733965Sjdp 29833965Sjdp /* add the extra activity measuring functions; they just delegate on */ 29933965Sjdp ri->ri_ops.putchar = vv_putchar; 30033965Sjdp 30133965Sjdp vidcvideo_stdscreen.nrows = ri->ri_rows; 30238889Sjdp vidcvideo_stdscreen.ncols = ri->ri_cols; 30333965Sjdp vidcvideo_stdscreen.textops = &ri->ri_ops; 30433965Sjdp vidcvideo_stdscreen.capabilities = ri->ri_caps; 305218822Sdim} 30633965Sjdp 30733965Sjdpstatic void 30833965Sjdpvidcvideo_attach(device_t parent, device_t self, void *aux) 30933965Sjdp{ 31033965Sjdp struct vidcvideo_softc *sc = device_private(self); 31133965Sjdp struct fb_devconfig *dc; 31277298Sobrien struct wsemuldisplaydev_attach_args waa; 31377298Sobrien long defattr; 31477298Sobrien 31533965Sjdp sc->sc_dev = self; 31633965Sjdp 31777298Sobrien dc = sc->sc_dc = &vidcvideo_console_dc; 31877298Sobrien 31933965Sjdp /* 32033965Sjdp * for reasons which are crazy we init vidcvideo twice, 32138889Sjdp * the second time sets up the cursor 32233965Sjdp */ 32333965Sjdp vidcvideo_init(); 324218822Sdim if (!vidcvideo_is_console) { 32533965Sjdp vidcvideo_getdevconfig(videomemory.vidm_vbase, 32633965Sjdp videomemory.vidm_size, 32733965Sjdp sc->sc_dc); 32833965Sjdp } 32933965Sjdp 33033965Sjdp vcons_init(&dc->dc_vd, dc, &vidcvideo_stdscreen, &vidcvideo_accessops); 33177298Sobrien dc->dc_vd.init_screen = vidcvideoinit_screen; 33233965Sjdp 33333965Sjdp vcons_init_screen(&dc->dc_vd, &dc->dc_console, 1, &defattr); 33433965Sjdp 33533965Sjdp dc->dc_console.scr_flags |= VCONS_SCREEN_IS_STATIC; 33633965Sjdp 33733965Sjdp vidcvideo_printdetails(); 33833965Sjdp aprint_normal(": mode %s, %dbpp\n", dc->mode_info.timings.name, 33938889Sjdp dc->dc_depth); 34033965Sjdp 34133965Sjdp /* set up interrupt flags */ 342218822Sdim vidcvideo_queue_dc_change(dc, WSDISPLAY_CMAP_DOLUT); 34333965Sjdp 34433965Sjdp /* Establish an interrupt handler, and clear any pending interrupts */ 34533965Sjdp dc->dc_ih = intr_claim(IRQ_FLYBACK, IPL_TTY, "vblank", vidcvideointr, dc); 34633965Sjdp 34733965Sjdp waa.console = (vidcvideo_is_console ? 1 : 0); 34833965Sjdp waa.scrdata = &vidcvideo_screenlist; 34977298Sobrien waa.accessops = &vidcvideo_accessops; 35077298Sobrien waa.accesscookie = &dc->dc_vd; 35177298Sobrien 35277298Sobrien config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE); 35333965Sjdp} 35433965Sjdp 35577298Sobrien 35677298Sobrienstatic int 35733965Sjdpvidcvideoioctl(void *v, void *vs, u_long cmd, void *data, int flag, 35833965Sjdp struct lwp *l) 35933965Sjdp{ 36033965Sjdp struct vcons_data *vd = v; 36133965Sjdp struct vidcvideo_softc *sc = vd->cookie; 36260484Sobrien struct fb_devconfig *dc = sc->sc_dc; 36333965Sjdp struct vcons_screen *ms = vd->active; 36433965Sjdp int state; 36533965Sjdp 36677298Sobrien switch (cmd) { 36777298Sobrien case WSDISPLAYIO_GTYPE: 36877298Sobrien *(u_int *)data = WSDISPLAY_TYPE_VIDC; 369218822Sdim return 0; 37033965Sjdp 37177298Sobrien case WSDISPLAYIO_GINFO: 37233965Sjdp if (ms == NULL) 37377298Sobrien return ENODEV; 37433965Sjdp#define wsd_fbip ((struct wsdisplay_fbinfo *)data) 37533965Sjdp wsd_fbip->height = dc->dc_height; 37633965Sjdp wsd_fbip->width = dc->dc_width; 37733965Sjdp wsd_fbip->depth = dc->dc_depth; 37833965Sjdp wsd_fbip->cmsize = CMAP_SIZE; 37933965Sjdp#undef fbt 38033965Sjdp return 0; 38133965Sjdp 38260484Sobrien case WSDISPLAYIO_GETCMAP: 38333965Sjdp return get_cmap(sc, (struct wsdisplay_cmap *)data); 38433965Sjdp 38533965Sjdp case WSDISPLAYIO_PUTCMAP: 38633965Sjdp return set_cmap(sc, (struct wsdisplay_cmap *)data); 38777298Sobrien 38833965Sjdp case WSDISPLAYIO_LINEBYTES: 38933965Sjdp *(u_int *)data = dc->dc_rowbytes; 39077298Sobrien return 0; 39177298Sobrien 39233965Sjdp case WSDISPLAYIO_SVIDEO: 39333965Sjdp state = *(int *)data; 394130561Sobrien dc->dc_blanked = (state == WSDISPLAYIO_VIDEO_OFF); 39533965Sjdp vidcvideo_queue_dc_change(dc, WSDISPLAY_VIDEO_ONOFF); 39633965Sjdp /* done on video blank */ 39760484Sobrien return 0; 39833965Sjdp 39960484Sobrien case WSDISPLAYIO_GVIDEO: 40060484Sobrien *(u_int *)data = dc->dc_blanked ? 40160484Sobrien WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 40260484Sobrien return 0; 40360484Sobrien 40433965Sjdp case WSDISPLAYIO_GCURPOS: 40533965Sjdp *(struct wsdisplay_curpos *)data = dc->dc_cursor.cc_pos; 40633965Sjdp return 0; 40733965Sjdp 40833965Sjdp case WSDISPLAYIO_SCURPOS: 40977298Sobrien set_curpos(sc, (struct wsdisplay_curpos *)data); 41033965Sjdp vidcvideo_queue_dc_change(dc, WSDISPLAY_CURSOR_DOPOS); 411130561Sobrien return 0; 41233965Sjdp 41333965Sjdp case WSDISPLAYIO_GCURMAX: 41433965Sjdp ((struct wsdisplay_curpos *)data)->x = CURSOR_MAX_WIDTH; 41560484Sobrien ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_HEIGHT; 41660484Sobrien return 0; 41760484Sobrien 41860484Sobrien case WSDISPLAYIO_GCURSOR: 41960484Sobrien return get_cursor(sc, (struct wsdisplay_cursor *)data); 42060484Sobrien 42133965Sjdp case WSDISPLAYIO_SCURSOR: 42233965Sjdp return set_cursor(sc, (struct wsdisplay_cursor *)data); 42333965Sjdp 42433965Sjdp case WSDISPLAYIO_SMODE: 42533965Sjdp state = *(int *)data; 42633965Sjdp if (state == WSDISPLAYIO_MODE_MAPPED) 427218822Sdim dc->dc_hwscroll_cookie = vidcvideo_hwscroll_reset(); 42833965Sjdp if (state == WSDISPLAYIO_MODE_EMUL) 42933965Sjdp vidcvideo_hwscroll_back(dc->dc_hwscroll_cookie); 43033965Sjdp vidcvideo_progr_scroll(); 431218822Sdim 43233965Sjdp return 0; 43333965Sjdp } 43433965Sjdp return EPASSTHROUGH; 43533965Sjdp} 436218822Sdim 43733965Sjdp 43833965Sjdppaddr_t 43933965Sjdpvidcvideommap(void *v, void *vs, off_t offset, int prot) 44033965Sjdp{ 44133965Sjdp struct vcons_data *vd = v; 442218822Sdim struct vidcvideo_softc *sc = vd->cookie; 443218822Sdim 444218822Sdim if (offset >= sc->sc_dc->dc_size || offset < 0) 445218822Sdim return -1; 446218822Sdim 447218822Sdim return arm_btop(sc->sc_dc->dc_paddr + offset); 448218822Sdim} 449218822Sdim 450218822Sdim 451218822Sdim/* EXPORT */ int 452218822Sdimvidcvideo_cnattach(vaddr_t addr) 45333965Sjdp{ 454218822Sdim struct fb_devconfig *dc = &vidcvideo_console_dc; 455218822Sdim struct rasops_info *ri; 456218822Sdim long defattr; 457218822Sdim 458218822Sdim vidcvideo_init(); 459218822Sdim 46033965Sjdp /* fetch current framebuffer config */ 461218822Sdim vidcvideo_getdevconfig(videomemory.vidm_vbase, 462218822Sdim videomemory.vidm_size, 463218822Sdim dc); 464218822Sdim 465218822Sdim dc->dc_vd.active = NULL; 466218822Sdim vidcvideoinit_screen(dc, &dc->dc_console, 1, &defattr); 467218822Sdim 468218822Sdim ri = &(dc->dc_console.scr_ri); 469218822Sdim ri->ri_hw = &dc->dc_console; 470218822Sdim dc->dc_console.scr_cookie = dc; 471218822Sdim 472218822Sdim (*ri->ri_ops.allocattr)(ri, 473218822Sdim WS_DEFAULT_FG, /* fg */ 47433965Sjdp WS_DEFAULT_BG, /* bg */ 47533965Sjdp 0, /* wsattrs */ 476218822Sdim &defattr); 477218822Sdim 478218822Sdim wsdisplay_cnattach(&vidcvideo_stdscreen, 479218822Sdim ri, /* emulcookie */ 480218822Sdim 0, 0, /* cursor position */ 481218822Sdim defattr); 482218822Sdim 48333965Sjdp vidcvideo_is_console = true; 484218822Sdim 485218822Sdim return 0; 486218822Sdim} 487218822Sdim 488218822Sdim 489218822Sdimstatic int 490218822Sdimvidcvideointr(void *arg) 491218822Sdim{ 492218822Sdim struct fb_devconfig *dc = arg; 49333965Sjdp 494218822Sdim return flush_dc_changes_to_screen(dc); 495218822Sdim} 496218822Sdim 497218822Sdimstatic int 498218822Sdimflush_dc_changes_to_screen(struct fb_devconfig *dc) 499218822Sdim{ 500218822Sdim int v, cleared = 0; 501218822Sdim 502218822Sdim v = dc->_internal_dc_changed; 503218822Sdim 504218822Sdim if (v == 0) { 505218822Sdim disable_irq(IRQ_FLYBACK); 506218822Sdim return 1; 507218822Sdim } 508218822Sdim 509218822Sdim if (v & WSDISPLAY_WB_COUNTER) { 510218822Sdim dc->dc_writeback_delay--; 511218822Sdim if (dc->dc_writeback_delay == 0) { 512218822Sdim cpu_dcache_wb_range(dc->dc_vaddr, dc->dc_size); 513218822Sdim cleared |= WSDISPLAY_WB_COUNTER; 514218822Sdim } 51533965Sjdp } 516218822Sdim 517218822Sdim if (v & WSDISPLAY_CMAP_DOLUT) { 518218822Sdim struct hwcmap256 *cm = &dc->dc_cmap; 519218822Sdim int index; 520218822Sdim 521218822Sdim if (dc->dc_depth == 4) { 522218822Sdim /* palette for 4 bpp is different from 8bpp */ 523218822Sdim vidcvideo_write(VIDC_PALREG, 0x00000000); 524218822Sdim for (index=0; index < (1 << dc->dc_depth); index++) 525218822Sdim vidcvideo_write(VIDC_PALETTE, 526218822Sdim VIDC_COL(cm->r[index], 527218822Sdim cm->g[index], 528218822Sdim cm->b[index])); 529218822Sdim } 530218822Sdim 531218822Sdim if (dc->dc_depth == 8) { 532218822Sdim /* 533218822Sdim * dunno what to do in more than 8bpp 534218822Sdim * palettes only make sense in 8bpp and less modes 535218822Sdim * on VIDC 536218822Sdim */ 537218822Sdim vidcvideo_write(VIDC_PALREG, 0x00000000); 538 for (index = 0; index < CMAP_SIZE; index++) { 539 vidcvideo_write(VIDC_PALETTE, 540 VIDC_COL(cm->r[index], cm->g[index], 541 cm->b[index])); 542 } 543 } 544 cleared |= WSDISPLAY_CMAP_DOLUT; 545 } 546 547 if (v & WSDISPLAY_VIDEO_ONOFF) { 548 vidcvideo_blank(dc->dc_blanked); 549 cleared |= WSDISPLAY_VIDEO_ONOFF; 550 } 551 552 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 553 int x, y; 554 x = dc->dc_cursor.cc_pos.x - dc->dc_cursor.cc_hot.x; 555 y = dc->dc_cursor.cc_pos.y - dc->dc_cursor.cc_hot.y; 556 557 vidcvideo_updatecursor(x, y); 558 cleared |= WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT; 559 } 560 561 if (v & WSDISPLAY_CURSOR_DOCUR) { 562 vidcvideo_enablecursor(dc->dc_curenb); 563 cleared |= WSDISPLAY_CURSOR_DOCUR; 564 } 565 566 dc->_internal_dc_changed ^= cleared; 567 568 if (dc->_internal_dc_changed == 0) { 569 disable_irq(IRQ_FLYBACK); 570 } 571 572 return 1; 573} 574 575 576static void vidcvideo_queue_dc_change(struct fb_devconfig *dc, int dc_change) 577{ 578 dc->_internal_dc_changed |= dc_change; 579 580 if (curcpl() == IPL_HIGH) { 581 /* running in ddb or without interrupts */ 582 dc->dc_writeback_delay = 1; 583 flush_dc_changes_to_screen(dc); 584 } else { 585 /* 586 * running with interrupts so handle this in the next 587 * vsync 588 */ 589 if (dc->dc_ih) { 590 enable_irq(IRQ_FLYBACK); 591 } 592 } 593} 594 595 596static const u_char ri_col_data[6][6] = { 597 { 0, 0, 0, 0, 0, 0}, /* 1 bpp */ 598 { 0, 0, 0, 0, 0, 0}, /* 2 bpp */ 599 { 0, 0, 0, 0, 0, 0}, /* 4 bpp */ 600 { 0, 0, 0, 0, 0, 0}, /* 8 bpp */ 601 { 6, 5, 5, 0, 6, 11}, /* 16 bpp */ 602 { 8, 8, 8, 0, 8, 16}, /* 32 bpp */ 603}; 604 605static void 606vidcvideo_colourmap_and_cursor_init(struct fb_devconfig *dc) 607{ 608 struct rasops_info *ri = &dc->dc_console.scr_ri; 609 const u_char *rgbdat; 610 struct hwcmap256 *cm; 611 const uint8_t *p; 612 int index; 613 614 /* Whatever we do later... just make sure we have a 615 * sane palette to start with 616 */ 617 vidcvideo_stdpalette(); 618 619 /* set up rgb bit pattern values for rasops_init */ 620 rgbdat = ri_col_data[dc->dc_log2_depth]; 621 ri->ri_rnum = rgbdat[0]; 622 ri->ri_gnum = rgbdat[1]; 623 ri->ri_bnum = rgbdat[2]; 624 ri->ri_rpos = rgbdat[3]; 625 ri->ri_gpos = rgbdat[4]; 626 ri->ri_bpos = rgbdat[5]; 627 628 /* initialise color map */ 629 cm = &dc->dc_cmap; 630 p = rasops_cmap; 631 for (index = 0; index < CMAP_SIZE; index++, p += 3) { 632 cm->r[index] = p[0]; 633 cm->g[index] = p[1]; 634 cm->b[index] = p[2]; 635 } 636 /* flush to hardware */ 637 vidcvideo_queue_dc_change(dc, WSDISPLAY_CMAP_DOLUT); 638} 639 640 641static int 642get_cmap(struct vidcvideo_softc *sc, struct wsdisplay_cmap *p) 643{ 644 u_int index = p->index, count = p->count; 645 int error; 646 647 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 648 return EINVAL; 649 650 error = copyout(&sc->sc_dc->dc_cmap.r[index], p->red, count); 651 if (error) 652 return error; 653 error = copyout(&sc->sc_dc->dc_cmap.g[index], p->green, count); 654 if (error) 655 return error; 656 error = copyout(&sc->sc_dc->dc_cmap.b[index], p->blue, count); 657 return error; 658} 659 660 661static int 662set_cmap(struct vidcvideo_softc *sc, struct wsdisplay_cmap *p) 663{ 664 struct fb_devconfig *dc = sc->sc_dc; 665 struct hwcmap256 cmap; 666 u_int index = p->index, count = p->count; 667 int error; 668 669 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 670 return EINVAL; 671 672 error = copyin(p->red, &cmap.r[index], count); 673 if (error) 674 return error; 675 error = copyin(p->green, &cmap.g[index], count); 676 if (error) 677 return error; 678 error = copyin(p->blue, &cmap.b[index], count); 679 if (error) 680 return error; 681 memcpy(&dc->dc_cmap.r[index], &cmap.r[index], count); 682 memcpy(&dc->dc_cmap.g[index], &cmap.g[index], count); 683 memcpy(&dc->dc_cmap.b[index], &cmap.b[index], count); 684 vidcvideo_queue_dc_change(dc, WSDISPLAY_CMAP_DOLUT); 685 return 0; 686} 687 688 689static int 690set_cursor(struct vidcvideo_softc *sc, struct wsdisplay_cursor *p) 691{ 692#define cc (&dc->dc_cursor) 693 struct fb_devconfig *dc = sc->sc_dc; 694 u_int v, index = 0, count = 0, icount = 0; 695 uint8_t r[2], g[2], b[2], image[512], mask[512]; 696 int error; 697 698 /* XXX gcc does not detect identical conditions */ 699 index = count = icount = 0; 700 701 v = p->which; 702 if (v & WSDISPLAY_CURSOR_DOCMAP) { 703 index = p->cmap.index; 704 count = p->cmap.count; 705 if (index >= CURSOR_MAX_COLOURS || 706 (index + count) > CURSOR_MAX_COLOURS) 707 return EINVAL; 708 error = copyin(p->cmap.red, &r[index], count); 709 if (error) 710 return error; 711 error = copyin(p->cmap.green, &g[index], count); 712 if (error) 713 return error; 714 error = copyin(p->cmap.blue, &b[index], count); 715 if (error) 716 return error; 717 } 718 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 719 if (p->size.x > CURSOR_MAX_WIDTH || 720 p->size.y > CURSOR_MAX_HEIGHT) 721 return EINVAL; 722 icount = sizeof(uint32_t) * p->size.y; 723 error = copyin(p->image, &image, icount); 724 if (error) 725 return error; 726 error = copyin(p->mask, &mask, icount); 727 if (error) 728 return error; 729 } 730 731 if (v & WSDISPLAY_CURSOR_DOCUR) 732 dc->dc_curenb = p->enable; 733 if (v & WSDISPLAY_CURSOR_DOPOS) 734 set_curpos(sc, &p->pos); 735 if (v & WSDISPLAY_CURSOR_DOHOT) 736 cc->cc_hot = p->hot; 737 if (v & WSDISPLAY_CURSOR_DOCMAP) { 738 memcpy(&cc->cc_color[index], &r[index], count); 739 memcpy(&cc->cc_color[index + 2], &g[index], count); 740 memcpy(&cc->cc_color[index + 4], &b[index], count); 741 } 742 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 743 cc->cc_size = p->size; 744 memset(cc->cc_image, 0, sizeof cc->cc_image); 745 memcpy(cc->cc_image, image, icount); 746 memset(cc->cc_mask, 0, sizeof cc->cc_mask); 747 memcpy(cc->cc_mask, mask, icount); 748 } 749 vidcvideo_queue_dc_change(dc, v); 750 751 return 0; 752#undef cc 753} 754 755 756static int 757get_cursor(struct vidcvideo_softc *sc, struct wsdisplay_cursor *p) 758{ 759 760 return EPASSTHROUGH; /* XXX */ 761} 762 763 764static void 765set_curpos(struct vidcvideo_softc *sc, struct wsdisplay_curpos *curpos) 766{ 767 struct fb_devconfig *dc = sc->sc_dc; 768 int x = curpos->x, y = curpos->y; 769 770 if (y < 0) 771 y = 0; 772 else if (y > dc->dc_height) 773 y = dc->dc_height; 774 if (x < 0) 775 x = 0; 776 else if (x > dc->dc_width) 777 x = dc->dc_width; 778 dc->dc_cursor.cc_pos.x = x; 779 dc->dc_cursor.cc_pos.y = y; 780} 781 782 783static void vv_copyrows(void *id, int srcrow, int dstrow, int nrows) 784{ 785 struct rasops_info *ri = id; 786 int height, size; 787 unsigned char *src, *dst; 788 struct vcons_screen *scr = ri->ri_hw; 789 struct fb_devconfig *dc = (struct fb_devconfig *) (scr->scr_cookie); 790 791 /* All movements are done in multiples of character heigths */ 792 height = ri->ri_font->fontheight * nrows; 793 size = height * ri->ri_stride; 794 795 /* check if we are full screen scrolling */ 796 797#if 0 798 int scrollup = (srcrow + nrows >= ri->ri_rows); 799 int scrolldown = (dstrow + nrows >= ri->ri_rows); 800 if ((scrollup || scrolldown) && 801 (videomemory.vidm_type == VIDEOMEM_TYPE_VRAM)) { 802 int offset = (srcrow - dstrow) * ri->ri_yscale; 803 ri->ri_bits = vidcvideo_hwscroll(offset); 804 vidcvideo_progr_scroll(); /* sadistic ; shouldnt this be on vsync? */ 805 806 /* wipe out remains of the screen if necessary */ 807 if (ri->ri_emuheight != ri->ri_height) 808 vv_eraserows(id, ri->ri_rows, 1, 0); 809 return; 810 } 811#endif 812 813 /* 814 * Else we just copy the area : we're braindead for now 815 * Note: we can't use hardware scrolling when the softc isnt 816 * known yet... if its not known we dont have interrupts and 817 * we can't change the display address reliable other than in 818 * a Vsync 819 */ 820 821 src = ri->ri_bits + srcrow * ri->ri_font->fontheight * ri->ri_stride; 822 dst = ri->ri_bits + dstrow * ri->ri_font->fontheight * ri->ri_stride; 823 824 memmove(dst, src, size); 825 826 /* delay the write back operation of the screen area */ 827 dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY; 828 vidcvideo_queue_dc_change(dc, WSDISPLAY_WB_COUNTER); 829} 830 831 832static void vv_eraserows(void *id, int startrow, int nrows, long attr) 833{ 834 struct rasops_info *ri = id; 835 int height; 836 unsigned char *src; 837 struct vcons_screen *scr = ri->ri_hw; 838 struct fb_devconfig *dc = (struct fb_devconfig *) (scr->scr_cookie); 839 840 /* we're braindead for now */ 841 height = ri->ri_font->fontheight * nrows * ri->ri_stride; 842 843 src = ri->ri_bits + startrow * ri->ri_font->fontheight * ri->ri_stride; 844 845 memset(src, 0, height); 846 847 /* delay the write back operation of the screen area */ 848 dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY; 849 vidcvideo_queue_dc_change(dc, WSDISPLAY_WB_COUNTER); 850} 851 852 853static void vv_putchar(void *id, int row, int col, u_int uc, long attr) 854{ 855 struct rasops_info *ri = id; 856 struct vcons_screen *scr = ri->ri_hw; 857 struct fb_devconfig *dc = (struct fb_devconfig *) (scr->scr_cookie); 858 859 /* just delegate */ 860 dc->orig_ri_ops.putchar(id, row, col, uc, attr); 861 862 /* delay the write back operation of the screen area */ 863 dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY; 864 vidcvideo_queue_dc_change(dc, WSDISPLAY_WB_COUNTER); 865} 866