18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/video/vt8623fb.c - fbdev driver for 38c2ecf20Sopenharmony_ci * integrated graphic core in VIA VT8623 [CLE266] chipset 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 88c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 98c2ecf20Sopenharmony_ci * more details. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Code is based on s3fb, some parts are from David Boucher's viafb 128c2ecf20Sopenharmony_ci * (http://davesdomain.org.uk/viafb/) 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/errno.h> 188c2ecf20Sopenharmony_ci#include <linux/string.h> 198c2ecf20Sopenharmony_ci#include <linux/mm.h> 208c2ecf20Sopenharmony_ci#include <linux/tty.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> 228c2ecf20Sopenharmony_ci#include <linux/fb.h> 238c2ecf20Sopenharmony_ci#include <linux/svga.h> 248c2ecf20Sopenharmony_ci#include <linux/init.h> 258c2ecf20Sopenharmony_ci#include <linux/pci.h> 268c2ecf20Sopenharmony_ci#include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */ 278c2ecf20Sopenharmony_ci#include <video/vga.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct vt8623fb_info { 308c2ecf20Sopenharmony_ci char __iomem *mmio_base; 318c2ecf20Sopenharmony_ci int wc_cookie; 328c2ecf20Sopenharmony_ci struct vgastate state; 338c2ecf20Sopenharmony_ci struct mutex open_lock; 348c2ecf20Sopenharmony_ci unsigned int ref_count; 358c2ecf20Sopenharmony_ci u32 pseudo_palette[16]; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------- */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const struct svga_fb_format vt8623fb_formats[] = { 438c2ecf20Sopenharmony_ci { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, 448c2ecf20Sopenharmony_ci FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP8, FB_VISUAL_PSEUDOCOLOR, 16, 16}, 458c2ecf20Sopenharmony_ci { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, 468c2ecf20Sopenharmony_ci FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 16, 16}, 478c2ecf20Sopenharmony_ci { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 1, 488c2ecf20Sopenharmony_ci FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 16, 16}, 498c2ecf20Sopenharmony_ci { 8, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, 508c2ecf20Sopenharmony_ci FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 8}, 518c2ecf20Sopenharmony_ci/* {16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0, 528c2ecf20Sopenharmony_ci FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4}, */ 538c2ecf20Sopenharmony_ci {16, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0, 548c2ecf20Sopenharmony_ci FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4}, 558c2ecf20Sopenharmony_ci {32, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 568c2ecf20Sopenharmony_ci FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 2, 2}, 578c2ecf20Sopenharmony_ci SVGA_FORMAT_END 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic const struct svga_pll vt8623_pll = {2, 127, 2, 7, 0, 3, 618c2ecf20Sopenharmony_ci 60000, 300000, 14318}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* CRT timing register sets */ 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END}; 668c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END}; 678c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END}; 688c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END}; 698c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END}; 708c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END}; 738c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END}; 748c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END}; 758c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END}; 768c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END}; 778c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END}; 808c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END}; 818c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END}; 828c2ecf20Sopenharmony_cistatic const struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic const struct svga_timing_regs vt8623_timing_regs = { 858c2ecf20Sopenharmony_ci vt8623_h_total_regs, vt8623_h_display_regs, vt8623_h_blank_start_regs, 868c2ecf20Sopenharmony_ci vt8623_h_blank_end_regs, vt8623_h_sync_start_regs, vt8623_h_sync_end_regs, 878c2ecf20Sopenharmony_ci vt8623_v_total_regs, vt8623_v_display_regs, vt8623_v_blank_start_regs, 888c2ecf20Sopenharmony_ci vt8623_v_blank_end_regs, vt8623_v_sync_start_regs, vt8623_v_sync_end_regs, 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------- */ 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* Module parameters */ 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic char *mode_option = "640x480-8@60"; 988c2ecf20Sopenharmony_cistatic int mtrr = 1; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ciMODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>"); 1018c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1028c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]"); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cimodule_param(mode_option, charp, 0644); 1058c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); 1068c2ecf20Sopenharmony_cimodule_param_named(mode, mode_option, charp, 0); 1078c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode, "Default video mode e.g. '648x480-8@60' (deprecated)"); 1088c2ecf20Sopenharmony_cimodule_param(mtrr, int, 0444); 1098c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)"); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------- */ 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void vt8623fb_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct vt8623fb_info *par = info->par; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci svga_tilecursor(par->state.vgabase, info, cursor); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic struct fb_tile_ops vt8623fb_tile_ops = { 1228c2ecf20Sopenharmony_ci .fb_settile = svga_settile, 1238c2ecf20Sopenharmony_ci .fb_tilecopy = svga_tilecopy, 1248c2ecf20Sopenharmony_ci .fb_tilefill = svga_tilefill, 1258c2ecf20Sopenharmony_ci .fb_tileblit = svga_tileblit, 1268c2ecf20Sopenharmony_ci .fb_tilecursor = vt8623fb_tilecursor, 1278c2ecf20Sopenharmony_ci .fb_get_tilemax = svga_get_tilemax, 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------- */ 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* image data is MSB-first, fb structure is MSB-first too */ 1358c2ecf20Sopenharmony_cistatic inline u32 expand_color(u32 c) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* vt8623fb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */ 1418c2ecf20Sopenharmony_cistatic void vt8623fb_iplan_imageblit(struct fb_info *info, const struct fb_image *image) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci u32 fg = expand_color(image->fg_color); 1448c2ecf20Sopenharmony_ci u32 bg = expand_color(image->bg_color); 1458c2ecf20Sopenharmony_ci const u8 *src1, *src; 1468c2ecf20Sopenharmony_ci u8 __iomem *dst1; 1478c2ecf20Sopenharmony_ci u32 __iomem *dst; 1488c2ecf20Sopenharmony_ci u32 val; 1498c2ecf20Sopenharmony_ci int x, y; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci src1 = image->data; 1528c2ecf20Sopenharmony_ci dst1 = info->screen_base + (image->dy * info->fix.line_length) 1538c2ecf20Sopenharmony_ci + ((image->dx / 8) * 4); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci for (y = 0; y < image->height; y++) { 1568c2ecf20Sopenharmony_ci src = src1; 1578c2ecf20Sopenharmony_ci dst = (u32 __iomem *) dst1; 1588c2ecf20Sopenharmony_ci for (x = 0; x < image->width; x += 8) { 1598c2ecf20Sopenharmony_ci val = *(src++) * 0x01010101; 1608c2ecf20Sopenharmony_ci val = (val & fg) | (~val & bg); 1618c2ecf20Sopenharmony_ci fb_writel(val, dst++); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci src1 += image->width / 8; 1648c2ecf20Sopenharmony_ci dst1 += info->fix.line_length; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/* vt8623fb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */ 1698c2ecf20Sopenharmony_cistatic void vt8623fb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci u32 fg = expand_color(rect->color); 1728c2ecf20Sopenharmony_ci u8 __iomem *dst1; 1738c2ecf20Sopenharmony_ci u32 __iomem *dst; 1748c2ecf20Sopenharmony_ci int x, y; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci dst1 = info->screen_base + (rect->dy * info->fix.line_length) 1778c2ecf20Sopenharmony_ci + ((rect->dx / 8) * 4); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci for (y = 0; y < rect->height; y++) { 1808c2ecf20Sopenharmony_ci dst = (u32 __iomem *) dst1; 1818c2ecf20Sopenharmony_ci for (x = 0; x < rect->width; x += 8) { 1828c2ecf20Sopenharmony_ci fb_writel(fg, dst++); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci dst1 += info->fix.line_length; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */ 1908c2ecf20Sopenharmony_cistatic inline u32 expand_pixel(u32 c) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci return (((c & 1) << 24) | ((c & 2) << 27) | ((c & 4) << 14) | ((c & 8) << 17) | 1938c2ecf20Sopenharmony_ci ((c & 16) << 4) | ((c & 32) << 7) | ((c & 64) >> 6) | ((c & 128) >> 3)) * 0xF; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* vt8623fb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */ 1978c2ecf20Sopenharmony_cistatic void vt8623fb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci u32 fg = image->fg_color * 0x11111111; 2008c2ecf20Sopenharmony_ci u32 bg = image->bg_color * 0x11111111; 2018c2ecf20Sopenharmony_ci const u8 *src1, *src; 2028c2ecf20Sopenharmony_ci u8 __iomem *dst1; 2038c2ecf20Sopenharmony_ci u32 __iomem *dst; 2048c2ecf20Sopenharmony_ci u32 val; 2058c2ecf20Sopenharmony_ci int x, y; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci src1 = image->data; 2088c2ecf20Sopenharmony_ci dst1 = info->screen_base + (image->dy * info->fix.line_length) 2098c2ecf20Sopenharmony_ci + ((image->dx / 8) * 4); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci for (y = 0; y < image->height; y++) { 2128c2ecf20Sopenharmony_ci src = src1; 2138c2ecf20Sopenharmony_ci dst = (u32 __iomem *) dst1; 2148c2ecf20Sopenharmony_ci for (x = 0; x < image->width; x += 8) { 2158c2ecf20Sopenharmony_ci val = expand_pixel(*(src++)); 2168c2ecf20Sopenharmony_ci val = (val & fg) | (~val & bg); 2178c2ecf20Sopenharmony_ci fb_writel(val, dst++); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci src1 += image->width / 8; 2208c2ecf20Sopenharmony_ci dst1 += info->fix.line_length; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic void vt8623fb_imageblit(struct fb_info *info, const struct fb_image *image) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci if ((info->var.bits_per_pixel == 4) && (image->depth == 1) 2278c2ecf20Sopenharmony_ci && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) { 2288c2ecf20Sopenharmony_ci if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES) 2298c2ecf20Sopenharmony_ci vt8623fb_iplan_imageblit(info, image); 2308c2ecf20Sopenharmony_ci else 2318c2ecf20Sopenharmony_ci vt8623fb_cfb4_imageblit(info, image); 2328c2ecf20Sopenharmony_ci } else 2338c2ecf20Sopenharmony_ci cfb_imageblit(info, image); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic void vt8623fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci if ((info->var.bits_per_pixel == 4) 2398c2ecf20Sopenharmony_ci && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0) 2408c2ecf20Sopenharmony_ci && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)) 2418c2ecf20Sopenharmony_ci vt8623fb_iplan_fillrect(info, rect); 2428c2ecf20Sopenharmony_ci else 2438c2ecf20Sopenharmony_ci cfb_fillrect(info, rect); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------- */ 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void vt8623_set_pixclock(struct fb_info *info, u32 pixclock) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct vt8623fb_info *par = info->par; 2538c2ecf20Sopenharmony_ci u16 m, n, r; 2548c2ecf20Sopenharmony_ci u8 regval; 2558c2ecf20Sopenharmony_ci int rv; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci rv = svga_compute_pll(&vt8623_pll, 1000000000 / pixclock, &m, &n, &r, info->node); 2588c2ecf20Sopenharmony_ci if (rv < 0) { 2598c2ecf20Sopenharmony_ci fb_err(info, "cannot set requested pixclock, keeping old value\n"); 2608c2ecf20Sopenharmony_ci return; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Set VGA misc register */ 2648c2ecf20Sopenharmony_ci regval = vga_r(par->state.vgabase, VGA_MIS_R); 2658c2ecf20Sopenharmony_ci vga_w(par->state.vgabase, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* Set clock registers */ 2688c2ecf20Sopenharmony_ci vga_wseq(par->state.vgabase, 0x46, (n | (r << 6))); 2698c2ecf20Sopenharmony_ci vga_wseq(par->state.vgabase, 0x47, m); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci udelay(1000); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* PLL reset */ 2748c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x40, 0x02, 0x02); 2758c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x40, 0x00, 0x02); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic int vt8623fb_open(struct fb_info *info, int user) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct vt8623fb_info *par = info->par; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci mutex_lock(&(par->open_lock)); 2848c2ecf20Sopenharmony_ci if (par->ref_count == 0) { 2858c2ecf20Sopenharmony_ci void __iomem *vgabase = par->state.vgabase; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci memset(&(par->state), 0, sizeof(struct vgastate)); 2888c2ecf20Sopenharmony_ci par->state.vgabase = vgabase; 2898c2ecf20Sopenharmony_ci par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP; 2908c2ecf20Sopenharmony_ci par->state.num_crtc = 0xA2; 2918c2ecf20Sopenharmony_ci par->state.num_seq = 0x50; 2928c2ecf20Sopenharmony_ci save_vga(&(par->state)); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci par->ref_count++; 2968c2ecf20Sopenharmony_ci mutex_unlock(&(par->open_lock)); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci return 0; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic int vt8623fb_release(struct fb_info *info, int user) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct vt8623fb_info *par = info->par; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci mutex_lock(&(par->open_lock)); 3068c2ecf20Sopenharmony_ci if (par->ref_count == 0) { 3078c2ecf20Sopenharmony_ci mutex_unlock(&(par->open_lock)); 3088c2ecf20Sopenharmony_ci return -EINVAL; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (par->ref_count == 1) 3128c2ecf20Sopenharmony_ci restore_vga(&(par->state)); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci par->ref_count--; 3158c2ecf20Sopenharmony_ci mutex_unlock(&(par->open_lock)); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic int vt8623fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci int rv, mem, step; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* Find appropriate format */ 3258c2ecf20Sopenharmony_ci rv = svga_match_format (vt8623fb_formats, var, NULL); 3268c2ecf20Sopenharmony_ci if (rv < 0) 3278c2ecf20Sopenharmony_ci { 3288c2ecf20Sopenharmony_ci fb_err(info, "unsupported mode requested\n"); 3298c2ecf20Sopenharmony_ci return rv; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Do not allow to have real resoulution larger than virtual */ 3338c2ecf20Sopenharmony_ci if (var->xres > var->xres_virtual) 3348c2ecf20Sopenharmony_ci var->xres_virtual = var->xres; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (var->yres > var->yres_virtual) 3378c2ecf20Sopenharmony_ci var->yres_virtual = var->yres; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* Round up xres_virtual to have proper alignment of lines */ 3408c2ecf20Sopenharmony_ci step = vt8623fb_formats[rv].xresstep - 1; 3418c2ecf20Sopenharmony_ci var->xres_virtual = (var->xres_virtual+step) & ~step; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Check whether have enough memory */ 3448c2ecf20Sopenharmony_ci mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual; 3458c2ecf20Sopenharmony_ci if (mem > info->screen_size) 3468c2ecf20Sopenharmony_ci { 3478c2ecf20Sopenharmony_ci fb_err(info, "not enough framebuffer memory (%d kB requested, %d kB available)\n", 3488c2ecf20Sopenharmony_ci mem >> 10, (unsigned int) (info->screen_size >> 10)); 3498c2ecf20Sopenharmony_ci return -EINVAL; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* Text mode is limited to 256 kB of memory */ 3538c2ecf20Sopenharmony_ci if ((var->bits_per_pixel == 0) && (mem > (256*1024))) 3548c2ecf20Sopenharmony_ci { 3558c2ecf20Sopenharmony_ci fb_err(info, "text framebuffer size too large (%d kB requested, 256 kB possible)\n", 3568c2ecf20Sopenharmony_ci mem >> 10); 3578c2ecf20Sopenharmony_ci return -EINVAL; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci rv = svga_check_timings (&vt8623_timing_regs, var, info->node); 3618c2ecf20Sopenharmony_ci if (rv < 0) 3628c2ecf20Sopenharmony_ci { 3638c2ecf20Sopenharmony_ci fb_err(info, "invalid timings requested\n"); 3648c2ecf20Sopenharmony_ci return rv; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* Interlaced mode not supported */ 3688c2ecf20Sopenharmony_ci if (var->vmode & FB_VMODE_INTERLACED) 3698c2ecf20Sopenharmony_ci return -EINVAL; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic int vt8623fb_set_par(struct fb_info *info) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci u32 mode, offset_value, fetch_value, screen_size; 3788c2ecf20Sopenharmony_ci struct vt8623fb_info *par = info->par; 3798c2ecf20Sopenharmony_ci u32 bpp = info->var.bits_per_pixel; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (bpp != 0) { 3828c2ecf20Sopenharmony_ci info->fix.ypanstep = 1; 3838c2ecf20Sopenharmony_ci info->fix.line_length = (info->var.xres_virtual * bpp) / 8; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci info->flags &= ~FBINFO_MISC_TILEBLITTING; 3868c2ecf20Sopenharmony_ci info->tileops = NULL; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* in 4bpp supports 8p wide tiles only, any tiles otherwise */ 3898c2ecf20Sopenharmony_ci info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0); 3908c2ecf20Sopenharmony_ci info->pixmap.blit_y = ~(u32)0; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci offset_value = (info->var.xres_virtual * bpp) / 64; 3938c2ecf20Sopenharmony_ci fetch_value = ((info->var.xres * bpp) / 128) + 4; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (bpp == 4) 3968c2ecf20Sopenharmony_ci fetch_value = (info->var.xres / 8) + 8; /* + 0 is OK */ 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci screen_size = info->var.yres_virtual * info->fix.line_length; 3998c2ecf20Sopenharmony_ci } else { 4008c2ecf20Sopenharmony_ci info->fix.ypanstep = 16; 4018c2ecf20Sopenharmony_ci info->fix.line_length = 0; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci info->flags |= FBINFO_MISC_TILEBLITTING; 4048c2ecf20Sopenharmony_ci info->tileops = &vt8623fb_tile_ops; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* supports 8x16 tiles only */ 4078c2ecf20Sopenharmony_ci info->pixmap.blit_x = 1 << (8 - 1); 4088c2ecf20Sopenharmony_ci info->pixmap.blit_y = 1 << (16 - 1); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci offset_value = info->var.xres_virtual / 16; 4118c2ecf20Sopenharmony_ci fetch_value = (info->var.xres / 8) + 8; 4128c2ecf20Sopenharmony_ci screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci info->var.xoffset = 0; 4168c2ecf20Sopenharmony_ci info->var.yoffset = 0; 4178c2ecf20Sopenharmony_ci info->var.activate = FB_ACTIVATE_NOW; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* Unlock registers */ 4208c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x10, 0x01, 0x01); 4218c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x80); 4228c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x47, 0x00, 0x01); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* Device, screen and sync off */ 4258c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); 4268c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x36, 0x30, 0x30); 4278c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x17, 0x00, 0x80); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* Set default values */ 4308c2ecf20Sopenharmony_ci svga_set_default_gfx_regs(par->state.vgabase); 4318c2ecf20Sopenharmony_ci svga_set_default_atc_regs(par->state.vgabase); 4328c2ecf20Sopenharmony_ci svga_set_default_seq_regs(par->state.vgabase); 4338c2ecf20Sopenharmony_ci svga_set_default_crt_regs(par->state.vgabase); 4348c2ecf20Sopenharmony_ci svga_wcrt_multi(par->state.vgabase, vt8623_line_compare_regs, 0xFFFFFFFF); 4358c2ecf20Sopenharmony_ci svga_wcrt_multi(par->state.vgabase, vt8623_start_address_regs, 0); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci svga_wcrt_multi(par->state.vgabase, vt8623_offset_regs, offset_value); 4388c2ecf20Sopenharmony_ci svga_wseq_multi(par->state.vgabase, vt8623_fetch_count_regs, fetch_value); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* Clear H/V Skew */ 4418c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x03, 0x00, 0x60); 4428c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x05, 0x00, 0x60); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (info->var.vmode & FB_VMODE_DOUBLE) 4458c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x09, 0x80, 0x80); 4468c2ecf20Sopenharmony_ci else 4478c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x09, 0x00, 0x80); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x1E, 0xF0, 0xF0); // DI/DVP bus 4508c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x2A, 0x0F, 0x0F); // DI/DVP bus 4518c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x16, 0x08, 0xBF); // FIFO read threshold 4528c2ecf20Sopenharmony_ci vga_wseq(par->state.vgabase, 0x17, 0x1F); // FIFO depth 4538c2ecf20Sopenharmony_ci vga_wseq(par->state.vgabase, 0x18, 0x4E); 4548c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x1A, 0x08, 0x08); // enable MMIO ? 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci vga_wcrt(par->state.vgabase, 0x32, 0x00); 4578c2ecf20Sopenharmony_ci vga_wcrt(par->state.vgabase, 0x34, 0x00); 4588c2ecf20Sopenharmony_ci vga_wcrt(par->state.vgabase, 0x6A, 0x80); 4598c2ecf20Sopenharmony_ci vga_wcrt(par->state.vgabase, 0x6A, 0xC0); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci vga_wgfx(par->state.vgabase, 0x20, 0x00); 4628c2ecf20Sopenharmony_ci vga_wgfx(par->state.vgabase, 0x21, 0x00); 4638c2ecf20Sopenharmony_ci vga_wgfx(par->state.vgabase, 0x22, 0x00); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* Set SR15 according to number of bits per pixel */ 4668c2ecf20Sopenharmony_ci mode = svga_match_format(vt8623fb_formats, &(info->var), &(info->fix)); 4678c2ecf20Sopenharmony_ci switch (mode) { 4688c2ecf20Sopenharmony_ci case 0: 4698c2ecf20Sopenharmony_ci fb_dbg(info, "text mode\n"); 4708c2ecf20Sopenharmony_ci svga_set_textmode_vga_regs(par->state.vgabase); 4718c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x15, 0x00, 0xFE); 4728c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x11, 0x60, 0x70); 4738c2ecf20Sopenharmony_ci break; 4748c2ecf20Sopenharmony_ci case 1: 4758c2ecf20Sopenharmony_ci fb_dbg(info, "4 bit pseudocolor\n"); 4768c2ecf20Sopenharmony_ci vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40); 4778c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x15, 0x20, 0xFE); 4788c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x70); 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci case 2: 4818c2ecf20Sopenharmony_ci fb_dbg(info, "4 bit pseudocolor, planar\n"); 4828c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x15, 0x00, 0xFE); 4838c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x70); 4848c2ecf20Sopenharmony_ci break; 4858c2ecf20Sopenharmony_ci case 3: 4868c2ecf20Sopenharmony_ci fb_dbg(info, "8 bit pseudocolor\n"); 4878c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x15, 0x22, 0xFE); 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci case 4: 4908c2ecf20Sopenharmony_ci fb_dbg(info, "5/6/5 truecolor\n"); 4918c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x15, 0xB6, 0xFE); 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci case 5: 4948c2ecf20Sopenharmony_ci fb_dbg(info, "8/8/8 truecolor\n"); 4958c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x15, 0xAE, 0xFE); 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci default: 4988c2ecf20Sopenharmony_ci printk(KERN_ERR "vt8623fb: unsupported mode - bug\n"); 4998c2ecf20Sopenharmony_ci return (-EINVAL); 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci vt8623_set_pixclock(info, info->var.pixclock); 5038c2ecf20Sopenharmony_ci svga_set_timings(par->state.vgabase, &vt8623_timing_regs, &(info->var), 1, 1, 5048c2ecf20Sopenharmony_ci (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, 1, 5058c2ecf20Sopenharmony_ci 1, info->node); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (screen_size > info->screen_size) 5088c2ecf20Sopenharmony_ci screen_size = info->screen_size; 5098c2ecf20Sopenharmony_ci memset_io(info->screen_base, 0x00, screen_size); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* Device and screen back on */ 5128c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80); 5138c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x36, 0x00, 0x30); 5148c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return 0; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic int vt8623fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 5218c2ecf20Sopenharmony_ci u_int transp, struct fb_info *fb) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci switch (fb->var.bits_per_pixel) { 5248c2ecf20Sopenharmony_ci case 0: 5258c2ecf20Sopenharmony_ci case 4: 5268c2ecf20Sopenharmony_ci if (regno >= 16) 5278c2ecf20Sopenharmony_ci return -EINVAL; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci outb(0x0F, VGA_PEL_MSK); 5308c2ecf20Sopenharmony_ci outb(regno, VGA_PEL_IW); 5318c2ecf20Sopenharmony_ci outb(red >> 10, VGA_PEL_D); 5328c2ecf20Sopenharmony_ci outb(green >> 10, VGA_PEL_D); 5338c2ecf20Sopenharmony_ci outb(blue >> 10, VGA_PEL_D); 5348c2ecf20Sopenharmony_ci break; 5358c2ecf20Sopenharmony_ci case 8: 5368c2ecf20Sopenharmony_ci if (regno >= 256) 5378c2ecf20Sopenharmony_ci return -EINVAL; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci outb(0xFF, VGA_PEL_MSK); 5408c2ecf20Sopenharmony_ci outb(regno, VGA_PEL_IW); 5418c2ecf20Sopenharmony_ci outb(red >> 10, VGA_PEL_D); 5428c2ecf20Sopenharmony_ci outb(green >> 10, VGA_PEL_D); 5438c2ecf20Sopenharmony_ci outb(blue >> 10, VGA_PEL_D); 5448c2ecf20Sopenharmony_ci break; 5458c2ecf20Sopenharmony_ci case 16: 5468c2ecf20Sopenharmony_ci if (regno >= 16) 5478c2ecf20Sopenharmony_ci return 0; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (fb->var.green.length == 5) 5508c2ecf20Sopenharmony_ci ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) | 5518c2ecf20Sopenharmony_ci ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11); 5528c2ecf20Sopenharmony_ci else if (fb->var.green.length == 6) 5538c2ecf20Sopenharmony_ci ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) | 5548c2ecf20Sopenharmony_ci ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); 5558c2ecf20Sopenharmony_ci else 5568c2ecf20Sopenharmony_ci return -EINVAL; 5578c2ecf20Sopenharmony_ci break; 5588c2ecf20Sopenharmony_ci case 24: 5598c2ecf20Sopenharmony_ci case 32: 5608c2ecf20Sopenharmony_ci if (regno >= 16) 5618c2ecf20Sopenharmony_ci return 0; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci /* ((transp & 0xFF00) << 16) */ 5648c2ecf20Sopenharmony_ci ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) | 5658c2ecf20Sopenharmony_ci (green & 0xFF00) | ((blue & 0xFF00) >> 8); 5668c2ecf20Sopenharmony_ci break; 5678c2ecf20Sopenharmony_ci default: 5688c2ecf20Sopenharmony_ci return -EINVAL; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic int vt8623fb_blank(int blank_mode, struct fb_info *info) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct vt8623fb_info *par = info->par; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci switch (blank_mode) { 5808c2ecf20Sopenharmony_ci case FB_BLANK_UNBLANK: 5818c2ecf20Sopenharmony_ci fb_dbg(info, "unblank\n"); 5828c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x36, 0x00, 0x30); 5838c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci case FB_BLANK_NORMAL: 5868c2ecf20Sopenharmony_ci fb_dbg(info, "blank\n"); 5878c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x36, 0x00, 0x30); 5888c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); 5898c2ecf20Sopenharmony_ci break; 5908c2ecf20Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 5918c2ecf20Sopenharmony_ci fb_dbg(info, "DPMS standby (hsync off)\n"); 5928c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x36, 0x10, 0x30); 5938c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); 5948c2ecf20Sopenharmony_ci break; 5958c2ecf20Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 5968c2ecf20Sopenharmony_ci fb_dbg(info, "DPMS suspend (vsync off)\n"); 5978c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x36, 0x20, 0x30); 5988c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); 5998c2ecf20Sopenharmony_ci break; 6008c2ecf20Sopenharmony_ci case FB_BLANK_POWERDOWN: 6018c2ecf20Sopenharmony_ci fb_dbg(info, "DPMS off (no sync)\n"); 6028c2ecf20Sopenharmony_ci svga_wcrt_mask(par->state.vgabase, 0x36, 0x30, 0x30); 6038c2ecf20Sopenharmony_ci svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci return 0; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci struct vt8623fb_info *par = info->par; 6148c2ecf20Sopenharmony_ci unsigned int offset; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* Calculate the offset */ 6178c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 0) { 6188c2ecf20Sopenharmony_ci offset = (var->yoffset / 16) * info->var.xres_virtual 6198c2ecf20Sopenharmony_ci + var->xoffset; 6208c2ecf20Sopenharmony_ci offset = offset >> 3; 6218c2ecf20Sopenharmony_ci } else { 6228c2ecf20Sopenharmony_ci offset = (var->yoffset * info->fix.line_length) + 6238c2ecf20Sopenharmony_ci (var->xoffset * info->var.bits_per_pixel / 8); 6248c2ecf20Sopenharmony_ci offset = offset >> ((info->var.bits_per_pixel == 4) ? 2 : 1); 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* Set the offset */ 6288c2ecf20Sopenharmony_ci svga_wcrt_multi(par->state.vgabase, vt8623_start_address_regs, offset); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci return 0; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------- */ 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci/* Frame buffer operations */ 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic const struct fb_ops vt8623fb_ops = { 6408c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6418c2ecf20Sopenharmony_ci .fb_open = vt8623fb_open, 6428c2ecf20Sopenharmony_ci .fb_release = vt8623fb_release, 6438c2ecf20Sopenharmony_ci .fb_check_var = vt8623fb_check_var, 6448c2ecf20Sopenharmony_ci .fb_set_par = vt8623fb_set_par, 6458c2ecf20Sopenharmony_ci .fb_setcolreg = vt8623fb_setcolreg, 6468c2ecf20Sopenharmony_ci .fb_blank = vt8623fb_blank, 6478c2ecf20Sopenharmony_ci .fb_pan_display = vt8623fb_pan_display, 6488c2ecf20Sopenharmony_ci .fb_fillrect = vt8623fb_fillrect, 6498c2ecf20Sopenharmony_ci .fb_copyarea = cfb_copyarea, 6508c2ecf20Sopenharmony_ci .fb_imageblit = vt8623fb_imageblit, 6518c2ecf20Sopenharmony_ci .fb_get_caps = svga_get_caps, 6528c2ecf20Sopenharmony_ci}; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci/* PCI probe */ 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci struct pci_bus_region bus_reg; 6608c2ecf20Sopenharmony_ci struct resource vga_res; 6618c2ecf20Sopenharmony_ci struct fb_info *info; 6628c2ecf20Sopenharmony_ci struct vt8623fb_info *par; 6638c2ecf20Sopenharmony_ci unsigned int memsize1, memsize2; 6648c2ecf20Sopenharmony_ci int rc; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* Ignore secondary VGA device because there is no VGA arbitration */ 6678c2ecf20Sopenharmony_ci if (! svga_primary_device(dev)) { 6688c2ecf20Sopenharmony_ci dev_info(&(dev->dev), "ignoring secondary device\n"); 6698c2ecf20Sopenharmony_ci return -ENODEV; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* Allocate and fill driver data structure */ 6738c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(struct vt8623fb_info), &(dev->dev)); 6748c2ecf20Sopenharmony_ci if (!info) 6758c2ecf20Sopenharmony_ci return -ENOMEM; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci par = info->par; 6788c2ecf20Sopenharmony_ci mutex_init(&par->open_lock); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN; 6818c2ecf20Sopenharmony_ci info->fbops = &vt8623fb_ops; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci /* Prepare PCI device */ 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci rc = pci_enable_device(dev); 6868c2ecf20Sopenharmony_ci if (rc < 0) { 6878c2ecf20Sopenharmony_ci dev_err(info->device, "cannot enable PCI device\n"); 6888c2ecf20Sopenharmony_ci goto err_enable_device; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci rc = pci_request_regions(dev, "vt8623fb"); 6928c2ecf20Sopenharmony_ci if (rc < 0) { 6938c2ecf20Sopenharmony_ci dev_err(info->device, "cannot reserve framebuffer region\n"); 6948c2ecf20Sopenharmony_ci goto err_request_regions; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci info->fix.smem_start = pci_resource_start(dev, 0); 6988c2ecf20Sopenharmony_ci info->fix.smem_len = pci_resource_len(dev, 0); 6998c2ecf20Sopenharmony_ci info->fix.mmio_start = pci_resource_start(dev, 1); 7008c2ecf20Sopenharmony_ci info->fix.mmio_len = pci_resource_len(dev, 1); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* Map physical IO memory address into kernel space */ 7038c2ecf20Sopenharmony_ci info->screen_base = pci_iomap_wc(dev, 0, 0); 7048c2ecf20Sopenharmony_ci if (! info->screen_base) { 7058c2ecf20Sopenharmony_ci rc = -ENOMEM; 7068c2ecf20Sopenharmony_ci dev_err(info->device, "iomap for framebuffer failed\n"); 7078c2ecf20Sopenharmony_ci goto err_iomap_1; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci par->mmio_base = pci_iomap(dev, 1, 0); 7118c2ecf20Sopenharmony_ci if (! par->mmio_base) { 7128c2ecf20Sopenharmony_ci rc = -ENOMEM; 7138c2ecf20Sopenharmony_ci dev_err(info->device, "iomap for MMIO failed\n"); 7148c2ecf20Sopenharmony_ci goto err_iomap_2; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci bus_reg.start = 0; 7188c2ecf20Sopenharmony_ci bus_reg.end = 64 * 1024; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci vga_res.flags = IORESOURCE_IO; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* Find how many physical memory there is on card */ 7278c2ecf20Sopenharmony_ci memsize1 = (vga_rseq(par->state.vgabase, 0x34) + 1) >> 1; 7288c2ecf20Sopenharmony_ci memsize2 = vga_rseq(par->state.vgabase, 0x39) << 2; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2)) 7318c2ecf20Sopenharmony_ci info->screen_size = memsize1 << 20; 7328c2ecf20Sopenharmony_ci else { 7338c2ecf20Sopenharmony_ci dev_err(info->device, "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2); 7348c2ecf20Sopenharmony_ci info->screen_size = 16 << 20; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci info->fix.smem_len = info->screen_size; 7388c2ecf20Sopenharmony_ci strcpy(info->fix.id, "VIA VT8623"); 7398c2ecf20Sopenharmony_ci info->fix.type = FB_TYPE_PACKED_PIXELS; 7408c2ecf20Sopenharmony_ci info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 7418c2ecf20Sopenharmony_ci info->fix.ypanstep = 0; 7428c2ecf20Sopenharmony_ci info->fix.accel = FB_ACCEL_NONE; 7438c2ecf20Sopenharmony_ci info->pseudo_palette = (void*)par->pseudo_palette; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* Prepare startup mode */ 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci kernel_param_lock(THIS_MODULE); 7488c2ecf20Sopenharmony_ci rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); 7498c2ecf20Sopenharmony_ci kernel_param_unlock(THIS_MODULE); 7508c2ecf20Sopenharmony_ci if (! ((rc == 1) || (rc == 2))) { 7518c2ecf20Sopenharmony_ci rc = -EINVAL; 7528c2ecf20Sopenharmony_ci dev_err(info->device, "mode %s not found\n", mode_option); 7538c2ecf20Sopenharmony_ci goto err_find_mode; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci rc = fb_alloc_cmap(&info->cmap, 256, 0); 7578c2ecf20Sopenharmony_ci if (rc < 0) { 7588c2ecf20Sopenharmony_ci dev_err(info->device, "cannot allocate colormap\n"); 7598c2ecf20Sopenharmony_ci goto err_alloc_cmap; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci rc = register_framebuffer(info); 7638c2ecf20Sopenharmony_ci if (rc < 0) { 7648c2ecf20Sopenharmony_ci dev_err(info->device, "cannot register framebuffer\n"); 7658c2ecf20Sopenharmony_ci goto err_reg_fb; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci fb_info(info, "%s on %s, %d MB RAM\n", 7698c2ecf20Sopenharmony_ci info->fix.id, pci_name(dev), info->fix.smem_len >> 20); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci /* Record a reference to the driver data */ 7728c2ecf20Sopenharmony_ci pci_set_drvdata(dev, info); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (mtrr) 7758c2ecf20Sopenharmony_ci par->wc_cookie = arch_phys_wc_add(info->fix.smem_start, 7768c2ecf20Sopenharmony_ci info->fix.smem_len); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci return 0; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci /* Error handling */ 7818c2ecf20Sopenharmony_cierr_reg_fb: 7828c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 7838c2ecf20Sopenharmony_cierr_alloc_cmap: 7848c2ecf20Sopenharmony_cierr_find_mode: 7858c2ecf20Sopenharmony_ci pci_iounmap(dev, par->mmio_base); 7868c2ecf20Sopenharmony_cierr_iomap_2: 7878c2ecf20Sopenharmony_ci pci_iounmap(dev, info->screen_base); 7888c2ecf20Sopenharmony_cierr_iomap_1: 7898c2ecf20Sopenharmony_ci pci_release_regions(dev); 7908c2ecf20Sopenharmony_cierr_request_regions: 7918c2ecf20Sopenharmony_ci/* pci_disable_device(dev); */ 7928c2ecf20Sopenharmony_cierr_enable_device: 7938c2ecf20Sopenharmony_ci framebuffer_release(info); 7948c2ecf20Sopenharmony_ci return rc; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci/* PCI remove */ 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic void vt8623_pci_remove(struct pci_dev *dev) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct fb_info *info = pci_get_drvdata(dev); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (info) { 8048c2ecf20Sopenharmony_ci struct vt8623fb_info *par = info->par; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci arch_phys_wc_del(par->wc_cookie); 8078c2ecf20Sopenharmony_ci unregister_framebuffer(info); 8088c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci pci_iounmap(dev, info->screen_base); 8118c2ecf20Sopenharmony_ci pci_iounmap(dev, par->mmio_base); 8128c2ecf20Sopenharmony_ci pci_release_regions(dev); 8138c2ecf20Sopenharmony_ci/* pci_disable_device(dev); */ 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci framebuffer_release(info); 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci/* PCI suspend */ 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic int __maybe_unused vt8623_pci_suspend(struct device *dev) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci struct fb_info *info = dev_get_drvdata(dev); 8258c2ecf20Sopenharmony_ci struct vt8623fb_info *par = info->par; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci dev_info(info->device, "suspend\n"); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci console_lock(); 8308c2ecf20Sopenharmony_ci mutex_lock(&(par->open_lock)); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (par->ref_count == 0) { 8338c2ecf20Sopenharmony_ci mutex_unlock(&(par->open_lock)); 8348c2ecf20Sopenharmony_ci console_unlock(); 8358c2ecf20Sopenharmony_ci return 0; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci fb_set_suspend(info, 1); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci mutex_unlock(&(par->open_lock)); 8418c2ecf20Sopenharmony_ci console_unlock(); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci return 0; 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci/* PCI resume */ 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic int __maybe_unused vt8623_pci_resume(struct device *dev) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci struct fb_info *info = dev_get_drvdata(dev); 8528c2ecf20Sopenharmony_ci struct vt8623fb_info *par = info->par; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci dev_info(info->device, "resume\n"); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci console_lock(); 8578c2ecf20Sopenharmony_ci mutex_lock(&(par->open_lock)); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (par->ref_count == 0) 8608c2ecf20Sopenharmony_ci goto fail; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci vt8623fb_set_par(info); 8638c2ecf20Sopenharmony_ci fb_set_suspend(info, 0); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cifail: 8668c2ecf20Sopenharmony_ci mutex_unlock(&(par->open_lock)); 8678c2ecf20Sopenharmony_ci console_unlock(); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci return 0; 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic const struct dev_pm_ops vt8623_pci_pm_ops = { 8738c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 8748c2ecf20Sopenharmony_ci .suspend = vt8623_pci_suspend, 8758c2ecf20Sopenharmony_ci .resume = vt8623_pci_resume, 8768c2ecf20Sopenharmony_ci .freeze = NULL, 8778c2ecf20Sopenharmony_ci .thaw = vt8623_pci_resume, 8788c2ecf20Sopenharmony_ci .poweroff = vt8623_pci_suspend, 8798c2ecf20Sopenharmony_ci .restore = vt8623_pci_resume, 8808c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 8818c2ecf20Sopenharmony_ci}; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci/* List of boards that we are trying to support */ 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_cistatic const struct pci_device_id vt8623_devices[] = { 8868c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122)}, 8878c2ecf20Sopenharmony_ci {0, 0, 0, 0, 0, 0, 0} 8888c2ecf20Sopenharmony_ci}; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, vt8623_devices); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic struct pci_driver vt8623fb_pci_driver = { 8938c2ecf20Sopenharmony_ci .name = "vt8623fb", 8948c2ecf20Sopenharmony_ci .id_table = vt8623_devices, 8958c2ecf20Sopenharmony_ci .probe = vt8623_pci_probe, 8968c2ecf20Sopenharmony_ci .remove = vt8623_pci_remove, 8978c2ecf20Sopenharmony_ci .driver.pm = &vt8623_pci_pm_ops, 8988c2ecf20Sopenharmony_ci}; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci/* Cleanup */ 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cistatic void __exit vt8623fb_cleanup(void) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci pr_debug("vt8623fb: cleaning up\n"); 9058c2ecf20Sopenharmony_ci pci_unregister_driver(&vt8623fb_pci_driver); 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci/* Driver Initialisation */ 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cistatic int __init vt8623fb_init(void) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci#ifndef MODULE 9148c2ecf20Sopenharmony_ci char *option = NULL; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (fb_get_options("vt8623fb", &option)) 9178c2ecf20Sopenharmony_ci return -ENODEV; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci if (option && *option) 9208c2ecf20Sopenharmony_ci mode_option = option; 9218c2ecf20Sopenharmony_ci#endif 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci pr_debug("vt8623fb: initializing\n"); 9248c2ecf20Sopenharmony_ci return pci_register_driver(&vt8623fb_pci_driver); 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------- */ 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci/* Modularization */ 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cimodule_init(vt8623fb_init); 9328c2ecf20Sopenharmony_cimodule_exit(vt8623fb_cleanup); 933