18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * newport_con.c: Abscon for newport hardware 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (C) 1998 Thomas Bogendoerfer (tsbogend@alpha.franken.de) 68c2ecf20Sopenharmony_ci * (C) 1999 Ulf Carlsson (ulfc@thepuffingruop.com) 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This driver is based on sgicons.c and cons_newport. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Copyright (C) 1996 David S. Miller (davem@davemloft.net) 118c2ecf20Sopenharmony_ci * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx) 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci#include <linux/kd.h> 178c2ecf20Sopenharmony_ci#include <linux/selection.h> 188c2ecf20Sopenharmony_ci#include <linux/console.h> 198c2ecf20Sopenharmony_ci#include <linux/vt_kern.h> 208c2ecf20Sopenharmony_ci#include <linux/mm.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <asm/io.h> 258c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 268c2ecf20Sopenharmony_ci#include <asm/page.h> 278c2ecf20Sopenharmony_ci#include <asm/gio_device.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <video/newport.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <linux/linux_logo.h> 328c2ecf20Sopenharmony_ci#include <linux/font.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define NEWPORT_LEN 0x10000 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define FONT_DATA ((unsigned char *)font_vga_8x16.data) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic unsigned char *font_data[MAX_NR_CONSOLES]; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic struct newport_regs *npregs; 418c2ecf20Sopenharmony_cistatic unsigned long newport_addr; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int logo_active; 448c2ecf20Sopenharmony_cistatic int topscan; 458c2ecf20Sopenharmony_cistatic int xcurs_correction = 29; 468c2ecf20Sopenharmony_cistatic int newport_xsize; 478c2ecf20Sopenharmony_cistatic int newport_ysize; 488c2ecf20Sopenharmony_cistatic int newport_has_init; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int newport_set_def_font(int unit, struct console_font *op); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define BMASK(c) (c << 24) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define RENDER(regs, cp) do { \ 558c2ecf20Sopenharmony_ci(regs)->go.zpattern = BMASK((cp)[0x0]); (regs)->go.zpattern = BMASK((cp)[0x1]); \ 568c2ecf20Sopenharmony_ci(regs)->go.zpattern = BMASK((cp)[0x2]); (regs)->go.zpattern = BMASK((cp)[0x3]); \ 578c2ecf20Sopenharmony_ci(regs)->go.zpattern = BMASK((cp)[0x4]); (regs)->go.zpattern = BMASK((cp)[0x5]); \ 588c2ecf20Sopenharmony_ci(regs)->go.zpattern = BMASK((cp)[0x6]); (regs)->go.zpattern = BMASK((cp)[0x7]); \ 598c2ecf20Sopenharmony_ci(regs)->go.zpattern = BMASK((cp)[0x8]); (regs)->go.zpattern = BMASK((cp)[0x9]); \ 608c2ecf20Sopenharmony_ci(regs)->go.zpattern = BMASK((cp)[0xa]); (regs)->go.zpattern = BMASK((cp)[0xb]); \ 618c2ecf20Sopenharmony_ci(regs)->go.zpattern = BMASK((cp)[0xc]); (regs)->go.zpattern = BMASK((cp)[0xd]); \ 628c2ecf20Sopenharmony_ci(regs)->go.zpattern = BMASK((cp)[0xe]); (regs)->go.zpattern = BMASK((cp)[0xf]); \ 638c2ecf20Sopenharmony_ci} while(0) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define TESTVAL 0xdeadbeef 668c2ecf20Sopenharmony_ci#define XSTI_TO_FXSTART(val) (((val) & 0xffff) << 11) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic inline void newport_render_background(int xstart, int ystart, 698c2ecf20Sopenharmony_ci int xend, int yend, int ci) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci newport_wait(npregs); 728c2ecf20Sopenharmony_ci npregs->set.wrmask = 0xffffffff; 738c2ecf20Sopenharmony_ci npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | 748c2ecf20Sopenharmony_ci NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX 758c2ecf20Sopenharmony_ci | NPORT_DMODE0_STOPY); 768c2ecf20Sopenharmony_ci npregs->set.colori = ci; 778c2ecf20Sopenharmony_ci npregs->set.xystarti = 788c2ecf20Sopenharmony_ci (xstart << 16) | ((ystart + topscan) & 0x3ff); 798c2ecf20Sopenharmony_ci npregs->go.xyendi = 808c2ecf20Sopenharmony_ci ((xend + 7) << 16) | ((yend + topscan + 15) & 0x3ff); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic inline void newport_init_cmap(void) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci unsigned short i; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 888c2ecf20Sopenharmony_ci newport_bfwait(npregs); 898c2ecf20Sopenharmony_ci newport_cmap_setaddr(npregs, color_table[i]); 908c2ecf20Sopenharmony_ci newport_cmap_setrgb(npregs, 918c2ecf20Sopenharmony_ci default_red[i], 928c2ecf20Sopenharmony_ci default_grn[i], default_blu[i]); 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic const struct linux_logo *newport_show_logo(void) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci#ifdef CONFIG_LOGO_SGI_CLUT224 998c2ecf20Sopenharmony_ci const struct linux_logo *logo = fb_find_logo(8); 1008c2ecf20Sopenharmony_ci const unsigned char *clut; 1018c2ecf20Sopenharmony_ci const unsigned char *data; 1028c2ecf20Sopenharmony_ci unsigned long i; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (!logo) 1058c2ecf20Sopenharmony_ci return NULL; 1068c2ecf20Sopenharmony_ci clut = logo->clut; 1078c2ecf20Sopenharmony_ci data = logo->data; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci for (i = 0; i < logo->clutsize; i++) { 1108c2ecf20Sopenharmony_ci newport_bfwait(npregs); 1118c2ecf20Sopenharmony_ci newport_cmap_setaddr(npregs, i + 0x20); 1128c2ecf20Sopenharmony_ci newport_cmap_setrgb(npregs, clut[0], clut[1], clut[2]); 1138c2ecf20Sopenharmony_ci clut += 3; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci newport_wait(npregs); 1178c2ecf20Sopenharmony_ci npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | 1188c2ecf20Sopenharmony_ci NPORT_DMODE0_CHOST); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci npregs->set.xystarti = ((newport_xsize - logo->width) << 16) | (0); 1218c2ecf20Sopenharmony_ci npregs->set.xyendi = ((newport_xsize - 1) << 16); 1228c2ecf20Sopenharmony_ci newport_wait(npregs); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci for (i = 0; i < logo->width*logo->height; i++) 1258c2ecf20Sopenharmony_ci npregs->go.hostrw0 = *data++ << 24; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return logo; 1288c2ecf20Sopenharmony_ci#else 1298c2ecf20Sopenharmony_ci return NULL; 1308c2ecf20Sopenharmony_ci#endif /* CONFIG_LOGO_SGI_CLUT224 */ 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic inline void newport_clear_screen(int xstart, int ystart, int xend, 1348c2ecf20Sopenharmony_ci int yend, int ci) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci if (logo_active) 1378c2ecf20Sopenharmony_ci return; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci newport_wait(npregs); 1408c2ecf20Sopenharmony_ci npregs->set.wrmask = 0xffffffff; 1418c2ecf20Sopenharmony_ci npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | 1428c2ecf20Sopenharmony_ci NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX 1438c2ecf20Sopenharmony_ci | NPORT_DMODE0_STOPY); 1448c2ecf20Sopenharmony_ci npregs->set.colori = ci; 1458c2ecf20Sopenharmony_ci npregs->set.xystarti = (xstart << 16) | ystart; 1468c2ecf20Sopenharmony_ci npregs->go.xyendi = (xend << 16) | yend; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic inline void newport_clear_lines(int ystart, int yend, int ci) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci ystart = ((ystart << 4) + topscan) & 0x3ff; 1528c2ecf20Sopenharmony_ci yend = ((yend << 4) + topscan + 15) & 0x3ff; 1538c2ecf20Sopenharmony_ci newport_clear_screen(0, ystart, 1280 + 63, yend, ci); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic void newport_reset(void) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci unsigned short treg; 1598c2ecf20Sopenharmony_ci int i; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci newport_wait(npregs); 1628c2ecf20Sopenharmony_ci treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); 1638c2ecf20Sopenharmony_ci newport_vc2_set(npregs, VC2_IREG_CONTROL, 1648c2ecf20Sopenharmony_ci (treg | VC2_CTRL_EVIDEO)); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci treg = newport_vc2_get(npregs, VC2_IREG_CENTRY); 1678c2ecf20Sopenharmony_ci newport_vc2_set(npregs, VC2_IREG_RADDR, treg); 1688c2ecf20Sopenharmony_ci npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM | 1698c2ecf20Sopenharmony_ci NPORT_DMODE_W2 | VC2_PROTOCOL); 1708c2ecf20Sopenharmony_ci for (i = 0; i < 128; i++) { 1718c2ecf20Sopenharmony_ci newport_bfwait(npregs); 1728c2ecf20Sopenharmony_ci if (i == 92 || i == 94) 1738c2ecf20Sopenharmony_ci npregs->set.dcbdata0.byshort.s1 = 0xff00; 1748c2ecf20Sopenharmony_ci else 1758c2ecf20Sopenharmony_ci npregs->set.dcbdata0.byshort.s1 = 0x0000; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci newport_init_cmap(); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* turn off popup plane */ 1818c2ecf20Sopenharmony_ci npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL | 1828c2ecf20Sopenharmony_ci XM9_CRS_CONFIG | NPORT_DMODE_W1); 1838c2ecf20Sopenharmony_ci npregs->set.dcbdata0.bybytes.b3 &= ~XM9_PUPMODE; 1848c2ecf20Sopenharmony_ci npregs->set.dcbmode = (DCB_XMAP1 | R_DCB_XMAP9_PROTOCOL | 1858c2ecf20Sopenharmony_ci XM9_CRS_CONFIG | NPORT_DMODE_W1); 1868c2ecf20Sopenharmony_ci npregs->set.dcbdata0.bybytes.b3 &= ~XM9_PUPMODE; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci topscan = 0; 1898c2ecf20Sopenharmony_ci npregs->cset.topscan = 0x3ff; 1908c2ecf20Sopenharmony_ci npregs->cset.xywin = (4096 << 16) | 4096; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* Clear the screen. */ 1938c2ecf20Sopenharmony_ci newport_clear_screen(0, 0, 1280 + 63, 1024, 0); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* 1978c2ecf20Sopenharmony_ci * calculate the actual screen size by reading 1988c2ecf20Sopenharmony_ci * the video timing out of the VC2 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_cistatic void newport_get_screensize(void) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci int i, cols; 2038c2ecf20Sopenharmony_ci unsigned short ventry, treg; 2048c2ecf20Sopenharmony_ci unsigned short linetable[128]; /* should be enough */ 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci ventry = newport_vc2_get(npregs, VC2_IREG_VENTRY); 2078c2ecf20Sopenharmony_ci newport_vc2_set(npregs, VC2_IREG_RADDR, ventry); 2088c2ecf20Sopenharmony_ci npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM | 2098c2ecf20Sopenharmony_ci NPORT_DMODE_W2 | VC2_PROTOCOL); 2108c2ecf20Sopenharmony_ci for (i = 0; i < 128; i++) { 2118c2ecf20Sopenharmony_ci newport_bfwait(npregs); 2128c2ecf20Sopenharmony_ci linetable[i] = npregs->set.dcbdata0.byshort.s1; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci newport_xsize = newport_ysize = 0; 2168c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(linetable) - 1 && linetable[i + 1]; i += 2) { 2178c2ecf20Sopenharmony_ci cols = 0; 2188c2ecf20Sopenharmony_ci newport_vc2_set(npregs, VC2_IREG_RADDR, linetable[i]); 2198c2ecf20Sopenharmony_ci npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM | 2208c2ecf20Sopenharmony_ci NPORT_DMODE_W2 | VC2_PROTOCOL); 2218c2ecf20Sopenharmony_ci do { 2228c2ecf20Sopenharmony_ci newport_bfwait(npregs); 2238c2ecf20Sopenharmony_ci treg = npregs->set.dcbdata0.byshort.s1; 2248c2ecf20Sopenharmony_ci if ((treg & 1) == 0) 2258c2ecf20Sopenharmony_ci cols += (treg >> 7) & 0xfe; 2268c2ecf20Sopenharmony_ci if ((treg & 0x80) == 0) { 2278c2ecf20Sopenharmony_ci newport_bfwait(npregs); 2288c2ecf20Sopenharmony_ci treg = npregs->set.dcbdata0.byshort.s1; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci } while ((treg & 0x8000) == 0); 2318c2ecf20Sopenharmony_ci if (cols) { 2328c2ecf20Sopenharmony_ci if (cols > newport_xsize) 2338c2ecf20Sopenharmony_ci newport_xsize = cols; 2348c2ecf20Sopenharmony_ci newport_ysize += linetable[i + 1]; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci printk("NG1: Screensize %dx%d\n", newport_xsize, newport_ysize); 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic void newport_get_revisions(void) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci unsigned int tmp; 2438c2ecf20Sopenharmony_ci unsigned int board_rev; 2448c2ecf20Sopenharmony_ci unsigned int rex3_rev; 2458c2ecf20Sopenharmony_ci unsigned int vc2_rev; 2468c2ecf20Sopenharmony_ci unsigned int cmap_rev; 2478c2ecf20Sopenharmony_ci unsigned int xmap9_rev; 2488c2ecf20Sopenharmony_ci unsigned int bt445_rev; 2498c2ecf20Sopenharmony_ci unsigned int bitplanes; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci rex3_rev = npregs->cset.status & NPORT_STAT_VERS; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci npregs->set.dcbmode = (DCB_CMAP0 | NCMAP_PROTOCOL | 2548c2ecf20Sopenharmony_ci NCMAP_REGADDR_RREG | NPORT_DMODE_W1); 2558c2ecf20Sopenharmony_ci tmp = npregs->set.dcbdata0.bybytes.b3; 2568c2ecf20Sopenharmony_ci cmap_rev = tmp & 7; 2578c2ecf20Sopenharmony_ci board_rev = (tmp >> 4) & 7; 2588c2ecf20Sopenharmony_ci bitplanes = ((board_rev > 1) && (tmp & 0x80)) ? 8 : 24; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci npregs->set.dcbmode = (DCB_CMAP1 | NCMAP_PROTOCOL | 2618c2ecf20Sopenharmony_ci NCMAP_REGADDR_RREG | NPORT_DMODE_W1); 2628c2ecf20Sopenharmony_ci tmp = npregs->set.dcbdata0.bybytes.b3; 2638c2ecf20Sopenharmony_ci if ((tmp & 7) < cmap_rev) 2648c2ecf20Sopenharmony_ci cmap_rev = (tmp & 7); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci vc2_rev = (newport_vc2_get(npregs, VC2_IREG_CONFIG) >> 5) & 7; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL | 2698c2ecf20Sopenharmony_ci XM9_CRS_REVISION | NPORT_DMODE_W1); 2708c2ecf20Sopenharmony_ci xmap9_rev = npregs->set.dcbdata0.bybytes.b3 & 7; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL | 2738c2ecf20Sopenharmony_ci BT445_CSR_ADDR_REG | NPORT_DMODE_W1); 2748c2ecf20Sopenharmony_ci npregs->set.dcbdata0.bybytes.b3 = BT445_REVISION_REG; 2758c2ecf20Sopenharmony_ci npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL | 2768c2ecf20Sopenharmony_ci BT445_CSR_REVISION | NPORT_DMODE_W1); 2778c2ecf20Sopenharmony_ci bt445_rev = (npregs->set.dcbdata0.bybytes.b3 >> 4) - 0x0a; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci#define L(a) (char)('A'+(a)) 2808c2ecf20Sopenharmony_ci printk 2818c2ecf20Sopenharmony_ci ("NG1: Revision %d, %d bitplanes, REX3 revision %c, VC2 revision %c, xmap9 revision %c, cmap revision %c, bt445 revision %c\n", 2828c2ecf20Sopenharmony_ci board_rev, bitplanes, L(rex3_rev), L(vc2_rev), L(xmap9_rev), 2838c2ecf20Sopenharmony_ci L(cmap_rev ? (cmap_rev + 1) : 0), L(bt445_rev)); 2848c2ecf20Sopenharmony_ci#undef L 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (board_rev == 3) /* I don't know all affected revisions */ 2878c2ecf20Sopenharmony_ci xcurs_correction = 21; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void newport_exit(void) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci int i; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* free memory used by user font */ 2958c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NR_CONSOLES; i++) 2968c2ecf20Sopenharmony_ci newport_set_def_font(i, NULL); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/* Can't be __init, do_take_over_console may call it later */ 3008c2ecf20Sopenharmony_cistatic const char *newport_startup(void) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci int i; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci npregs->cset.config = NPORT_CFG_GD0; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (newport_wait(npregs)) 3078c2ecf20Sopenharmony_ci goto out_unmap; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci npregs->set.xstarti = TESTVAL; 3108c2ecf20Sopenharmony_ci if (npregs->set._xstart.word != XSTI_TO_FXSTART(TESTVAL)) 3118c2ecf20Sopenharmony_ci goto out_unmap; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NR_CONSOLES; i++) 3148c2ecf20Sopenharmony_ci font_data[i] = FONT_DATA; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci newport_reset(); 3178c2ecf20Sopenharmony_ci newport_get_revisions(); 3188c2ecf20Sopenharmony_ci newport_get_screensize(); 3198c2ecf20Sopenharmony_ci newport_has_init = 1; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return "SGI Newport"; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ciout_unmap: 3248c2ecf20Sopenharmony_ci return NULL; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic void newport_init(struct vc_data *vc, int init) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci int cols, rows; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci cols = newport_xsize / 8; 3328c2ecf20Sopenharmony_ci rows = newport_ysize / 16; 3338c2ecf20Sopenharmony_ci vc->vc_can_do_color = 1; 3348c2ecf20Sopenharmony_ci if (init) { 3358c2ecf20Sopenharmony_ci vc->vc_cols = cols; 3368c2ecf20Sopenharmony_ci vc->vc_rows = rows; 3378c2ecf20Sopenharmony_ci } else 3388c2ecf20Sopenharmony_ci vc_resize(vc, cols, rows); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic void newport_deinit(struct vc_data *c) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci if (!con_is_bound(&newport_con) && newport_has_init) { 3448c2ecf20Sopenharmony_ci newport_exit(); 3458c2ecf20Sopenharmony_ci newport_has_init = 0; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic void newport_clear(struct vc_data *vc, int sy, int sx, int height, 3508c2ecf20Sopenharmony_ci int width) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci int xend = ((sx + width) << 3) - 1; 3538c2ecf20Sopenharmony_ci int ystart = ((sy << 4) + topscan) & 0x3ff; 3548c2ecf20Sopenharmony_ci int yend = (((sy + height) << 4) + topscan - 1) & 0x3ff; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (logo_active) 3578c2ecf20Sopenharmony_ci return; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (ystart < yend) { 3608c2ecf20Sopenharmony_ci newport_clear_screen(sx << 3, ystart, xend, yend, 3618c2ecf20Sopenharmony_ci (vc->state.color & 0xf0) >> 4); 3628c2ecf20Sopenharmony_ci } else { 3638c2ecf20Sopenharmony_ci newport_clear_screen(sx << 3, ystart, xend, 1023, 3648c2ecf20Sopenharmony_ci (vc->state.color & 0xf0) >> 4); 3658c2ecf20Sopenharmony_ci newport_clear_screen(sx << 3, 0, xend, yend, 3668c2ecf20Sopenharmony_ci (vc->state.color & 0xf0) >> 4); 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic void newport_putc(struct vc_data *vc, int charattr, int ypos, 3718c2ecf20Sopenharmony_ci int xpos) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci unsigned char *p; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci p = &font_data[vc->vc_num][(charattr & 0xff) << 4]; 3768c2ecf20Sopenharmony_ci charattr = (charattr >> 8) & 0xff; 3778c2ecf20Sopenharmony_ci xpos <<= 3; 3788c2ecf20Sopenharmony_ci ypos <<= 4; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci newport_render_background(xpos, ypos, xpos, ypos, 3818c2ecf20Sopenharmony_ci (charattr & 0xf0) >> 4); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Set the color and drawing mode. */ 3848c2ecf20Sopenharmony_ci newport_wait(npregs); 3858c2ecf20Sopenharmony_ci npregs->set.colori = charattr & 0xf; 3868c2ecf20Sopenharmony_ci npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | 3878c2ecf20Sopenharmony_ci NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB | 3888c2ecf20Sopenharmony_ci NPORT_DMODE0_L32); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* Set coordinates for bitmap operation. */ 3918c2ecf20Sopenharmony_ci npregs->set.xystarti = (xpos << 16) | ((ypos + topscan) & 0x3ff); 3928c2ecf20Sopenharmony_ci npregs->set.xyendi = ((xpos + 7) << 16); 3938c2ecf20Sopenharmony_ci newport_wait(npregs); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* Go, baby, go... */ 3968c2ecf20Sopenharmony_ci RENDER(npregs, p); 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic void newport_putcs(struct vc_data *vc, const unsigned short *s, 4008c2ecf20Sopenharmony_ci int count, int ypos, int xpos) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci int i; 4038c2ecf20Sopenharmony_ci int charattr; 4048c2ecf20Sopenharmony_ci unsigned char *p; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci charattr = (scr_readw(s) >> 8) & 0xff; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci xpos <<= 3; 4098c2ecf20Sopenharmony_ci ypos <<= 4; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (!logo_active) 4128c2ecf20Sopenharmony_ci /* Clear the area behing the string */ 4138c2ecf20Sopenharmony_ci newport_render_background(xpos, ypos, 4148c2ecf20Sopenharmony_ci xpos + ((count - 1) << 3), ypos, 4158c2ecf20Sopenharmony_ci (charattr & 0xf0) >> 4); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci newport_wait(npregs); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* Set the color and drawing mode. */ 4208c2ecf20Sopenharmony_ci npregs->set.colori = charattr & 0xf; 4218c2ecf20Sopenharmony_ci npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | 4228c2ecf20Sopenharmony_ci NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB | 4238c2ecf20Sopenharmony_ci NPORT_DMODE0_L32); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci for (i = 0; i < count; i++, xpos += 8) { 4268c2ecf20Sopenharmony_ci p = &font_data[vc->vc_num][(scr_readw(s++) & 0xff) << 4]; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci newport_wait(npregs); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* Set coordinates for bitmap operation. */ 4318c2ecf20Sopenharmony_ci npregs->set.xystarti = 4328c2ecf20Sopenharmony_ci (xpos << 16) | ((ypos + topscan) & 0x3ff); 4338c2ecf20Sopenharmony_ci npregs->set.xyendi = ((xpos + 7) << 16); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* Go, baby, go... */ 4368c2ecf20Sopenharmony_ci RENDER(npregs, p); 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic void newport_cursor(struct vc_data *vc, int mode) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci unsigned short treg; 4438c2ecf20Sopenharmony_ci int xcurs, ycurs; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci switch (mode) { 4468c2ecf20Sopenharmony_ci case CM_ERASE: 4478c2ecf20Sopenharmony_ci treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); 4488c2ecf20Sopenharmony_ci newport_vc2_set(npregs, VC2_IREG_CONTROL, 4498c2ecf20Sopenharmony_ci (treg & ~(VC2_CTRL_ECDISP))); 4508c2ecf20Sopenharmony_ci break; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci case CM_MOVE: 4538c2ecf20Sopenharmony_ci case CM_DRAW: 4548c2ecf20Sopenharmony_ci treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); 4558c2ecf20Sopenharmony_ci newport_vc2_set(npregs, VC2_IREG_CONTROL, 4568c2ecf20Sopenharmony_ci (treg | VC2_CTRL_ECDISP)); 4578c2ecf20Sopenharmony_ci xcurs = (vc->vc_pos - vc->vc_visible_origin) / 2; 4588c2ecf20Sopenharmony_ci ycurs = ((xcurs / vc->vc_cols) << 4) + 31; 4598c2ecf20Sopenharmony_ci xcurs = ((xcurs % vc->vc_cols) << 3) + xcurs_correction; 4608c2ecf20Sopenharmony_ci newport_vc2_set(npregs, VC2_IREG_CURSX, xcurs); 4618c2ecf20Sopenharmony_ci newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs); 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int newport_switch(struct vc_data *vc) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci static int logo_drawn = 0; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci topscan = 0; 4708c2ecf20Sopenharmony_ci npregs->cset.topscan = 0x3ff; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (!logo_drawn) { 4738c2ecf20Sopenharmony_ci if (newport_show_logo()) { 4748c2ecf20Sopenharmony_ci logo_drawn = 1; 4758c2ecf20Sopenharmony_ci logo_active = 1; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return 1; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic int newport_blank(struct vc_data *c, int blank, int mode_switch) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci unsigned short treg; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (blank == 0) { 4878c2ecf20Sopenharmony_ci /* unblank console */ 4888c2ecf20Sopenharmony_ci treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); 4898c2ecf20Sopenharmony_ci newport_vc2_set(npregs, VC2_IREG_CONTROL, 4908c2ecf20Sopenharmony_ci (treg | VC2_CTRL_EDISP)); 4918c2ecf20Sopenharmony_ci } else { 4928c2ecf20Sopenharmony_ci /* blank console */ 4938c2ecf20Sopenharmony_ci treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); 4948c2ecf20Sopenharmony_ci newport_vc2_set(npregs, VC2_IREG_CONTROL, 4958c2ecf20Sopenharmony_ci (treg & ~(VC2_CTRL_EDISP))); 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci return 1; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic int newport_set_font(int unit, struct console_font *op) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci int w = op->width; 5038c2ecf20Sopenharmony_ci int h = op->height; 5048c2ecf20Sopenharmony_ci int size = h * op->charcount; 5058c2ecf20Sopenharmony_ci int i; 5068c2ecf20Sopenharmony_ci unsigned char *new_data, *data = op->data, *p; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* ladis: when I grow up, there will be a day... and more sizes will 5098c2ecf20Sopenharmony_ci * be supported ;-) */ 5108c2ecf20Sopenharmony_ci if ((w != 8) || (h != 16) 5118c2ecf20Sopenharmony_ci || (op->charcount != 256 && op->charcount != 512)) 5128c2ecf20Sopenharmony_ci return -EINVAL; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci if (!(new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, 5158c2ecf20Sopenharmony_ci GFP_USER))) return -ENOMEM; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci new_data += FONT_EXTRA_WORDS * sizeof(int); 5188c2ecf20Sopenharmony_ci FNTSIZE(new_data) = size; 5198c2ecf20Sopenharmony_ci FNTCHARCNT(new_data) = op->charcount; 5208c2ecf20Sopenharmony_ci REFCOUNT(new_data) = 0; /* usage counter */ 5218c2ecf20Sopenharmony_ci FNTSUM(new_data) = 0; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci p = new_data; 5248c2ecf20Sopenharmony_ci for (i = 0; i < op->charcount; i++) { 5258c2ecf20Sopenharmony_ci memcpy(p, data, h); 5268c2ecf20Sopenharmony_ci data += 32; 5278c2ecf20Sopenharmony_ci p += h; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci /* check if font is already used by other console */ 5318c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NR_CONSOLES; i++) { 5328c2ecf20Sopenharmony_ci if (font_data[i] != FONT_DATA 5338c2ecf20Sopenharmony_ci && FNTSIZE(font_data[i]) == size 5348c2ecf20Sopenharmony_ci && !memcmp(font_data[i], new_data, size)) { 5358c2ecf20Sopenharmony_ci kfree(new_data - FONT_EXTRA_WORDS * sizeof(int)); 5368c2ecf20Sopenharmony_ci /* current font is the same as the new one */ 5378c2ecf20Sopenharmony_ci if (i == unit) 5388c2ecf20Sopenharmony_ci return 0; 5398c2ecf20Sopenharmony_ci new_data = font_data[i]; 5408c2ecf20Sopenharmony_ci break; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci /* old font is user font */ 5448c2ecf20Sopenharmony_ci if (font_data[unit] != FONT_DATA) { 5458c2ecf20Sopenharmony_ci if (--REFCOUNT(font_data[unit]) == 0) 5468c2ecf20Sopenharmony_ci kfree(font_data[unit] - 5478c2ecf20Sopenharmony_ci FONT_EXTRA_WORDS * sizeof(int)); 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci REFCOUNT(new_data)++; 5508c2ecf20Sopenharmony_ci font_data[unit] = new_data; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic int newport_set_def_font(int unit, struct console_font *op) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci if (font_data[unit] != FONT_DATA) { 5588c2ecf20Sopenharmony_ci if (--REFCOUNT(font_data[unit]) == 0) 5598c2ecf20Sopenharmony_ci kfree(font_data[unit] - 5608c2ecf20Sopenharmony_ci FONT_EXTRA_WORDS * sizeof(int)); 5618c2ecf20Sopenharmony_ci font_data[unit] = FONT_DATA; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci return 0; 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic int newport_font_default(struct vc_data *vc, struct console_font *op, char *name) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci return newport_set_def_font(vc->vc_num, op); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic int newport_font_set(struct vc_data *vc, struct console_font *font, unsigned flags) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci return newport_set_font(vc->vc_num, font); 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic bool newport_scroll(struct vc_data *vc, unsigned int t, unsigned int b, 5788c2ecf20Sopenharmony_ci enum con_scroll dir, unsigned int lines) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci int count, x, y; 5818c2ecf20Sopenharmony_ci unsigned short *s, *d; 5828c2ecf20Sopenharmony_ci unsigned short chattr; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci logo_active = 0; /* it's time to disable the logo now.. */ 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (t == 0 && b == vc->vc_rows) { 5878c2ecf20Sopenharmony_ci if (dir == SM_UP) { 5888c2ecf20Sopenharmony_ci topscan = (topscan + (lines << 4)) & 0x3ff; 5898c2ecf20Sopenharmony_ci newport_clear_lines(vc->vc_rows - lines, 5908c2ecf20Sopenharmony_ci vc->vc_rows - 1, 5918c2ecf20Sopenharmony_ci (vc->state.color & 0xf0) >> 4); 5928c2ecf20Sopenharmony_ci } else { 5938c2ecf20Sopenharmony_ci topscan = (topscan + (-lines << 4)) & 0x3ff; 5948c2ecf20Sopenharmony_ci newport_clear_lines(0, lines - 1, 5958c2ecf20Sopenharmony_ci (vc->state.color & 0xf0) >> 4); 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci npregs->cset.topscan = (topscan - 1) & 0x3ff; 5988c2ecf20Sopenharmony_ci return false; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci count = (b - t - lines) * vc->vc_cols; 6028c2ecf20Sopenharmony_ci if (dir == SM_UP) { 6038c2ecf20Sopenharmony_ci x = 0; 6048c2ecf20Sopenharmony_ci y = t; 6058c2ecf20Sopenharmony_ci s = (unsigned short *) (vc->vc_origin + 6068c2ecf20Sopenharmony_ci vc->vc_size_row * (t + lines)); 6078c2ecf20Sopenharmony_ci d = (unsigned short *) (vc->vc_origin + 6088c2ecf20Sopenharmony_ci vc->vc_size_row * t); 6098c2ecf20Sopenharmony_ci while (count--) { 6108c2ecf20Sopenharmony_ci chattr = scr_readw(s++); 6118c2ecf20Sopenharmony_ci if (chattr != scr_readw(d)) { 6128c2ecf20Sopenharmony_ci newport_putc(vc, chattr, y, x); 6138c2ecf20Sopenharmony_ci scr_writew(chattr, d); 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci d++; 6168c2ecf20Sopenharmony_ci if (++x == vc->vc_cols) { 6178c2ecf20Sopenharmony_ci x = 0; 6188c2ecf20Sopenharmony_ci y++; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci d = (unsigned short *) (vc->vc_origin + 6228c2ecf20Sopenharmony_ci vc->vc_size_row * (b - lines)); 6238c2ecf20Sopenharmony_ci x = 0; 6248c2ecf20Sopenharmony_ci y = b - lines; 6258c2ecf20Sopenharmony_ci for (count = 0; count < (lines * vc->vc_cols); count++) { 6268c2ecf20Sopenharmony_ci if (scr_readw(d) != vc->vc_video_erase_char) { 6278c2ecf20Sopenharmony_ci newport_putc(vc, vc->vc_video_erase_char, 6288c2ecf20Sopenharmony_ci y, x); 6298c2ecf20Sopenharmony_ci scr_writew(vc->vc_video_erase_char, d); 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci d++; 6328c2ecf20Sopenharmony_ci if (++x == vc->vc_cols) { 6338c2ecf20Sopenharmony_ci x = 0; 6348c2ecf20Sopenharmony_ci y++; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci } else { 6388c2ecf20Sopenharmony_ci x = vc->vc_cols - 1; 6398c2ecf20Sopenharmony_ci y = b - 1; 6408c2ecf20Sopenharmony_ci s = (unsigned short *) (vc->vc_origin + 6418c2ecf20Sopenharmony_ci vc->vc_size_row * (b - lines) - 2); 6428c2ecf20Sopenharmony_ci d = (unsigned short *) (vc->vc_origin + 6438c2ecf20Sopenharmony_ci vc->vc_size_row * b - 2); 6448c2ecf20Sopenharmony_ci while (count--) { 6458c2ecf20Sopenharmony_ci chattr = scr_readw(s--); 6468c2ecf20Sopenharmony_ci if (chattr != scr_readw(d)) { 6478c2ecf20Sopenharmony_ci newport_putc(vc, chattr, y, x); 6488c2ecf20Sopenharmony_ci scr_writew(chattr, d); 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci d--; 6518c2ecf20Sopenharmony_ci if (x-- == 0) { 6528c2ecf20Sopenharmony_ci x = vc->vc_cols - 1; 6538c2ecf20Sopenharmony_ci y--; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci d = (unsigned short *) (vc->vc_origin + 6578c2ecf20Sopenharmony_ci vc->vc_size_row * t); 6588c2ecf20Sopenharmony_ci x = 0; 6598c2ecf20Sopenharmony_ci y = t; 6608c2ecf20Sopenharmony_ci for (count = 0; count < (lines * vc->vc_cols); count++) { 6618c2ecf20Sopenharmony_ci if (scr_readw(d) != vc->vc_video_erase_char) { 6628c2ecf20Sopenharmony_ci newport_putc(vc, vc->vc_video_erase_char, 6638c2ecf20Sopenharmony_ci y, x); 6648c2ecf20Sopenharmony_ci scr_writew(vc->vc_video_erase_char, d); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci d++; 6678c2ecf20Sopenharmony_ci if (++x == vc->vc_cols) { 6688c2ecf20Sopenharmony_ci x = 0; 6698c2ecf20Sopenharmony_ci y++; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci return true; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic void newport_save_screen(struct vc_data *vc) { } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ciconst struct consw newport_con = { 6798c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6808c2ecf20Sopenharmony_ci .con_startup = newport_startup, 6818c2ecf20Sopenharmony_ci .con_init = newport_init, 6828c2ecf20Sopenharmony_ci .con_deinit = newport_deinit, 6838c2ecf20Sopenharmony_ci .con_clear = newport_clear, 6848c2ecf20Sopenharmony_ci .con_putc = newport_putc, 6858c2ecf20Sopenharmony_ci .con_putcs = newport_putcs, 6868c2ecf20Sopenharmony_ci .con_cursor = newport_cursor, 6878c2ecf20Sopenharmony_ci .con_scroll = newport_scroll, 6888c2ecf20Sopenharmony_ci .con_switch = newport_switch, 6898c2ecf20Sopenharmony_ci .con_blank = newport_blank, 6908c2ecf20Sopenharmony_ci .con_font_set = newport_font_set, 6918c2ecf20Sopenharmony_ci .con_font_default = newport_font_default, 6928c2ecf20Sopenharmony_ci .con_save_screen = newport_save_screen 6938c2ecf20Sopenharmony_ci}; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cistatic int newport_probe(struct gio_device *dev, 6968c2ecf20Sopenharmony_ci const struct gio_device_id *id) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci int err; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (!dev->resource.start) 7018c2ecf20Sopenharmony_ci return -EINVAL; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (npregs) 7048c2ecf20Sopenharmony_ci return -EBUSY; /* we only support one Newport as console */ 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci newport_addr = dev->resource.start + 0xF0000; 7078c2ecf20Sopenharmony_ci if (!request_mem_region(newport_addr, NEWPORT_LEN, "Newport")) 7088c2ecf20Sopenharmony_ci return -ENODEV; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci npregs = (struct newport_regs *)/* ioremap cannot fail */ 7118c2ecf20Sopenharmony_ci ioremap(newport_addr, sizeof(struct newport_regs)); 7128c2ecf20Sopenharmony_ci console_lock(); 7138c2ecf20Sopenharmony_ci err = do_take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1); 7148c2ecf20Sopenharmony_ci console_unlock(); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (err) { 7178c2ecf20Sopenharmony_ci iounmap((void *)npregs); 7188c2ecf20Sopenharmony_ci release_mem_region(newport_addr, NEWPORT_LEN); 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci return err; 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic void newport_remove(struct gio_device *dev) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci give_up_console(&newport_con); 7268c2ecf20Sopenharmony_ci iounmap((void *)npregs); 7278c2ecf20Sopenharmony_ci release_mem_region(newport_addr, NEWPORT_LEN); 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic struct gio_device_id newport_ids[] = { 7318c2ecf20Sopenharmony_ci { .id = 0x7e }, 7328c2ecf20Sopenharmony_ci { .id = 0xff } 7338c2ecf20Sopenharmony_ci}; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ciMODULE_ALIAS("gio:7e"); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic struct gio_driver newport_driver = { 7388c2ecf20Sopenharmony_ci .name = "newport", 7398c2ecf20Sopenharmony_ci .id_table = newport_ids, 7408c2ecf20Sopenharmony_ci .probe = newport_probe, 7418c2ecf20Sopenharmony_ci .remove = newport_remove, 7428c2ecf20Sopenharmony_ci}; 7438c2ecf20Sopenharmony_cimodule_driver(newport_driver, gio_register_driver, gio_unregister_driver); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 746