18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Permedia2 framebuffer driver. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * 2.5/2.6 driver: 58c2ecf20Sopenharmony_ci * Copyright (c) 2003 Jim Hague (jim.hague@acm.org) 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * based on 2.4 driver: 88c2ecf20Sopenharmony_ci * Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) 98c2ecf20Sopenharmony_ci * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com) 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * and additional input from James Simmon's port of Hannu Mallat's tdfx 128c2ecf20Sopenharmony_ci * driver. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I 158c2ecf20Sopenharmony_ci * have no access to other pm2fb implementations. Sparc (and thus 168c2ecf20Sopenharmony_ci * hopefully other big-endian) devices now work, thanks to a lot of 178c2ecf20Sopenharmony_ci * testing work by Ron Murray. I have no access to CVision hardware, 188c2ecf20Sopenharmony_ci * and therefore for now I am omitting the CVision code. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Multiple boards support has been on the TODO list for ages. 218c2ecf20Sopenharmony_ci * Don't expect this to change. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 248c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 258c2ecf20Sopenharmony_ci * more details. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/module.h> 318c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 328c2ecf20Sopenharmony_ci#include <linux/kernel.h> 338c2ecf20Sopenharmony_ci#include <linux/errno.h> 348c2ecf20Sopenharmony_ci#include <linux/string.h> 358c2ecf20Sopenharmony_ci#include <linux/mm.h> 368c2ecf20Sopenharmony_ci#include <linux/slab.h> 378c2ecf20Sopenharmony_ci#include <linux/delay.h> 388c2ecf20Sopenharmony_ci#include <linux/fb.h> 398c2ecf20Sopenharmony_ci#include <linux/init.h> 408c2ecf20Sopenharmony_ci#include <linux/pci.h> 418c2ecf20Sopenharmony_ci#include <video/permedia2.h> 428c2ecf20Sopenharmony_ci#include <video/cvisionppc.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN) 458c2ecf20Sopenharmony_ci#error "The endianness of the target host has not been defined." 468c2ecf20Sopenharmony_ci#endif 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#if !defined(CONFIG_PCI) 498c2ecf20Sopenharmony_ci#error "Only generic PCI cards supported." 508c2ecf20Sopenharmony_ci#endif 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#undef PM2FB_MASTER_DEBUG 538c2ecf20Sopenharmony_ci#ifdef PM2FB_MASTER_DEBUG 548c2ecf20Sopenharmony_ci#define DPRINTK(a, b...) \ 558c2ecf20Sopenharmony_ci printk(KERN_DEBUG "pm2fb: %s: " a, __func__ , ## b) 568c2ecf20Sopenharmony_ci#else 578c2ecf20Sopenharmony_ci#define DPRINTK(a, b...) no_printk(a, ##b) 588c2ecf20Sopenharmony_ci#endif 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define PM2_PIXMAP_SIZE (1600 * 4) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* 638c2ecf20Sopenharmony_ci * Driver data 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_cistatic int hwcursor = 1; 668c2ecf20Sopenharmony_cistatic char *mode_option; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* 698c2ecf20Sopenharmony_ci * The XFree GLINT driver will (I think to implement hardware cursor 708c2ecf20Sopenharmony_ci * support on TVP4010 and similar where there is no RAMDAC - see 718c2ecf20Sopenharmony_ci * comment in set_video) always request +ve sync regardless of what 728c2ecf20Sopenharmony_ci * the mode requires. This screws me because I have a Sun 738c2ecf20Sopenharmony_ci * fixed-frequency monitor which absolutely has to have -ve sync. So 748c2ecf20Sopenharmony_ci * these flags allow the user to specify that requests for +ve sync 758c2ecf20Sopenharmony_ci * should be silently turned in -ve sync. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_cistatic bool lowhsync; 788c2ecf20Sopenharmony_cistatic bool lowvsync; 798c2ecf20Sopenharmony_cistatic bool noaccel; 808c2ecf20Sopenharmony_cistatic bool nomtrr; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* 838c2ecf20Sopenharmony_ci * The hardware state of the graphics card that isn't part of the 848c2ecf20Sopenharmony_ci * screeninfo. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_cistruct pm2fb_par 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci pm2type_t type; /* Board type */ 898c2ecf20Sopenharmony_ci unsigned char __iomem *v_regs;/* virtual address of p_regs */ 908c2ecf20Sopenharmony_ci u32 memclock; /* memclock */ 918c2ecf20Sopenharmony_ci u32 video; /* video flags before blanking */ 928c2ecf20Sopenharmony_ci u32 mem_config; /* MemConfig reg at probe */ 938c2ecf20Sopenharmony_ci u32 mem_control; /* MemControl reg at probe */ 948c2ecf20Sopenharmony_ci u32 boot_address; /* BootAddress reg at probe */ 958c2ecf20Sopenharmony_ci u32 palette[16]; 968c2ecf20Sopenharmony_ci int wc_cookie; 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* 1008c2ecf20Sopenharmony_ci * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo 1018c2ecf20Sopenharmony_ci * if we don't use modedb. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_cistatic struct fb_fix_screeninfo pm2fb_fix = { 1048c2ecf20Sopenharmony_ci .id = "", 1058c2ecf20Sopenharmony_ci .type = FB_TYPE_PACKED_PIXELS, 1068c2ecf20Sopenharmony_ci .visual = FB_VISUAL_PSEUDOCOLOR, 1078c2ecf20Sopenharmony_ci .xpanstep = 1, 1088c2ecf20Sopenharmony_ci .ypanstep = 1, 1098c2ecf20Sopenharmony_ci .ywrapstep = 0, 1108c2ecf20Sopenharmony_ci .accel = FB_ACCEL_3DLABS_PERMEDIA2, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* 1148c2ecf20Sopenharmony_ci * Default video mode. In case the modedb doesn't work. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_cistatic const struct fb_var_screeninfo pm2fb_var = { 1178c2ecf20Sopenharmony_ci /* "640x480, 8 bpp @ 60 Hz */ 1188c2ecf20Sopenharmony_ci .xres = 640, 1198c2ecf20Sopenharmony_ci .yres = 480, 1208c2ecf20Sopenharmony_ci .xres_virtual = 640, 1218c2ecf20Sopenharmony_ci .yres_virtual = 480, 1228c2ecf20Sopenharmony_ci .bits_per_pixel = 8, 1238c2ecf20Sopenharmony_ci .red = {0, 8, 0}, 1248c2ecf20Sopenharmony_ci .blue = {0, 8, 0}, 1258c2ecf20Sopenharmony_ci .green = {0, 8, 0}, 1268c2ecf20Sopenharmony_ci .activate = FB_ACTIVATE_NOW, 1278c2ecf20Sopenharmony_ci .height = -1, 1288c2ecf20Sopenharmony_ci .width = -1, 1298c2ecf20Sopenharmony_ci .accel_flags = 0, 1308c2ecf20Sopenharmony_ci .pixclock = 39721, 1318c2ecf20Sopenharmony_ci .left_margin = 40, 1328c2ecf20Sopenharmony_ci .right_margin = 24, 1338c2ecf20Sopenharmony_ci .upper_margin = 32, 1348c2ecf20Sopenharmony_ci .lower_margin = 11, 1358c2ecf20Sopenharmony_ci .hsync_len = 96, 1368c2ecf20Sopenharmony_ci .vsync_len = 2, 1378c2ecf20Sopenharmony_ci .vmode = FB_VMODE_NONINTERLACED 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* 1418c2ecf20Sopenharmony_ci * Utility functions 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic inline u32 pm2_RD(struct pm2fb_par *p, s32 off) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci return fb_readl(p->v_regs + off); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic inline void pm2_WR(struct pm2fb_par *p, s32 off, u32 v) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci fb_writel(v, p->v_regs + off); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic inline u32 pm2_RDAC_RD(struct pm2fb_par *p, s32 idx) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); 1578c2ecf20Sopenharmony_ci mb(); 1588c2ecf20Sopenharmony_ci return pm2_RD(p, PM2R_RD_INDEXED_DATA); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic inline u32 pm2v_RDAC_RD(struct pm2fb_par *p, s32 idx) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); 1648c2ecf20Sopenharmony_ci mb(); 1658c2ecf20Sopenharmony_ci return pm2_RD(p, PM2VR_RD_INDEXED_DATA); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic inline void pm2_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); 1718c2ecf20Sopenharmony_ci wmb(); 1728c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RD_INDEXED_DATA, v); 1738c2ecf20Sopenharmony_ci wmb(); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic inline void pm2v_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); 1798c2ecf20Sopenharmony_ci wmb(); 1808c2ecf20Sopenharmony_ci pm2_WR(p, PM2VR_RD_INDEXED_DATA, v); 1818c2ecf20Sopenharmony_ci wmb(); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT 1858c2ecf20Sopenharmony_ci#define WAIT_FIFO(p, a) 1868c2ecf20Sopenharmony_ci#else 1878c2ecf20Sopenharmony_cistatic inline void WAIT_FIFO(struct pm2fb_par *p, u32 a) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci while (pm2_RD(p, PM2R_IN_FIFO_SPACE) < a) 1908c2ecf20Sopenharmony_ci cpu_relax(); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci#endif 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/* 1958c2ecf20Sopenharmony_ci * partial products for the supported horizontal resolutions. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci#define PACKPP(p0, p1, p2) (((p2) << 6) | ((p1) << 3) | (p0)) 1988c2ecf20Sopenharmony_cistatic const struct { 1998c2ecf20Sopenharmony_ci u16 width; 2008c2ecf20Sopenharmony_ci u16 pp; 2018c2ecf20Sopenharmony_ci} pp_table[] = { 2028c2ecf20Sopenharmony_ci { 32, PACKPP(1, 0, 0) }, { 64, PACKPP(1, 1, 0) }, 2038c2ecf20Sopenharmony_ci { 96, PACKPP(1, 1, 1) }, { 128, PACKPP(2, 1, 1) }, 2048c2ecf20Sopenharmony_ci { 160, PACKPP(2, 2, 1) }, { 192, PACKPP(2, 2, 2) }, 2058c2ecf20Sopenharmony_ci { 224, PACKPP(3, 2, 1) }, { 256, PACKPP(3, 2, 2) }, 2068c2ecf20Sopenharmony_ci { 288, PACKPP(3, 3, 1) }, { 320, PACKPP(3, 3, 2) }, 2078c2ecf20Sopenharmony_ci { 384, PACKPP(3, 3, 3) }, { 416, PACKPP(4, 3, 1) }, 2088c2ecf20Sopenharmony_ci { 448, PACKPP(4, 3, 2) }, { 512, PACKPP(4, 3, 3) }, 2098c2ecf20Sopenharmony_ci { 544, PACKPP(4, 4, 1) }, { 576, PACKPP(4, 4, 2) }, 2108c2ecf20Sopenharmony_ci { 640, PACKPP(4, 4, 3) }, { 768, PACKPP(4, 4, 4) }, 2118c2ecf20Sopenharmony_ci { 800, PACKPP(5, 4, 1) }, { 832, PACKPP(5, 4, 2) }, 2128c2ecf20Sopenharmony_ci { 896, PACKPP(5, 4, 3) }, { 1024, PACKPP(5, 4, 4) }, 2138c2ecf20Sopenharmony_ci { 1056, PACKPP(5, 5, 1) }, { 1088, PACKPP(5, 5, 2) }, 2148c2ecf20Sopenharmony_ci { 1152, PACKPP(5, 5, 3) }, { 1280, PACKPP(5, 5, 4) }, 2158c2ecf20Sopenharmony_ci { 1536, PACKPP(5, 5, 5) }, { 1568, PACKPP(6, 5, 1) }, 2168c2ecf20Sopenharmony_ci { 1600, PACKPP(6, 5, 2) }, { 1664, PACKPP(6, 5, 3) }, 2178c2ecf20Sopenharmony_ci { 1792, PACKPP(6, 5, 4) }, { 2048, PACKPP(6, 5, 5) }, 2188c2ecf20Sopenharmony_ci { 0, 0 } }; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic u32 partprod(u32 xres) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci int i; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++) 2258c2ecf20Sopenharmony_ci ; 2268c2ecf20Sopenharmony_ci if (pp_table[i].width == 0) 2278c2ecf20Sopenharmony_ci DPRINTK("invalid width %u\n", xres); 2288c2ecf20Sopenharmony_ci return pp_table[i].pp; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic u32 to3264(u32 timing, int bpp, int is64) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci switch (bpp) { 2348c2ecf20Sopenharmony_ci case 24: 2358c2ecf20Sopenharmony_ci timing *= 3; 2368c2ecf20Sopenharmony_ci fallthrough; 2378c2ecf20Sopenharmony_ci case 8: 2388c2ecf20Sopenharmony_ci timing >>= 1; 2398c2ecf20Sopenharmony_ci fallthrough; 2408c2ecf20Sopenharmony_ci case 16: 2418c2ecf20Sopenharmony_ci timing >>= 1; 2428c2ecf20Sopenharmony_ci case 32: 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci if (is64) 2468c2ecf20Sopenharmony_ci timing >>= 1; 2478c2ecf20Sopenharmony_ci return timing; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void pm2_mnp(u32 clk, unsigned char *mm, unsigned char *nn, 2518c2ecf20Sopenharmony_ci unsigned char *pp) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci unsigned char m; 2548c2ecf20Sopenharmony_ci unsigned char n; 2558c2ecf20Sopenharmony_ci unsigned char p; 2568c2ecf20Sopenharmony_ci u32 f; 2578c2ecf20Sopenharmony_ci s32 curr; 2588c2ecf20Sopenharmony_ci s32 delta = 100000; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci *mm = *nn = *pp = 0; 2618c2ecf20Sopenharmony_ci for (n = 2; n < 15; n++) { 2628c2ecf20Sopenharmony_ci for (m = 2; m; m++) { 2638c2ecf20Sopenharmony_ci f = PM2_REFERENCE_CLOCK * m / n; 2648c2ecf20Sopenharmony_ci if (f >= 150000 && f <= 300000) { 2658c2ecf20Sopenharmony_ci for (p = 0; p < 5; p++, f >>= 1) { 2668c2ecf20Sopenharmony_ci curr = (clk > f) ? clk - f : f - clk; 2678c2ecf20Sopenharmony_ci if (curr < delta) { 2688c2ecf20Sopenharmony_ci delta = curr; 2698c2ecf20Sopenharmony_ci *mm = m; 2708c2ecf20Sopenharmony_ci *nn = n; 2718c2ecf20Sopenharmony_ci *pp = p; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic void pm2v_mnp(u32 clk, unsigned char *mm, unsigned char *nn, 2808c2ecf20Sopenharmony_ci unsigned char *pp) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci unsigned char m; 2838c2ecf20Sopenharmony_ci unsigned char n; 2848c2ecf20Sopenharmony_ci unsigned char p; 2858c2ecf20Sopenharmony_ci u32 f; 2868c2ecf20Sopenharmony_ci s32 delta = 1000; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci *mm = *nn = *pp = 0; 2898c2ecf20Sopenharmony_ci for (m = 1; m < 128; m++) { 2908c2ecf20Sopenharmony_ci for (n = 2 * m + 1; n; n++) { 2918c2ecf20Sopenharmony_ci for (p = 0; p < 2; p++) { 2928c2ecf20Sopenharmony_ci f = (PM2_REFERENCE_CLOCK >> (p + 1)) * n / m; 2938c2ecf20Sopenharmony_ci if (clk > f - delta && clk < f + delta) { 2948c2ecf20Sopenharmony_ci delta = (clk > f) ? clk - f : f - clk; 2958c2ecf20Sopenharmony_ci *mm = m; 2968c2ecf20Sopenharmony_ci *nn = n; 2978c2ecf20Sopenharmony_ci *pp = p; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic void clear_palette(struct pm2fb_par *p) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci int i = 256; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci WAIT_FIFO(p, 1); 3098c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0); 3108c2ecf20Sopenharmony_ci wmb(); 3118c2ecf20Sopenharmony_ci while (i--) { 3128c2ecf20Sopenharmony_ci WAIT_FIFO(p, 3); 3138c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RD_PALETTE_DATA, 0); 3148c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RD_PALETTE_DATA, 0); 3158c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RD_PALETTE_DATA, 0); 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic void reset_card(struct pm2fb_par *p) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci if (p->type == PM2_TYPE_PERMEDIA2V) 3228c2ecf20Sopenharmony_ci pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0); 3238c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RESET_STATUS, 0); 3248c2ecf20Sopenharmony_ci mb(); 3258c2ecf20Sopenharmony_ci while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET) 3268c2ecf20Sopenharmony_ci cpu_relax(); 3278c2ecf20Sopenharmony_ci mb(); 3288c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT 3298c2ecf20Sopenharmony_ci DPRINTK("FIFO disconnect enabled\n"); 3308c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_FIFO_DISCON, 1); 3318c2ecf20Sopenharmony_ci mb(); 3328c2ecf20Sopenharmony_ci#endif 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* Restore stashed memory config information from probe */ 3358c2ecf20Sopenharmony_ci WAIT_FIFO(p, 3); 3368c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_MEM_CONTROL, p->mem_control); 3378c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_BOOT_ADDRESS, p->boot_address); 3388c2ecf20Sopenharmony_ci wmb(); 3398c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_MEM_CONFIG, p->mem_config); 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic void reset_config(struct pm2fb_par *p) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci WAIT_FIFO(p, 53); 3458c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG) & 3468c2ecf20Sopenharmony_ci ~(PM2F_VGA_ENABLE | PM2F_VGA_FIXED)); 3478c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L)); 3488c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L)); 3498c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_FIFO_CONTROL, 0); 3508c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_APERTURE_ONE, 0); 3518c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_APERTURE_TWO, 0); 3528c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RASTERIZER_MODE, 0); 3538c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB); 3548c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_LB_READ_FORMAT, 0); 3558c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0); 3568c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_LB_READ_MODE, 0); 3578c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0); 3588c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0); 3598c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0); 3608c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_FB_WINDOW_BASE, 0); 3618c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_LB_WINDOW_BASE, 0); 3628c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L)); 3638c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L)); 3648c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_FB_READ_PIXEL, 0); 3658c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_DITHER_MODE, 0); 3668c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0); 3678c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_DEPTH_MODE, 0); 3688c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_STENCIL_MODE, 0); 3698c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0); 3708c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0); 3718c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0); 3728c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_YUV_MODE, 0); 3738c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_COLOR_DDA_MODE, 0); 3748c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0); 3758c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_FOG_MODE, 0); 3768c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0); 3778c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0); 3788c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_STATISTICS_MODE, 0); 3798c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_SCISSOR_MODE, 0); 3808c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION); 3818c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RD_PIXEL_MASK, 0xff); 3828c2ecf20Sopenharmony_ci switch (p->type) { 3838c2ecf20Sopenharmony_ci case PM2_TYPE_PERMEDIA2: 3848c2ecf20Sopenharmony_ci pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */ 3858c2ecf20Sopenharmony_ci pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0); 3868c2ecf20Sopenharmony_ci pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8); 3878c2ecf20Sopenharmony_ci pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0); 3888c2ecf20Sopenharmony_ci pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0); 3898c2ecf20Sopenharmony_ci pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0); 3908c2ecf20Sopenharmony_ci pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0); 3918c2ecf20Sopenharmony_ci pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0); 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci case PM2_TYPE_PERMEDIA2V: 3948c2ecf20Sopenharmony_ci pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */ 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic void set_aperture(struct pm2fb_par *p, u32 depth) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci /* 4028c2ecf20Sopenharmony_ci * The hardware is little-endian. When used in big-endian 4038c2ecf20Sopenharmony_ci * hosts, the on-chip aperture settings are used where 4048c2ecf20Sopenharmony_ci * possible to translate from host to card byte order. 4058c2ecf20Sopenharmony_ci */ 4068c2ecf20Sopenharmony_ci WAIT_FIFO(p, 2); 4078c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN 4088c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD); 4098c2ecf20Sopenharmony_ci#else 4108c2ecf20Sopenharmony_ci switch (depth) { 4118c2ecf20Sopenharmony_ci case 24: /* RGB->BGR */ 4128c2ecf20Sopenharmony_ci /* 4138c2ecf20Sopenharmony_ci * We can't use the aperture to translate host to 4148c2ecf20Sopenharmony_ci * card byte order here, so we switch to BGR mode 4158c2ecf20Sopenharmony_ci * in pm2fb_set_par(). 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_ci case 8: /* B->B */ 4188c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD); 4198c2ecf20Sopenharmony_ci break; 4208c2ecf20Sopenharmony_ci case 16: /* HL->LH */ 4218c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_HALFWORDSWAP); 4228c2ecf20Sopenharmony_ci break; 4238c2ecf20Sopenharmony_ci case 32: /* RGBA->ABGR */ 4248c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_BYTESWAP); 4258c2ecf20Sopenharmony_ci break; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci#endif 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* We don't use aperture two, so this may be superflous */ 4308c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_APERTURE_TWO, PM2F_APERTURE_STANDARD); 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic void set_color(struct pm2fb_par *p, unsigned char regno, 4348c2ecf20Sopenharmony_ci unsigned char r, unsigned char g, unsigned char b) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci WAIT_FIFO(p, 4); 4378c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, regno); 4388c2ecf20Sopenharmony_ci wmb(); 4398c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RD_PALETTE_DATA, r); 4408c2ecf20Sopenharmony_ci wmb(); 4418c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RD_PALETTE_DATA, g); 4428c2ecf20Sopenharmony_ci wmb(); 4438c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_RD_PALETTE_DATA, b); 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic void set_memclock(struct pm2fb_par *par, u32 clk) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci int i; 4498c2ecf20Sopenharmony_ci unsigned char m, n, p; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci switch (par->type) { 4528c2ecf20Sopenharmony_ci case PM2_TYPE_PERMEDIA2V: 4538c2ecf20Sopenharmony_ci pm2v_mnp(clk/2, &m, &n, &p); 4548c2ecf20Sopenharmony_ci WAIT_FIFO(par, 12); 4558c2ecf20Sopenharmony_ci pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8); 4568c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0); 4578c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m); 4588c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_MCLK_FEEDBACK, n); 4598c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p); 4608c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1); 4618c2ecf20Sopenharmony_ci rmb(); 4628c2ecf20Sopenharmony_ci for (i = 256; i; i--) 4638c2ecf20Sopenharmony_ci if (pm2v_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2) 4648c2ecf20Sopenharmony_ci break; 4658c2ecf20Sopenharmony_ci pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci case PM2_TYPE_PERMEDIA2: 4688c2ecf20Sopenharmony_ci pm2_mnp(clk, &m, &n, &p); 4698c2ecf20Sopenharmony_ci WAIT_FIFO(par, 10); 4708c2ecf20Sopenharmony_ci pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 6); 4718c2ecf20Sopenharmony_ci pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_1, m); 4728c2ecf20Sopenharmony_ci pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_2, n); 4738c2ecf20Sopenharmony_ci pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p); 4748c2ecf20Sopenharmony_ci pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS); 4758c2ecf20Sopenharmony_ci rmb(); 4768c2ecf20Sopenharmony_ci for (i = 256; i; i--) 4778c2ecf20Sopenharmony_ci if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED) 4788c2ecf20Sopenharmony_ci break; 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic void set_pixclock(struct pm2fb_par *par, u32 clk) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci int i; 4868c2ecf20Sopenharmony_ci unsigned char m, n, p; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci switch (par->type) { 4898c2ecf20Sopenharmony_ci case PM2_TYPE_PERMEDIA2: 4908c2ecf20Sopenharmony_ci pm2_mnp(clk, &m, &n, &p); 4918c2ecf20Sopenharmony_ci WAIT_FIFO(par, 10); 4928c2ecf20Sopenharmony_ci pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0); 4938c2ecf20Sopenharmony_ci pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m); 4948c2ecf20Sopenharmony_ci pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n); 4958c2ecf20Sopenharmony_ci pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p); 4968c2ecf20Sopenharmony_ci pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS); 4978c2ecf20Sopenharmony_ci rmb(); 4988c2ecf20Sopenharmony_ci for (i = 256; i; i--) 4998c2ecf20Sopenharmony_ci if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED) 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci case PM2_TYPE_PERMEDIA2V: 5038c2ecf20Sopenharmony_ci pm2v_mnp(clk/2, &m, &n, &p); 5048c2ecf20Sopenharmony_ci WAIT_FIFO(par, 8); 5058c2ecf20Sopenharmony_ci pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8); 5068c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CLK0_PRESCALE, m); 5078c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CLK0_FEEDBACK, n); 5088c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CLK0_POSTSCALE, p); 5098c2ecf20Sopenharmony_ci pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); 5108c2ecf20Sopenharmony_ci break; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic void set_video(struct pm2fb_par *p, u32 video) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci u32 tmp; 5178c2ecf20Sopenharmony_ci u32 vsync = video; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci DPRINTK("video = 0x%x\n", video); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* 5228c2ecf20Sopenharmony_ci * The hardware cursor needs +vsync to recognise vert retrace. 5238c2ecf20Sopenharmony_ci * We may not be using the hardware cursor, but the X Glint 5248c2ecf20Sopenharmony_ci * driver may well. So always set +hsync/+vsync and then set 5258c2ecf20Sopenharmony_ci * the RAMDAC to invert the sync if necessary. 5268c2ecf20Sopenharmony_ci */ 5278c2ecf20Sopenharmony_ci vsync &= ~(PM2F_HSYNC_MASK | PM2F_VSYNC_MASK); 5288c2ecf20Sopenharmony_ci vsync |= PM2F_HSYNC_ACT_HIGH | PM2F_VSYNC_ACT_HIGH; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci WAIT_FIFO(p, 3); 5318c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_VIDEO_CONTROL, vsync); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci switch (p->type) { 5348c2ecf20Sopenharmony_ci case PM2_TYPE_PERMEDIA2: 5358c2ecf20Sopenharmony_ci tmp = PM2F_RD_PALETTE_WIDTH_8; 5368c2ecf20Sopenharmony_ci if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW) 5378c2ecf20Sopenharmony_ci tmp |= 4; /* invert hsync */ 5388c2ecf20Sopenharmony_ci if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW) 5398c2ecf20Sopenharmony_ci tmp |= 8; /* invert vsync */ 5408c2ecf20Sopenharmony_ci pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, tmp); 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci case PM2_TYPE_PERMEDIA2V: 5438c2ecf20Sopenharmony_ci tmp = 0; 5448c2ecf20Sopenharmony_ci if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW) 5458c2ecf20Sopenharmony_ci tmp |= 1; /* invert hsync */ 5468c2ecf20Sopenharmony_ci if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW) 5478c2ecf20Sopenharmony_ci tmp |= 4; /* invert vsync */ 5488c2ecf20Sopenharmony_ci pm2v_RDAC_WR(p, PM2VI_RD_SYNC_CONTROL, tmp); 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci/* 5548c2ecf20Sopenharmony_ci * pm2fb_check_var - Optional function. Validates a var passed in. 5558c2ecf20Sopenharmony_ci * @var: frame buffer variable screen structure 5568c2ecf20Sopenharmony_ci * @info: frame buffer structure that represents a single frame buffer 5578c2ecf20Sopenharmony_ci * 5588c2ecf20Sopenharmony_ci * Checks to see if the hardware supports the state requested by 5598c2ecf20Sopenharmony_ci * var passed in. 5608c2ecf20Sopenharmony_ci * 5618c2ecf20Sopenharmony_ci * Returns negative errno on error, or zero on success. 5628c2ecf20Sopenharmony_ci */ 5638c2ecf20Sopenharmony_cistatic int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci u32 lpitch; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (var->bits_per_pixel != 8 && var->bits_per_pixel != 16 && 5688c2ecf20Sopenharmony_ci var->bits_per_pixel != 24 && var->bits_per_pixel != 32) { 5698c2ecf20Sopenharmony_ci DPRINTK("depth not supported: %u\n", var->bits_per_pixel); 5708c2ecf20Sopenharmony_ci return -EINVAL; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (var->xres != var->xres_virtual) { 5748c2ecf20Sopenharmony_ci DPRINTK("virtual x resolution != " 5758c2ecf20Sopenharmony_ci "physical x resolution not supported\n"); 5768c2ecf20Sopenharmony_ci return -EINVAL; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (var->yres > var->yres_virtual) { 5808c2ecf20Sopenharmony_ci DPRINTK("virtual y resolution < " 5818c2ecf20Sopenharmony_ci "physical y resolution not possible\n"); 5828c2ecf20Sopenharmony_ci return -EINVAL; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* permedia cannot blit over 2048 */ 5868c2ecf20Sopenharmony_ci if (var->yres_virtual > 2047) { 5878c2ecf20Sopenharmony_ci var->yres_virtual = 2047; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (var->xoffset) { 5918c2ecf20Sopenharmony_ci DPRINTK("xoffset not supported\n"); 5928c2ecf20Sopenharmony_ci return -EINVAL; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { 5968c2ecf20Sopenharmony_ci DPRINTK("interlace not supported\n"); 5978c2ecf20Sopenharmony_ci return -EINVAL; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ 6018c2ecf20Sopenharmony_ci lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (var->xres < 320 || var->xres > 1600) { 6048c2ecf20Sopenharmony_ci DPRINTK("width not supported: %u\n", var->xres); 6058c2ecf20Sopenharmony_ci return -EINVAL; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (var->yres < 200 || var->yres > 1200) { 6098c2ecf20Sopenharmony_ci DPRINTK("height not supported: %u\n", var->yres); 6108c2ecf20Sopenharmony_ci return -EINVAL; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (lpitch * var->yres_virtual > info->fix.smem_len) { 6148c2ecf20Sopenharmony_ci DPRINTK("no memory for screen (%ux%ux%u)\n", 6158c2ecf20Sopenharmony_ci var->xres, var->yres_virtual, var->bits_per_pixel); 6168c2ecf20Sopenharmony_ci return -EINVAL; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (!var->pixclock) { 6208c2ecf20Sopenharmony_ci DPRINTK("pixclock is zero\n"); 6218c2ecf20Sopenharmony_ci return -EINVAL; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) { 6258c2ecf20Sopenharmony_ci DPRINTK("pixclock too high (%ldKHz)\n", 6268c2ecf20Sopenharmony_ci PICOS2KHZ(var->pixclock)); 6278c2ecf20Sopenharmony_ci return -EINVAL; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci var->transp.offset = 0; 6318c2ecf20Sopenharmony_ci var->transp.length = 0; 6328c2ecf20Sopenharmony_ci switch (var->bits_per_pixel) { 6338c2ecf20Sopenharmony_ci case 8: 6348c2ecf20Sopenharmony_ci var->red.length = 8; 6358c2ecf20Sopenharmony_ci var->green.length = 8; 6368c2ecf20Sopenharmony_ci var->blue.length = 8; 6378c2ecf20Sopenharmony_ci break; 6388c2ecf20Sopenharmony_ci case 16: 6398c2ecf20Sopenharmony_ci var->red.offset = 11; 6408c2ecf20Sopenharmony_ci var->red.length = 5; 6418c2ecf20Sopenharmony_ci var->green.offset = 5; 6428c2ecf20Sopenharmony_ci var->green.length = 6; 6438c2ecf20Sopenharmony_ci var->blue.offset = 0; 6448c2ecf20Sopenharmony_ci var->blue.length = 5; 6458c2ecf20Sopenharmony_ci break; 6468c2ecf20Sopenharmony_ci case 32: 6478c2ecf20Sopenharmony_ci var->transp.offset = 24; 6488c2ecf20Sopenharmony_ci var->transp.length = 8; 6498c2ecf20Sopenharmony_ci var->red.offset = 16; 6508c2ecf20Sopenharmony_ci var->green.offset = 8; 6518c2ecf20Sopenharmony_ci var->blue.offset = 0; 6528c2ecf20Sopenharmony_ci var->red.length = 8; 6538c2ecf20Sopenharmony_ci var->green.length = 8; 6548c2ecf20Sopenharmony_ci var->blue.length = 8; 6558c2ecf20Sopenharmony_ci break; 6568c2ecf20Sopenharmony_ci case 24: 6578c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 6588c2ecf20Sopenharmony_ci var->red.offset = 0; 6598c2ecf20Sopenharmony_ci var->blue.offset = 16; 6608c2ecf20Sopenharmony_ci#else 6618c2ecf20Sopenharmony_ci var->red.offset = 16; 6628c2ecf20Sopenharmony_ci var->blue.offset = 0; 6638c2ecf20Sopenharmony_ci#endif 6648c2ecf20Sopenharmony_ci var->green.offset = 8; 6658c2ecf20Sopenharmony_ci var->red.length = 8; 6668c2ecf20Sopenharmony_ci var->green.length = 8; 6678c2ecf20Sopenharmony_ci var->blue.length = 8; 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci var->height = -1; 6718c2ecf20Sopenharmony_ci var->width = -1; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci var->accel_flags = 0; /* Can't mmap if this is on */ 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci DPRINTK("Checking graphics mode at %dx%d depth %d\n", 6768c2ecf20Sopenharmony_ci var->xres, var->yres, var->bits_per_pixel); 6778c2ecf20Sopenharmony_ci return 0; 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci/** 6818c2ecf20Sopenharmony_ci * pm2fb_set_par - Alters the hardware state. 6828c2ecf20Sopenharmony_ci * @info: frame buffer structure that represents a single frame buffer 6838c2ecf20Sopenharmony_ci * 6848c2ecf20Sopenharmony_ci * Using the fb_var_screeninfo in fb_info we set the resolution of the 6858c2ecf20Sopenharmony_ci * this particular framebuffer. 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_cistatic int pm2fb_set_par(struct fb_info *info) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci struct pm2fb_par *par = info->par; 6908c2ecf20Sopenharmony_ci u32 pixclock; 6918c2ecf20Sopenharmony_ci u32 width = (info->var.xres_virtual + 7) & ~7; 6928c2ecf20Sopenharmony_ci u32 height = info->var.yres_virtual; 6938c2ecf20Sopenharmony_ci u32 depth = (info->var.bits_per_pixel + 7) & ~7; 6948c2ecf20Sopenharmony_ci u32 hsstart, hsend, hbend, htotal; 6958c2ecf20Sopenharmony_ci u32 vsstart, vsend, vbend, vtotal; 6968c2ecf20Sopenharmony_ci u32 stride; 6978c2ecf20Sopenharmony_ci u32 base; 6988c2ecf20Sopenharmony_ci u32 video = 0; 6998c2ecf20Sopenharmony_ci u32 clrmode = PM2F_RD_COLOR_MODE_RGB | PM2F_RD_GUI_ACTIVE; 7008c2ecf20Sopenharmony_ci u32 txtmap = 0; 7018c2ecf20Sopenharmony_ci u32 pixsize = 0; 7028c2ecf20Sopenharmony_ci u32 clrformat = 0; 7038c2ecf20Sopenharmony_ci u32 misc = 1; /* 8-bit DAC */ 7048c2ecf20Sopenharmony_ci u32 xres = (info->var.xres + 31) & ~31; 7058c2ecf20Sopenharmony_ci int data64; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci reset_card(par); 7088c2ecf20Sopenharmony_ci reset_config(par); 7098c2ecf20Sopenharmony_ci clear_palette(par); 7108c2ecf20Sopenharmony_ci if (par->memclock) 7118c2ecf20Sopenharmony_ci set_memclock(par, par->memclock); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci depth = (depth > 32) ? 32 : depth; 7148c2ecf20Sopenharmony_ci data64 = depth > 8 || par->type == PM2_TYPE_PERMEDIA2V; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci pixclock = PICOS2KHZ(info->var.pixclock); 7178c2ecf20Sopenharmony_ci if (pixclock > PM2_MAX_PIXCLOCK) { 7188c2ecf20Sopenharmony_ci DPRINTK("pixclock too high (%uKHz)\n", pixclock); 7198c2ecf20Sopenharmony_ci return -EINVAL; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci hsstart = to3264(info->var.right_margin, depth, data64); 7238c2ecf20Sopenharmony_ci hsend = hsstart + to3264(info->var.hsync_len, depth, data64); 7248c2ecf20Sopenharmony_ci hbend = hsend + to3264(info->var.left_margin, depth, data64); 7258c2ecf20Sopenharmony_ci htotal = to3264(xres, depth, data64) + hbend - 1; 7268c2ecf20Sopenharmony_ci vsstart = (info->var.lower_margin) 7278c2ecf20Sopenharmony_ci ? info->var.lower_margin - 1 7288c2ecf20Sopenharmony_ci : 0; /* FIXME! */ 7298c2ecf20Sopenharmony_ci vsend = info->var.lower_margin + info->var.vsync_len - 1; 7308c2ecf20Sopenharmony_ci vbend = info->var.lower_margin + info->var.vsync_len + 7318c2ecf20Sopenharmony_ci info->var.upper_margin; 7328c2ecf20Sopenharmony_ci vtotal = info->var.yres + vbend - 1; 7338c2ecf20Sopenharmony_ci stride = to3264(width, depth, 1); 7348c2ecf20Sopenharmony_ci base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1); 7358c2ecf20Sopenharmony_ci if (data64) 7368c2ecf20Sopenharmony_ci video |= PM2F_DATA_64_ENABLE; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) { 7398c2ecf20Sopenharmony_ci if (lowhsync) { 7408c2ecf20Sopenharmony_ci DPRINTK("ignoring +hsync, using -hsync.\n"); 7418c2ecf20Sopenharmony_ci video |= PM2F_HSYNC_ACT_LOW; 7428c2ecf20Sopenharmony_ci } else 7438c2ecf20Sopenharmony_ci video |= PM2F_HSYNC_ACT_HIGH; 7448c2ecf20Sopenharmony_ci } else 7458c2ecf20Sopenharmony_ci video |= PM2F_HSYNC_ACT_LOW; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) { 7488c2ecf20Sopenharmony_ci if (lowvsync) { 7498c2ecf20Sopenharmony_ci DPRINTK("ignoring +vsync, using -vsync.\n"); 7508c2ecf20Sopenharmony_ci video |= PM2F_VSYNC_ACT_LOW; 7518c2ecf20Sopenharmony_ci } else 7528c2ecf20Sopenharmony_ci video |= PM2F_VSYNC_ACT_HIGH; 7538c2ecf20Sopenharmony_ci } else 7548c2ecf20Sopenharmony_ci video |= PM2F_VSYNC_ACT_LOW; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { 7578c2ecf20Sopenharmony_ci DPRINTK("interlaced not supported\n"); 7588c2ecf20Sopenharmony_ci return -EINVAL; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) 7618c2ecf20Sopenharmony_ci video |= PM2F_LINE_DOUBLE; 7628c2ecf20Sopenharmony_ci if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) 7638c2ecf20Sopenharmony_ci video |= PM2F_VIDEO_ENABLE; 7648c2ecf20Sopenharmony_ci par->video = video; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci info->fix.visual = 7678c2ecf20Sopenharmony_ci (depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; 7688c2ecf20Sopenharmony_ci info->fix.line_length = info->var.xres * depth / 8; 7698c2ecf20Sopenharmony_ci info->cmap.len = 256; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci /* 7728c2ecf20Sopenharmony_ci * Settings calculated. Now write them out. 7738c2ecf20Sopenharmony_ci */ 7748c2ecf20Sopenharmony_ci if (par->type == PM2_TYPE_PERMEDIA2V) { 7758c2ecf20Sopenharmony_ci WAIT_FIFO(par, 1); 7768c2ecf20Sopenharmony_ci pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci set_aperture(par, depth); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci mb(); 7828c2ecf20Sopenharmony_ci WAIT_FIFO(par, 19); 7838c2ecf20Sopenharmony_ci switch (depth) { 7848c2ecf20Sopenharmony_ci case 8: 7858c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_FB_READ_PIXEL, 0); 7868c2ecf20Sopenharmony_ci clrformat = 0x2e; 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci case 16: 7898c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_FB_READ_PIXEL, 1); 7908c2ecf20Sopenharmony_ci clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB565; 7918c2ecf20Sopenharmony_ci txtmap = PM2F_TEXTEL_SIZE_16; 7928c2ecf20Sopenharmony_ci pixsize = 1; 7938c2ecf20Sopenharmony_ci clrformat = 0x70; 7948c2ecf20Sopenharmony_ci misc |= 8; 7958c2ecf20Sopenharmony_ci break; 7968c2ecf20Sopenharmony_ci case 32: 7978c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_FB_READ_PIXEL, 2); 7988c2ecf20Sopenharmony_ci clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGBA8888; 7998c2ecf20Sopenharmony_ci txtmap = PM2F_TEXTEL_SIZE_32; 8008c2ecf20Sopenharmony_ci pixsize = 2; 8018c2ecf20Sopenharmony_ci clrformat = 0x20; 8028c2ecf20Sopenharmony_ci misc |= 8; 8038c2ecf20Sopenharmony_ci break; 8048c2ecf20Sopenharmony_ci case 24: 8058c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_FB_READ_PIXEL, 4); 8068c2ecf20Sopenharmony_ci clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB888; 8078c2ecf20Sopenharmony_ci txtmap = PM2F_TEXTEL_SIZE_24; 8088c2ecf20Sopenharmony_ci pixsize = 4; 8098c2ecf20Sopenharmony_ci clrformat = 0x20; 8108c2ecf20Sopenharmony_ci misc |= 8; 8118c2ecf20Sopenharmony_ci break; 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE); 8148c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres)); 8158c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_LB_READ_MODE, partprod(xres)); 8168c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_TEXTURE_MAP_FORMAT, txtmap | partprod(xres)); 8178c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_H_TOTAL, htotal); 8188c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_HS_START, hsstart); 8198c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_HS_END, hsend); 8208c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_HG_END, hbend); 8218c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_HB_END, hbend); 8228c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_V_TOTAL, vtotal); 8238c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_VS_START, vsstart); 8248c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_VS_END, vsend); 8258c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_VB_END, vbend); 8268c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_SCREEN_STRIDE, stride); 8278c2ecf20Sopenharmony_ci wmb(); 8288c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_WINDOW_ORIGIN, 0); 8298c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_SCREEN_SIZE, (height << 16) | width); 8308c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE); 8318c2ecf20Sopenharmony_ci wmb(); 8328c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_SCREEN_BASE, base); 8338c2ecf20Sopenharmony_ci wmb(); 8348c2ecf20Sopenharmony_ci set_video(par, video); 8358c2ecf20Sopenharmony_ci WAIT_FIFO(par, 10); 8368c2ecf20Sopenharmony_ci switch (par->type) { 8378c2ecf20Sopenharmony_ci case PM2_TYPE_PERMEDIA2: 8388c2ecf20Sopenharmony_ci pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, clrmode); 8398c2ecf20Sopenharmony_ci pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL, 8408c2ecf20Sopenharmony_ci (depth == 8) ? 0 : PM2F_COLOR_KEY_TEST_OFF); 8418c2ecf20Sopenharmony_ci break; 8428c2ecf20Sopenharmony_ci case PM2_TYPE_PERMEDIA2V: 8438c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_DAC_CONTROL, 0); 8448c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize); 8458c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_COLOR_FORMAT, clrformat); 8468c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_MISC_CONTROL, misc); 8478c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_OVERLAY_KEY, 0); 8488c2ecf20Sopenharmony_ci break; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci set_pixclock(par, pixclock); 8518c2ecf20Sopenharmony_ci DPRINTK("Setting graphics mode at %dx%d depth %d\n", 8528c2ecf20Sopenharmony_ci info->var.xres, info->var.yres, info->var.bits_per_pixel); 8538c2ecf20Sopenharmony_ci return 0; 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci/** 8578c2ecf20Sopenharmony_ci * pm2fb_setcolreg - Sets a color register. 8588c2ecf20Sopenharmony_ci * @regno: boolean, 0 copy local, 1 get_user() function 8598c2ecf20Sopenharmony_ci * @red: frame buffer colormap structure 8608c2ecf20Sopenharmony_ci * @green: The green value which can be up to 16 bits wide 8618c2ecf20Sopenharmony_ci * @blue: The blue value which can be up to 16 bits wide. 8628c2ecf20Sopenharmony_ci * @transp: If supported the alpha value which can be up to 16 bits wide. 8638c2ecf20Sopenharmony_ci * @info: frame buffer info structure 8648c2ecf20Sopenharmony_ci * 8658c2ecf20Sopenharmony_ci * Set a single color register. The values supplied have a 16 bit 8668c2ecf20Sopenharmony_ci * magnitude which needs to be scaled in this function for the hardware. 8678c2ecf20Sopenharmony_ci * Pretty much a direct lift from tdfxfb.c. 8688c2ecf20Sopenharmony_ci * 8698c2ecf20Sopenharmony_ci * Returns negative errno on error, or zero on success. 8708c2ecf20Sopenharmony_ci */ 8718c2ecf20Sopenharmony_cistatic int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, 8728c2ecf20Sopenharmony_ci unsigned blue, unsigned transp, 8738c2ecf20Sopenharmony_ci struct fb_info *info) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci struct pm2fb_par *par = info->par; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (regno >= info->cmap.len) /* no. of hw registers */ 8788c2ecf20Sopenharmony_ci return -EINVAL; 8798c2ecf20Sopenharmony_ci /* 8808c2ecf20Sopenharmony_ci * Program hardware... do anything you want with transp 8818c2ecf20Sopenharmony_ci */ 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* grayscale works only partially under directcolor */ 8848c2ecf20Sopenharmony_ci /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 8858c2ecf20Sopenharmony_ci if (info->var.grayscale) 8868c2ecf20Sopenharmony_ci red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* Directcolor: 8898c2ecf20Sopenharmony_ci * var->{color}.offset contains start of bitfield 8908c2ecf20Sopenharmony_ci * var->{color}.length contains length of bitfield 8918c2ecf20Sopenharmony_ci * {hardwarespecific} contains width of DAC 8928c2ecf20Sopenharmony_ci * cmap[X] is programmed to 8938c2ecf20Sopenharmony_ci * (X << red.offset) | (X << green.offset) | (X << blue.offset) 8948c2ecf20Sopenharmony_ci * RAMDAC[X] is programmed to (red, green, blue) 8958c2ecf20Sopenharmony_ci * 8968c2ecf20Sopenharmony_ci * Pseudocolor: 8978c2ecf20Sopenharmony_ci * uses offset = 0 && length = DAC register width. 8988c2ecf20Sopenharmony_ci * var->{color}.offset is 0 8998c2ecf20Sopenharmony_ci * var->{color}.length contains width of DAC 9008c2ecf20Sopenharmony_ci * cmap is not used 9018c2ecf20Sopenharmony_ci * DAC[X] is programmed to (red, green, blue) 9028c2ecf20Sopenharmony_ci * Truecolor: 9038c2ecf20Sopenharmony_ci * does not use RAMDAC (usually has 3 of them). 9048c2ecf20Sopenharmony_ci * var->{color}.offset contains start of bitfield 9058c2ecf20Sopenharmony_ci * var->{color}.length contains length of bitfield 9068c2ecf20Sopenharmony_ci * cmap is programmed to 9078c2ecf20Sopenharmony_ci * (red << red.offset) | (green << green.offset) | 9088c2ecf20Sopenharmony_ci * (blue << blue.offset) | (transp << transp.offset) 9098c2ecf20Sopenharmony_ci * RAMDAC does not exist 9108c2ecf20Sopenharmony_ci */ 9118c2ecf20Sopenharmony_ci#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF -(val)) >> 16) 9128c2ecf20Sopenharmony_ci switch (info->fix.visual) { 9138c2ecf20Sopenharmony_ci case FB_VISUAL_TRUECOLOR: 9148c2ecf20Sopenharmony_ci case FB_VISUAL_PSEUDOCOLOR: 9158c2ecf20Sopenharmony_ci red = CNVT_TOHW(red, info->var.red.length); 9168c2ecf20Sopenharmony_ci green = CNVT_TOHW(green, info->var.green.length); 9178c2ecf20Sopenharmony_ci blue = CNVT_TOHW(blue, info->var.blue.length); 9188c2ecf20Sopenharmony_ci transp = CNVT_TOHW(transp, info->var.transp.length); 9198c2ecf20Sopenharmony_ci break; 9208c2ecf20Sopenharmony_ci case FB_VISUAL_DIRECTCOLOR: 9218c2ecf20Sopenharmony_ci /* example here assumes 8 bit DAC. Might be different 9228c2ecf20Sopenharmony_ci * for your hardware */ 9238c2ecf20Sopenharmony_ci red = CNVT_TOHW(red, 8); 9248c2ecf20Sopenharmony_ci green = CNVT_TOHW(green, 8); 9258c2ecf20Sopenharmony_ci blue = CNVT_TOHW(blue, 8); 9268c2ecf20Sopenharmony_ci /* hey, there is bug in transp handling... */ 9278c2ecf20Sopenharmony_ci transp = CNVT_TOHW(transp, 8); 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci#undef CNVT_TOHW 9318c2ecf20Sopenharmony_ci /* Truecolor has hardware independent palette */ 9328c2ecf20Sopenharmony_ci if (info->fix.visual == FB_VISUAL_TRUECOLOR) { 9338c2ecf20Sopenharmony_ci u32 v; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (regno >= 16) 9368c2ecf20Sopenharmony_ci return -EINVAL; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci v = (red << info->var.red.offset) | 9398c2ecf20Sopenharmony_ci (green << info->var.green.offset) | 9408c2ecf20Sopenharmony_ci (blue << info->var.blue.offset) | 9418c2ecf20Sopenharmony_ci (transp << info->var.transp.offset); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci switch (info->var.bits_per_pixel) { 9448c2ecf20Sopenharmony_ci case 8: 9458c2ecf20Sopenharmony_ci break; 9468c2ecf20Sopenharmony_ci case 16: 9478c2ecf20Sopenharmony_ci case 24: 9488c2ecf20Sopenharmony_ci case 32: 9498c2ecf20Sopenharmony_ci par->palette[regno] = v; 9508c2ecf20Sopenharmony_ci break; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci return 0; 9538c2ecf20Sopenharmony_ci } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) 9548c2ecf20Sopenharmony_ci set_color(par, regno, red, green, blue); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci return 0; 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci/** 9608c2ecf20Sopenharmony_ci * pm2fb_pan_display - Pans the display. 9618c2ecf20Sopenharmony_ci * @var: frame buffer variable screen structure 9628c2ecf20Sopenharmony_ci * @info: frame buffer structure that represents a single frame buffer 9638c2ecf20Sopenharmony_ci * 9648c2ecf20Sopenharmony_ci * Pan (or wrap, depending on the `vmode' field) the display using the 9658c2ecf20Sopenharmony_ci * `xoffset' and `yoffset' fields of the `var' structure. 9668c2ecf20Sopenharmony_ci * If the values don't fit, return -EINVAL. 9678c2ecf20Sopenharmony_ci * 9688c2ecf20Sopenharmony_ci * Returns negative errno on error, or zero on success. 9698c2ecf20Sopenharmony_ci * 9708c2ecf20Sopenharmony_ci */ 9718c2ecf20Sopenharmony_cistatic int pm2fb_pan_display(struct fb_var_screeninfo *var, 9728c2ecf20Sopenharmony_ci struct fb_info *info) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci struct pm2fb_par *p = info->par; 9758c2ecf20Sopenharmony_ci u32 base; 9768c2ecf20Sopenharmony_ci u32 depth = (info->var.bits_per_pixel + 7) & ~7; 9778c2ecf20Sopenharmony_ci u32 xres = (info->var.xres + 31) & ~31; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci depth = (depth > 32) ? 32 : depth; 9808c2ecf20Sopenharmony_ci base = to3264(var->yoffset * xres + var->xoffset, depth, 1); 9818c2ecf20Sopenharmony_ci WAIT_FIFO(p, 1); 9828c2ecf20Sopenharmony_ci pm2_WR(p, PM2R_SCREEN_BASE, base); 9838c2ecf20Sopenharmony_ci return 0; 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci/** 9878c2ecf20Sopenharmony_ci * pm2fb_blank - Blanks the display. 9888c2ecf20Sopenharmony_ci * @blank_mode: the blank mode we want. 9898c2ecf20Sopenharmony_ci * @info: frame buffer structure that represents a single frame buffer 9908c2ecf20Sopenharmony_ci * 9918c2ecf20Sopenharmony_ci * Blank the screen if blank_mode != 0, else unblank. Return 0 if 9928c2ecf20Sopenharmony_ci * blanking succeeded, != 0 if un-/blanking failed due to e.g. a 9938c2ecf20Sopenharmony_ci * video mode which doesn't support it. Implements VESA suspend 9948c2ecf20Sopenharmony_ci * and powerdown modes on hardware that supports disabling hsync/vsync: 9958c2ecf20Sopenharmony_ci * blank_mode == 2: suspend vsync 9968c2ecf20Sopenharmony_ci * blank_mode == 3: suspend hsync 9978c2ecf20Sopenharmony_ci * blank_mode == 4: powerdown 9988c2ecf20Sopenharmony_ci * 9998c2ecf20Sopenharmony_ci * Returns negative errno on error, or zero on success. 10008c2ecf20Sopenharmony_ci * 10018c2ecf20Sopenharmony_ci */ 10028c2ecf20Sopenharmony_cistatic int pm2fb_blank(int blank_mode, struct fb_info *info) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci struct pm2fb_par *par = info->par; 10058c2ecf20Sopenharmony_ci u32 video = par->video; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci DPRINTK("blank_mode %d\n", blank_mode); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci switch (blank_mode) { 10108c2ecf20Sopenharmony_ci case FB_BLANK_UNBLANK: 10118c2ecf20Sopenharmony_ci /* Screen: On */ 10128c2ecf20Sopenharmony_ci video |= PM2F_VIDEO_ENABLE; 10138c2ecf20Sopenharmony_ci break; 10148c2ecf20Sopenharmony_ci case FB_BLANK_NORMAL: 10158c2ecf20Sopenharmony_ci /* Screen: Off */ 10168c2ecf20Sopenharmony_ci video &= ~PM2F_VIDEO_ENABLE; 10178c2ecf20Sopenharmony_ci break; 10188c2ecf20Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 10198c2ecf20Sopenharmony_ci /* VSync: Off */ 10208c2ecf20Sopenharmony_ci video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW); 10218c2ecf20Sopenharmony_ci break; 10228c2ecf20Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 10238c2ecf20Sopenharmony_ci /* HSync: Off */ 10248c2ecf20Sopenharmony_ci video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW); 10258c2ecf20Sopenharmony_ci break; 10268c2ecf20Sopenharmony_ci case FB_BLANK_POWERDOWN: 10278c2ecf20Sopenharmony_ci /* HSync: Off, VSync: Off */ 10288c2ecf20Sopenharmony_ci video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK | PM2F_BLANK_LOW); 10298c2ecf20Sopenharmony_ci break; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci set_video(par, video); 10328c2ecf20Sopenharmony_ci return 0; 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cistatic int pm2fb_sync(struct fb_info *info) 10368c2ecf20Sopenharmony_ci{ 10378c2ecf20Sopenharmony_ci struct pm2fb_par *par = info->par; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci WAIT_FIFO(par, 1); 10408c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_SYNC, 0); 10418c2ecf20Sopenharmony_ci mb(); 10428c2ecf20Sopenharmony_ci do { 10438c2ecf20Sopenharmony_ci while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0) 10448c2ecf20Sopenharmony_ci cpu_relax(); 10458c2ecf20Sopenharmony_ci } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC)); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci return 0; 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic void pm2fb_fillrect(struct fb_info *info, 10518c2ecf20Sopenharmony_ci const struct fb_fillrect *region) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci struct pm2fb_par *par = info->par; 10548c2ecf20Sopenharmony_ci struct fb_fillrect modded; 10558c2ecf20Sopenharmony_ci int vxres, vyres; 10568c2ecf20Sopenharmony_ci u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? 10578c2ecf20Sopenharmony_ci ((u32 *)info->pseudo_palette)[region->color] : region->color; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (info->state != FBINFO_STATE_RUNNING) 10608c2ecf20Sopenharmony_ci return; 10618c2ecf20Sopenharmony_ci if ((info->flags & FBINFO_HWACCEL_DISABLED) || 10628c2ecf20Sopenharmony_ci region->rop != ROP_COPY ) { 10638c2ecf20Sopenharmony_ci cfb_fillrect(info, region); 10648c2ecf20Sopenharmony_ci return; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci vxres = info->var.xres_virtual; 10688c2ecf20Sopenharmony_ci vyres = info->var.yres_virtual; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci memcpy(&modded, region, sizeof(struct fb_fillrect)); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (!modded.width || !modded.height || 10738c2ecf20Sopenharmony_ci modded.dx >= vxres || modded.dy >= vyres) 10748c2ecf20Sopenharmony_ci return; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (modded.dx + modded.width > vxres) 10778c2ecf20Sopenharmony_ci modded.width = vxres - modded.dx; 10788c2ecf20Sopenharmony_ci if (modded.dy + modded.height > vyres) 10798c2ecf20Sopenharmony_ci modded.height = vyres - modded.dy; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 8) 10828c2ecf20Sopenharmony_ci color |= color << 8; 10838c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel <= 16) 10848c2ecf20Sopenharmony_ci color |= color << 16; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci WAIT_FIFO(par, 3); 10878c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE); 10888c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx); 10898c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width); 10908c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel != 24) { 10918c2ecf20Sopenharmony_ci WAIT_FIFO(par, 2); 10928c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_FB_BLOCK_COLOR, color); 10938c2ecf20Sopenharmony_ci wmb(); 10948c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RENDER, 10958c2ecf20Sopenharmony_ci PM2F_RENDER_RECTANGLE | PM2F_RENDER_FASTFILL); 10968c2ecf20Sopenharmony_ci } else { 10978c2ecf20Sopenharmony_ci WAIT_FIFO(par, 4); 10988c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_COLOR_DDA_MODE, 1); 10998c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_CONSTANT_COLOR, color); 11008c2ecf20Sopenharmony_ci wmb(); 11018c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RENDER, 11028c2ecf20Sopenharmony_ci PM2F_RENDER_RECTANGLE | 11038c2ecf20Sopenharmony_ci PM2F_INCREASE_X | PM2F_INCREASE_Y ); 11048c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_COLOR_DDA_MODE, 0); 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic void pm2fb_copyarea(struct fb_info *info, 11098c2ecf20Sopenharmony_ci const struct fb_copyarea *area) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci struct pm2fb_par *par = info->par; 11128c2ecf20Sopenharmony_ci struct fb_copyarea modded; 11138c2ecf20Sopenharmony_ci u32 vxres, vyres; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (info->state != FBINFO_STATE_RUNNING) 11168c2ecf20Sopenharmony_ci return; 11178c2ecf20Sopenharmony_ci if (info->flags & FBINFO_HWACCEL_DISABLED) { 11188c2ecf20Sopenharmony_ci cfb_copyarea(info, area); 11198c2ecf20Sopenharmony_ci return; 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci memcpy(&modded, area, sizeof(struct fb_copyarea)); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci vxres = info->var.xres_virtual; 11258c2ecf20Sopenharmony_ci vyres = info->var.yres_virtual; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci if (!modded.width || !modded.height || 11288c2ecf20Sopenharmony_ci modded.sx >= vxres || modded.sy >= vyres || 11298c2ecf20Sopenharmony_ci modded.dx >= vxres || modded.dy >= vyres) 11308c2ecf20Sopenharmony_ci return; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci if (modded.sx + modded.width > vxres) 11338c2ecf20Sopenharmony_ci modded.width = vxres - modded.sx; 11348c2ecf20Sopenharmony_ci if (modded.dx + modded.width > vxres) 11358c2ecf20Sopenharmony_ci modded.width = vxres - modded.dx; 11368c2ecf20Sopenharmony_ci if (modded.sy + modded.height > vyres) 11378c2ecf20Sopenharmony_ci modded.height = vyres - modded.sy; 11388c2ecf20Sopenharmony_ci if (modded.dy + modded.height > vyres) 11398c2ecf20Sopenharmony_ci modded.height = vyres - modded.dy; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci WAIT_FIFO(par, 5); 11428c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE | 11438c2ecf20Sopenharmony_ci PM2F_CONFIG_FB_READ_SOURCE_ENABLE); 11448c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_FB_SOURCE_DELTA, 11458c2ecf20Sopenharmony_ci ((modded.sy - modded.dy) & 0xfff) << 16 | 11468c2ecf20Sopenharmony_ci ((modded.sx - modded.dx) & 0xfff)); 11478c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx); 11488c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width); 11498c2ecf20Sopenharmony_ci wmb(); 11508c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE | 11518c2ecf20Sopenharmony_ci (modded.dx < modded.sx ? PM2F_INCREASE_X : 0) | 11528c2ecf20Sopenharmony_ci (modded.dy < modded.sy ? PM2F_INCREASE_Y : 0)); 11538c2ecf20Sopenharmony_ci} 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_cistatic void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image) 11568c2ecf20Sopenharmony_ci{ 11578c2ecf20Sopenharmony_ci struct pm2fb_par *par = info->par; 11588c2ecf20Sopenharmony_ci u32 height = image->height; 11598c2ecf20Sopenharmony_ci u32 fgx, bgx; 11608c2ecf20Sopenharmony_ci const u32 *src = (const u32 *)image->data; 11618c2ecf20Sopenharmony_ci u32 xres = (info->var.xres + 31) & ~31; 11628c2ecf20Sopenharmony_ci int raster_mode = 1; /* invert bits */ 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN 11658c2ecf20Sopenharmony_ci raster_mode |= 3 << 7; /* reverse byte order */ 11668c2ecf20Sopenharmony_ci#endif 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci if (info->state != FBINFO_STATE_RUNNING) 11698c2ecf20Sopenharmony_ci return; 11708c2ecf20Sopenharmony_ci if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1) { 11718c2ecf20Sopenharmony_ci cfb_imageblit(info, image); 11728c2ecf20Sopenharmony_ci return; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci switch (info->fix.visual) { 11758c2ecf20Sopenharmony_ci case FB_VISUAL_PSEUDOCOLOR: 11768c2ecf20Sopenharmony_ci fgx = image->fg_color; 11778c2ecf20Sopenharmony_ci bgx = image->bg_color; 11788c2ecf20Sopenharmony_ci break; 11798c2ecf20Sopenharmony_ci case FB_VISUAL_TRUECOLOR: 11808c2ecf20Sopenharmony_ci default: 11818c2ecf20Sopenharmony_ci fgx = par->palette[image->fg_color]; 11828c2ecf20Sopenharmony_ci bgx = par->palette[image->bg_color]; 11838c2ecf20Sopenharmony_ci break; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 8) { 11868c2ecf20Sopenharmony_ci fgx |= fgx << 8; 11878c2ecf20Sopenharmony_ci bgx |= bgx << 8; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel <= 16) { 11908c2ecf20Sopenharmony_ci fgx |= fgx << 16; 11918c2ecf20Sopenharmony_ci bgx |= bgx << 16; 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci WAIT_FIFO(par, 13); 11958c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres)); 11968c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_SCISSOR_MIN_XY, 11978c2ecf20Sopenharmony_ci ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff)); 11988c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_SCISSOR_MAX_XY, 11998c2ecf20Sopenharmony_ci (((image->dy + image->height) & 0x0fff) << 16) | 12008c2ecf20Sopenharmony_ci ((image->dx + image->width) & 0x0fff)); 12018c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_SCISSOR_MODE, 1); 12028c2ecf20Sopenharmony_ci /* GXcopy & UNIT_ENABLE */ 12038c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_LOGICAL_OP_MODE, (0x3 << 1) | 1); 12048c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RECTANGLE_ORIGIN, 12058c2ecf20Sopenharmony_ci ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff)); 12068c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RECTANGLE_SIZE, 12078c2ecf20Sopenharmony_ci ((image->height & 0x0fff) << 16) | 12088c2ecf20Sopenharmony_ci ((image->width) & 0x0fff)); 12098c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 24) { 12108c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_COLOR_DDA_MODE, 1); 12118c2ecf20Sopenharmony_ci /* clear area */ 12128c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_CONSTANT_COLOR, bgx); 12138c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RENDER, 12148c2ecf20Sopenharmony_ci PM2F_RENDER_RECTANGLE | 12158c2ecf20Sopenharmony_ci PM2F_INCREASE_X | PM2F_INCREASE_Y); 12168c2ecf20Sopenharmony_ci /* BitMapPackEachScanline */ 12178c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode | (1 << 9)); 12188c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_CONSTANT_COLOR, fgx); 12198c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RENDER, 12208c2ecf20Sopenharmony_ci PM2F_RENDER_RECTANGLE | 12218c2ecf20Sopenharmony_ci PM2F_INCREASE_X | PM2F_INCREASE_Y | 12228c2ecf20Sopenharmony_ci PM2F_RENDER_SYNC_ON_BIT_MASK); 12238c2ecf20Sopenharmony_ci } else { 12248c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_COLOR_DDA_MODE, 0); 12258c2ecf20Sopenharmony_ci /* clear area */ 12268c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_FB_BLOCK_COLOR, bgx); 12278c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RENDER, 12288c2ecf20Sopenharmony_ci PM2F_RENDER_RECTANGLE | 12298c2ecf20Sopenharmony_ci PM2F_RENDER_FASTFILL | 12308c2ecf20Sopenharmony_ci PM2F_INCREASE_X | PM2F_INCREASE_Y); 12318c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode); 12328c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx); 12338c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RENDER, 12348c2ecf20Sopenharmony_ci PM2F_RENDER_RECTANGLE | 12358c2ecf20Sopenharmony_ci PM2F_INCREASE_X | PM2F_INCREASE_Y | 12368c2ecf20Sopenharmony_ci PM2F_RENDER_FASTFILL | 12378c2ecf20Sopenharmony_ci PM2F_RENDER_SYNC_ON_BIT_MASK); 12388c2ecf20Sopenharmony_ci } 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci while (height--) { 12418c2ecf20Sopenharmony_ci int width = ((image->width + 7) >> 3) 12428c2ecf20Sopenharmony_ci + info->pixmap.scan_align - 1; 12438c2ecf20Sopenharmony_ci width >>= 2; 12448c2ecf20Sopenharmony_ci WAIT_FIFO(par, width); 12458c2ecf20Sopenharmony_ci while (width--) { 12468c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_BIT_MASK_PATTERN, *src); 12478c2ecf20Sopenharmony_ci src++; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci WAIT_FIFO(par, 3); 12518c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RASTERIZER_MODE, 0); 12528c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_COLOR_DDA_MODE, 0); 12538c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_SCISSOR_MODE, 0); 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci/* 12578c2ecf20Sopenharmony_ci * Hardware cursor support. 12588c2ecf20Sopenharmony_ci */ 12598c2ecf20Sopenharmony_cistatic const u8 cursor_bits_lookup[16] = { 12608c2ecf20Sopenharmony_ci 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 12618c2ecf20Sopenharmony_ci 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 12628c2ecf20Sopenharmony_ci}; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_cistatic int pm2vfb_cursor(struct fb_info *info, struct fb_cursor *cursor) 12658c2ecf20Sopenharmony_ci{ 12668c2ecf20Sopenharmony_ci struct pm2fb_par *par = info->par; 12678c2ecf20Sopenharmony_ci u8 mode = PM2F_CURSORMODE_TYPE_X; 12688c2ecf20Sopenharmony_ci int x = cursor->image.dx - info->var.xoffset; 12698c2ecf20Sopenharmony_ci int y = cursor->image.dy - info->var.yoffset; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci if (cursor->enable) 12728c2ecf20Sopenharmony_ci mode |= PM2F_CURSORMODE_CURSOR_ENABLE; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_MODE, mode); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci if (!cursor->enable) 12778c2ecf20Sopenharmony_ci x = 2047; /* push it outside display */ 12788c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_LOW, x & 0xff); 12798c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0xf); 12808c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_LOW, y & 0xff); 12818c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HIGH, (y >> 8) & 0xf); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* 12848c2ecf20Sopenharmony_ci * If the cursor is not be changed this means either we want the 12858c2ecf20Sopenharmony_ci * current cursor state (if enable is set) or we want to query what 12868c2ecf20Sopenharmony_ci * we can do with the cursor (if enable is not set) 12878c2ecf20Sopenharmony_ci */ 12888c2ecf20Sopenharmony_ci if (!cursor->set) 12898c2ecf20Sopenharmony_ci return 0; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if (cursor->set & FB_CUR_SETHOT) { 12928c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HOT, 12938c2ecf20Sopenharmony_ci cursor->hot.x & 0x3f); 12948c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HOT, 12958c2ecf20Sopenharmony_ci cursor->hot.y & 0x3f); 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci if (cursor->set & FB_CUR_SETCMAP) { 12998c2ecf20Sopenharmony_ci u32 fg_idx = cursor->image.fg_color; 13008c2ecf20Sopenharmony_ci u32 bg_idx = cursor->image.bg_color; 13018c2ecf20Sopenharmony_ci struct fb_cmap cmap = info->cmap; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci /* the X11 driver says one should use these color registers */ 13048c2ecf20Sopenharmony_ci pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8); 13058c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 0, 13068c2ecf20Sopenharmony_ci cmap.red[bg_idx] >> 8 ); 13078c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 1, 13088c2ecf20Sopenharmony_ci cmap.green[bg_idx] >> 8 ); 13098c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 2, 13108c2ecf20Sopenharmony_ci cmap.blue[bg_idx] >> 8 ); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 3, 13138c2ecf20Sopenharmony_ci cmap.red[fg_idx] >> 8 ); 13148c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 4, 13158c2ecf20Sopenharmony_ci cmap.green[fg_idx] >> 8 ); 13168c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 5, 13178c2ecf20Sopenharmony_ci cmap.blue[fg_idx] >> 8 ); 13188c2ecf20Sopenharmony_ci pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { 13228c2ecf20Sopenharmony_ci u8 *bitmap = (u8 *)cursor->image.data; 13238c2ecf20Sopenharmony_ci u8 *mask = (u8 *)cursor->mask; 13248c2ecf20Sopenharmony_ci int i; 13258c2ecf20Sopenharmony_ci int pos = PM2VI_RD_CURSOR_PATTERN; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci for (i = 0; i < cursor->image.height; i++) { 13288c2ecf20Sopenharmony_ci int j = (cursor->image.width + 7) >> 3; 13298c2ecf20Sopenharmony_ci int k = 8 - j; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci for (; j > 0; j--) { 13348c2ecf20Sopenharmony_ci u8 data = *bitmap ^ *mask; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci if (cursor->rop == ROP_COPY) 13378c2ecf20Sopenharmony_ci data = *mask & *bitmap; 13388c2ecf20Sopenharmony_ci /* Upper 4 bits of bitmap data */ 13398c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, pos++, 13408c2ecf20Sopenharmony_ci cursor_bits_lookup[data >> 4] | 13418c2ecf20Sopenharmony_ci (cursor_bits_lookup[*mask >> 4] << 1)); 13428c2ecf20Sopenharmony_ci /* Lower 4 bits of bitmap */ 13438c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, pos++, 13448c2ecf20Sopenharmony_ci cursor_bits_lookup[data & 0xf] | 13458c2ecf20Sopenharmony_ci (cursor_bits_lookup[*mask & 0xf] << 1)); 13468c2ecf20Sopenharmony_ci bitmap++; 13478c2ecf20Sopenharmony_ci mask++; 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci for (; k > 0; k--) { 13508c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, pos++, 0); 13518c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, pos++, 0); 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci while (pos < (1024 + PM2VI_RD_CURSOR_PATTERN)) { 13568c2ecf20Sopenharmony_ci pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8); 13578c2ecf20Sopenharmony_ci pm2v_RDAC_WR(par, pos++, 0); 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci return 0; 13638c2ecf20Sopenharmony_ci} 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_cistatic int pm2fb_cursor(struct fb_info *info, struct fb_cursor *cursor) 13668c2ecf20Sopenharmony_ci{ 13678c2ecf20Sopenharmony_ci struct pm2fb_par *par = info->par; 13688c2ecf20Sopenharmony_ci u8 mode; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci if (!hwcursor) 13718c2ecf20Sopenharmony_ci return -EINVAL; /* just to force soft_cursor() call */ 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci /* Too large of a cursor or wrong bpp :-( */ 13748c2ecf20Sopenharmony_ci if (cursor->image.width > 64 || 13758c2ecf20Sopenharmony_ci cursor->image.height > 64 || 13768c2ecf20Sopenharmony_ci cursor->image.depth > 1) 13778c2ecf20Sopenharmony_ci return -EINVAL; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (par->type == PM2_TYPE_PERMEDIA2V) 13808c2ecf20Sopenharmony_ci return pm2vfb_cursor(info, cursor); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci mode = 0x40; 13838c2ecf20Sopenharmony_ci if (cursor->enable) 13848c2ecf20Sopenharmony_ci mode = 0x43; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci pm2_RDAC_WR(par, PM2I_RD_CURSOR_CONTROL, mode); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci /* 13898c2ecf20Sopenharmony_ci * If the cursor is not be changed this means either we want the 13908c2ecf20Sopenharmony_ci * current cursor state (if enable is set) or we want to query what 13918c2ecf20Sopenharmony_ci * we can do with the cursor (if enable is not set) 13928c2ecf20Sopenharmony_ci */ 13938c2ecf20Sopenharmony_ci if (!cursor->set) 13948c2ecf20Sopenharmony_ci return 0; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci if (cursor->set & FB_CUR_SETPOS) { 13978c2ecf20Sopenharmony_ci int x = cursor->image.dx - info->var.xoffset + 63; 13988c2ecf20Sopenharmony_ci int y = cursor->image.dy - info->var.yoffset + 63; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci WAIT_FIFO(par, 4); 14018c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_X_LSB, x & 0xff); 14028c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_X_MSB, (x >> 8) & 0x7); 14038c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_Y_LSB, y & 0xff); 14048c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_Y_MSB, (y >> 8) & 0x7); 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if (cursor->set & FB_CUR_SETCMAP) { 14088c2ecf20Sopenharmony_ci u32 fg_idx = cursor->image.fg_color; 14098c2ecf20Sopenharmony_ci u32 bg_idx = cursor->image.bg_color; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci WAIT_FIFO(par, 7); 14128c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_COLOR_ADDRESS, 1); 14138c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, 14148c2ecf20Sopenharmony_ci info->cmap.red[bg_idx] >> 8); 14158c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, 14168c2ecf20Sopenharmony_ci info->cmap.green[bg_idx] >> 8); 14178c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, 14188c2ecf20Sopenharmony_ci info->cmap.blue[bg_idx] >> 8); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, 14218c2ecf20Sopenharmony_ci info->cmap.red[fg_idx] >> 8); 14228c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, 14238c2ecf20Sopenharmony_ci info->cmap.green[fg_idx] >> 8); 14248c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, 14258c2ecf20Sopenharmony_ci info->cmap.blue[fg_idx] >> 8); 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { 14298c2ecf20Sopenharmony_ci u8 *bitmap = (u8 *)cursor->image.data; 14308c2ecf20Sopenharmony_ci u8 *mask = (u8 *)cursor->mask; 14318c2ecf20Sopenharmony_ci int i; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci WAIT_FIFO(par, 1); 14348c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_PALETTE_WRITE_ADDRESS, 0); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci for (i = 0; i < cursor->image.height; i++) { 14378c2ecf20Sopenharmony_ci int j = (cursor->image.width + 7) >> 3; 14388c2ecf20Sopenharmony_ci int k = 8 - j; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci WAIT_FIFO(par, 8); 14418c2ecf20Sopenharmony_ci for (; j > 0; j--) { 14428c2ecf20Sopenharmony_ci u8 data = *bitmap ^ *mask; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci if (cursor->rop == ROP_COPY) 14458c2ecf20Sopenharmony_ci data = *mask & *bitmap; 14468c2ecf20Sopenharmony_ci /* bitmap data */ 14478c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_DATA, data); 14488c2ecf20Sopenharmony_ci bitmap++; 14498c2ecf20Sopenharmony_ci mask++; 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci for (; k > 0; k--) 14528c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci for (; i < 64; i++) { 14558c2ecf20Sopenharmony_ci int j = 8; 14568c2ecf20Sopenharmony_ci WAIT_FIFO(par, 8); 14578c2ecf20Sopenharmony_ci while (j-- > 0) 14588c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci mask = (u8 *)cursor->mask; 14628c2ecf20Sopenharmony_ci for (i = 0; i < cursor->image.height; i++) { 14638c2ecf20Sopenharmony_ci int j = (cursor->image.width + 7) >> 3; 14648c2ecf20Sopenharmony_ci int k = 8 - j; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci WAIT_FIFO(par, 8); 14678c2ecf20Sopenharmony_ci for (; j > 0; j--) { 14688c2ecf20Sopenharmony_ci /* mask */ 14698c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_DATA, *mask); 14708c2ecf20Sopenharmony_ci mask++; 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci for (; k > 0; k--) 14738c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci for (; i < 64; i++) { 14768c2ecf20Sopenharmony_ci int j = 8; 14778c2ecf20Sopenharmony_ci WAIT_FIFO(par, 8); 14788c2ecf20Sopenharmony_ci while (j-- > 0) 14798c2ecf20Sopenharmony_ci pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci return 0; 14838c2ecf20Sopenharmony_ci} 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci/* ------------ Hardware Independent Functions ------------ */ 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci/* 14888c2ecf20Sopenharmony_ci * Frame buffer operations 14898c2ecf20Sopenharmony_ci */ 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_cistatic const struct fb_ops pm2fb_ops = { 14928c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 14938c2ecf20Sopenharmony_ci .fb_check_var = pm2fb_check_var, 14948c2ecf20Sopenharmony_ci .fb_set_par = pm2fb_set_par, 14958c2ecf20Sopenharmony_ci .fb_setcolreg = pm2fb_setcolreg, 14968c2ecf20Sopenharmony_ci .fb_blank = pm2fb_blank, 14978c2ecf20Sopenharmony_ci .fb_pan_display = pm2fb_pan_display, 14988c2ecf20Sopenharmony_ci .fb_fillrect = pm2fb_fillrect, 14998c2ecf20Sopenharmony_ci .fb_copyarea = pm2fb_copyarea, 15008c2ecf20Sopenharmony_ci .fb_imageblit = pm2fb_imageblit, 15018c2ecf20Sopenharmony_ci .fb_sync = pm2fb_sync, 15028c2ecf20Sopenharmony_ci .fb_cursor = pm2fb_cursor, 15038c2ecf20Sopenharmony_ci}; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci/* 15068c2ecf20Sopenharmony_ci * PCI stuff 15078c2ecf20Sopenharmony_ci */ 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci/** 15118c2ecf20Sopenharmony_ci * Device initialisation 15128c2ecf20Sopenharmony_ci * 15138c2ecf20Sopenharmony_ci * Initialise and allocate resource for PCI device. 15148c2ecf20Sopenharmony_ci * 15158c2ecf20Sopenharmony_ci * @param pdev PCI device. 15168c2ecf20Sopenharmony_ci * @param id PCI device ID. 15178c2ecf20Sopenharmony_ci */ 15188c2ecf20Sopenharmony_cistatic int pm2fb_probe(struct pci_dev *pdev, const struct pci_device_id *id) 15198c2ecf20Sopenharmony_ci{ 15208c2ecf20Sopenharmony_ci struct pm2fb_par *default_par; 15218c2ecf20Sopenharmony_ci struct fb_info *info; 15228c2ecf20Sopenharmony_ci int err; 15238c2ecf20Sopenharmony_ci int retval = -ENXIO; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 15268c2ecf20Sopenharmony_ci if (err) { 15278c2ecf20Sopenharmony_ci printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err); 15288c2ecf20Sopenharmony_ci return err; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(struct pm2fb_par), &pdev->dev); 15328c2ecf20Sopenharmony_ci if (!info) { 15338c2ecf20Sopenharmony_ci err = -ENOMEM; 15348c2ecf20Sopenharmony_ci goto err_exit_disable; 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci default_par = info->par; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci switch (pdev->device) { 15398c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_TI_TVP4020: 15408c2ecf20Sopenharmony_ci strcpy(pm2fb_fix.id, "TVP4020"); 15418c2ecf20Sopenharmony_ci default_par->type = PM2_TYPE_PERMEDIA2; 15428c2ecf20Sopenharmony_ci break; 15438c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_3DLABS_PERMEDIA2: 15448c2ecf20Sopenharmony_ci strcpy(pm2fb_fix.id, "Permedia2"); 15458c2ecf20Sopenharmony_ci default_par->type = PM2_TYPE_PERMEDIA2; 15468c2ecf20Sopenharmony_ci break; 15478c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_3DLABS_PERMEDIA2V: 15488c2ecf20Sopenharmony_ci strcpy(pm2fb_fix.id, "Permedia2v"); 15498c2ecf20Sopenharmony_ci default_par->type = PM2_TYPE_PERMEDIA2V; 15508c2ecf20Sopenharmony_ci break; 15518c2ecf20Sopenharmony_ci } 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci pm2fb_fix.mmio_start = pci_resource_start(pdev, 0); 15548c2ecf20Sopenharmony_ci pm2fb_fix.mmio_len = PM2_REGS_SIZE; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci#if defined(__BIG_ENDIAN) 15578c2ecf20Sopenharmony_ci /* 15588c2ecf20Sopenharmony_ci * PM2 has a 64k register file, mapped twice in 128k. Lower 15598c2ecf20Sopenharmony_ci * map is little-endian, upper map is big-endian. 15608c2ecf20Sopenharmony_ci */ 15618c2ecf20Sopenharmony_ci pm2fb_fix.mmio_start += PM2_REGS_SIZE; 15628c2ecf20Sopenharmony_ci DPRINTK("Adjusting register base for big-endian.\n"); 15638c2ecf20Sopenharmony_ci#endif 15648c2ecf20Sopenharmony_ci DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci /* Registers - request region and map it. */ 15678c2ecf20Sopenharmony_ci if (!request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len, 15688c2ecf20Sopenharmony_ci "pm2fb regbase")) { 15698c2ecf20Sopenharmony_ci printk(KERN_WARNING "pm2fb: Can't reserve regbase.\n"); 15708c2ecf20Sopenharmony_ci goto err_exit_neither; 15718c2ecf20Sopenharmony_ci } 15728c2ecf20Sopenharmony_ci default_par->v_regs = 15738c2ecf20Sopenharmony_ci ioremap(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); 15748c2ecf20Sopenharmony_ci if (!default_par->v_regs) { 15758c2ecf20Sopenharmony_ci printk(KERN_WARNING "pm2fb: Can't remap %s register area.\n", 15768c2ecf20Sopenharmony_ci pm2fb_fix.id); 15778c2ecf20Sopenharmony_ci release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); 15788c2ecf20Sopenharmony_ci goto err_exit_neither; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci /* Stash away memory register info for use when we reset the board */ 15828c2ecf20Sopenharmony_ci default_par->mem_control = pm2_RD(default_par, PM2R_MEM_CONTROL); 15838c2ecf20Sopenharmony_ci default_par->boot_address = pm2_RD(default_par, PM2R_BOOT_ADDRESS); 15848c2ecf20Sopenharmony_ci default_par->mem_config = pm2_RD(default_par, PM2R_MEM_CONFIG); 15858c2ecf20Sopenharmony_ci DPRINTK("MemControl 0x%x BootAddress 0x%x MemConfig 0x%x\n", 15868c2ecf20Sopenharmony_ci default_par->mem_control, default_par->boot_address, 15878c2ecf20Sopenharmony_ci default_par->mem_config); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci if (default_par->mem_control == 0 && 15908c2ecf20Sopenharmony_ci default_par->boot_address == 0x31 && 15918c2ecf20Sopenharmony_ci default_par->mem_config == 0x259fffff) { 15928c2ecf20Sopenharmony_ci default_par->memclock = CVPPC_MEMCLOCK; 15938c2ecf20Sopenharmony_ci default_par->mem_control = 0; 15948c2ecf20Sopenharmony_ci default_par->boot_address = 0x20; 15958c2ecf20Sopenharmony_ci default_par->mem_config = 0xe6002021; 15968c2ecf20Sopenharmony_ci if (pdev->subsystem_vendor == 0x1048 && 15978c2ecf20Sopenharmony_ci pdev->subsystem_device == 0x0a31) { 15988c2ecf20Sopenharmony_ci DPRINTK("subsystem_vendor: %04x, " 15998c2ecf20Sopenharmony_ci "subsystem_device: %04x\n", 16008c2ecf20Sopenharmony_ci pdev->subsystem_vendor, pdev->subsystem_device); 16018c2ecf20Sopenharmony_ci DPRINTK("We have not been initialized by VGA BIOS and " 16028c2ecf20Sopenharmony_ci "are running on an Elsa Winner 2000 Office\n"); 16038c2ecf20Sopenharmony_ci DPRINTK("Initializing card timings manually...\n"); 16048c2ecf20Sopenharmony_ci default_par->memclock = 100000; 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci if (pdev->subsystem_vendor == 0x3d3d && 16078c2ecf20Sopenharmony_ci pdev->subsystem_device == 0x0100) { 16088c2ecf20Sopenharmony_ci DPRINTK("subsystem_vendor: %04x, " 16098c2ecf20Sopenharmony_ci "subsystem_device: %04x\n", 16108c2ecf20Sopenharmony_ci pdev->subsystem_vendor, pdev->subsystem_device); 16118c2ecf20Sopenharmony_ci DPRINTK("We have not been initialized by VGA BIOS and " 16128c2ecf20Sopenharmony_ci "are running on an 3dlabs reference board\n"); 16138c2ecf20Sopenharmony_ci DPRINTK("Initializing card timings manually...\n"); 16148c2ecf20Sopenharmony_ci default_par->memclock = 74894; 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci } 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci /* Now work out how big lfb is going to be. */ 16198c2ecf20Sopenharmony_ci switch (default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) { 16208c2ecf20Sopenharmony_ci case PM2F_MEM_BANKS_1: 16218c2ecf20Sopenharmony_ci pm2fb_fix.smem_len = 0x200000; 16228c2ecf20Sopenharmony_ci break; 16238c2ecf20Sopenharmony_ci case PM2F_MEM_BANKS_2: 16248c2ecf20Sopenharmony_ci pm2fb_fix.smem_len = 0x400000; 16258c2ecf20Sopenharmony_ci break; 16268c2ecf20Sopenharmony_ci case PM2F_MEM_BANKS_3: 16278c2ecf20Sopenharmony_ci pm2fb_fix.smem_len = 0x600000; 16288c2ecf20Sopenharmony_ci break; 16298c2ecf20Sopenharmony_ci case PM2F_MEM_BANKS_4: 16308c2ecf20Sopenharmony_ci pm2fb_fix.smem_len = 0x800000; 16318c2ecf20Sopenharmony_ci break; 16328c2ecf20Sopenharmony_ci } 16338c2ecf20Sopenharmony_ci pm2fb_fix.smem_start = pci_resource_start(pdev, 1); 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci /* Linear frame buffer - request region and map it. */ 16368c2ecf20Sopenharmony_ci if (!request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len, 16378c2ecf20Sopenharmony_ci "pm2fb smem")) { 16388c2ecf20Sopenharmony_ci printk(KERN_WARNING "pm2fb: Can't reserve smem.\n"); 16398c2ecf20Sopenharmony_ci goto err_exit_mmio; 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci info->screen_base = 16428c2ecf20Sopenharmony_ci ioremap_wc(pm2fb_fix.smem_start, pm2fb_fix.smem_len); 16438c2ecf20Sopenharmony_ci if (!info->screen_base) { 16448c2ecf20Sopenharmony_ci printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n"); 16458c2ecf20Sopenharmony_ci release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); 16468c2ecf20Sopenharmony_ci goto err_exit_mmio; 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci if (!nomtrr) 16508c2ecf20Sopenharmony_ci default_par->wc_cookie = arch_phys_wc_add(pm2fb_fix.smem_start, 16518c2ecf20Sopenharmony_ci pm2fb_fix.smem_len); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci info->fbops = &pm2fb_ops; 16548c2ecf20Sopenharmony_ci info->fix = pm2fb_fix; 16558c2ecf20Sopenharmony_ci info->pseudo_palette = default_par->palette; 16568c2ecf20Sopenharmony_ci info->flags = FBINFO_DEFAULT | 16578c2ecf20Sopenharmony_ci FBINFO_HWACCEL_YPAN | 16588c2ecf20Sopenharmony_ci FBINFO_HWACCEL_COPYAREA | 16598c2ecf20Sopenharmony_ci FBINFO_HWACCEL_IMAGEBLIT | 16608c2ecf20Sopenharmony_ci FBINFO_HWACCEL_FILLRECT; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci info->pixmap.addr = kmalloc(PM2_PIXMAP_SIZE, GFP_KERNEL); 16638c2ecf20Sopenharmony_ci if (!info->pixmap.addr) { 16648c2ecf20Sopenharmony_ci retval = -ENOMEM; 16658c2ecf20Sopenharmony_ci goto err_exit_pixmap; 16668c2ecf20Sopenharmony_ci } 16678c2ecf20Sopenharmony_ci info->pixmap.size = PM2_PIXMAP_SIZE; 16688c2ecf20Sopenharmony_ci info->pixmap.buf_align = 4; 16698c2ecf20Sopenharmony_ci info->pixmap.scan_align = 4; 16708c2ecf20Sopenharmony_ci info->pixmap.access_align = 32; 16718c2ecf20Sopenharmony_ci info->pixmap.flags = FB_PIXMAP_SYSTEM; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci if (noaccel) { 16748c2ecf20Sopenharmony_ci printk(KERN_DEBUG "disabling acceleration\n"); 16758c2ecf20Sopenharmony_ci info->flags |= FBINFO_HWACCEL_DISABLED; 16768c2ecf20Sopenharmony_ci info->pixmap.scan_align = 1; 16778c2ecf20Sopenharmony_ci } 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci if (!mode_option) 16808c2ecf20Sopenharmony_ci mode_option = "640x480@60"; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); 16838c2ecf20Sopenharmony_ci if (!err || err == 4) 16848c2ecf20Sopenharmony_ci info->var = pm2fb_var; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci retval = fb_alloc_cmap(&info->cmap, 256, 0); 16878c2ecf20Sopenharmony_ci if (retval < 0) 16888c2ecf20Sopenharmony_ci goto err_exit_both; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci retval = register_framebuffer(info); 16918c2ecf20Sopenharmony_ci if (retval < 0) 16928c2ecf20Sopenharmony_ci goto err_exit_all; 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci fb_info(info, "%s frame buffer device, memory = %dK\n", 16958c2ecf20Sopenharmony_ci info->fix.id, pm2fb_fix.smem_len / 1024); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci /* 16988c2ecf20Sopenharmony_ci * Our driver data 16998c2ecf20Sopenharmony_ci */ 17008c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, info); 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci return 0; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci err_exit_all: 17058c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 17068c2ecf20Sopenharmony_ci err_exit_both: 17078c2ecf20Sopenharmony_ci kfree(info->pixmap.addr); 17088c2ecf20Sopenharmony_ci err_exit_pixmap: 17098c2ecf20Sopenharmony_ci iounmap(info->screen_base); 17108c2ecf20Sopenharmony_ci release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); 17118c2ecf20Sopenharmony_ci err_exit_mmio: 17128c2ecf20Sopenharmony_ci iounmap(default_par->v_regs); 17138c2ecf20Sopenharmony_ci release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); 17148c2ecf20Sopenharmony_ci err_exit_neither: 17158c2ecf20Sopenharmony_ci framebuffer_release(info); 17168c2ecf20Sopenharmony_ci err_exit_disable: 17178c2ecf20Sopenharmony_ci pci_disable_device(pdev); 17188c2ecf20Sopenharmony_ci return retval; 17198c2ecf20Sopenharmony_ci} 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci/** 17228c2ecf20Sopenharmony_ci * Device removal. 17238c2ecf20Sopenharmony_ci * 17248c2ecf20Sopenharmony_ci * Release all device resources. 17258c2ecf20Sopenharmony_ci * 17268c2ecf20Sopenharmony_ci * @param pdev PCI device to clean up. 17278c2ecf20Sopenharmony_ci */ 17288c2ecf20Sopenharmony_cistatic void pm2fb_remove(struct pci_dev *pdev) 17298c2ecf20Sopenharmony_ci{ 17308c2ecf20Sopenharmony_ci struct fb_info *info = pci_get_drvdata(pdev); 17318c2ecf20Sopenharmony_ci struct fb_fix_screeninfo *fix = &info->fix; 17328c2ecf20Sopenharmony_ci struct pm2fb_par *par = info->par; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci unregister_framebuffer(info); 17358c2ecf20Sopenharmony_ci arch_phys_wc_del(par->wc_cookie); 17368c2ecf20Sopenharmony_ci iounmap(info->screen_base); 17378c2ecf20Sopenharmony_ci release_mem_region(fix->smem_start, fix->smem_len); 17388c2ecf20Sopenharmony_ci iounmap(par->v_regs); 17398c2ecf20Sopenharmony_ci release_mem_region(fix->mmio_start, fix->mmio_len); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 17428c2ecf20Sopenharmony_ci kfree(info->pixmap.addr); 17438c2ecf20Sopenharmony_ci framebuffer_release(info); 17448c2ecf20Sopenharmony_ci pci_disable_device(pdev); 17458c2ecf20Sopenharmony_ci} 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_cistatic const struct pci_device_id pm2fb_id_table[] = { 17488c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, 17498c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 17508c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, 17518c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 17528c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, 17538c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 17548c2ecf20Sopenharmony_ci { 0, } 17558c2ecf20Sopenharmony_ci}; 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_cistatic struct pci_driver pm2fb_driver = { 17588c2ecf20Sopenharmony_ci .name = "pm2fb", 17598c2ecf20Sopenharmony_ci .id_table = pm2fb_id_table, 17608c2ecf20Sopenharmony_ci .probe = pm2fb_probe, 17618c2ecf20Sopenharmony_ci .remove = pm2fb_remove, 17628c2ecf20Sopenharmony_ci}; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pm2fb_id_table); 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci#ifndef MODULE 17688c2ecf20Sopenharmony_ci/** 17698c2ecf20Sopenharmony_ci * Parse user specified options. 17708c2ecf20Sopenharmony_ci * 17718c2ecf20Sopenharmony_ci * This is, comma-separated options following `video=pm2fb:'. 17728c2ecf20Sopenharmony_ci */ 17738c2ecf20Sopenharmony_cistatic int __init pm2fb_setup(char *options) 17748c2ecf20Sopenharmony_ci{ 17758c2ecf20Sopenharmony_ci char *this_opt; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci if (!options || !*options) 17788c2ecf20Sopenharmony_ci return 0; 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci while ((this_opt = strsep(&options, ",")) != NULL) { 17818c2ecf20Sopenharmony_ci if (!*this_opt) 17828c2ecf20Sopenharmony_ci continue; 17838c2ecf20Sopenharmony_ci if (!strcmp(this_opt, "lowhsync")) 17848c2ecf20Sopenharmony_ci lowhsync = 1; 17858c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "lowvsync")) 17868c2ecf20Sopenharmony_ci lowvsync = 1; 17878c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "hwcursor=", 9)) 17888c2ecf20Sopenharmony_ci hwcursor = simple_strtoul(this_opt + 9, NULL, 0); 17898c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "nomtrr", 6)) 17908c2ecf20Sopenharmony_ci nomtrr = 1; 17918c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "noaccel", 7)) 17928c2ecf20Sopenharmony_ci noaccel = 1; 17938c2ecf20Sopenharmony_ci else 17948c2ecf20Sopenharmony_ci mode_option = this_opt; 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci return 0; 17978c2ecf20Sopenharmony_ci} 17988c2ecf20Sopenharmony_ci#endif 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_cistatic int __init pm2fb_init(void) 18028c2ecf20Sopenharmony_ci{ 18038c2ecf20Sopenharmony_ci#ifndef MODULE 18048c2ecf20Sopenharmony_ci char *option = NULL; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci if (fb_get_options("pm2fb", &option)) 18078c2ecf20Sopenharmony_ci return -ENODEV; 18088c2ecf20Sopenharmony_ci pm2fb_setup(option); 18098c2ecf20Sopenharmony_ci#endif 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci return pci_register_driver(&pm2fb_driver); 18128c2ecf20Sopenharmony_ci} 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_cimodule_init(pm2fb_init); 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci#ifdef MODULE 18178c2ecf20Sopenharmony_ci/* 18188c2ecf20Sopenharmony_ci * Cleanup 18198c2ecf20Sopenharmony_ci */ 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_cistatic void __exit pm2fb_exit(void) 18228c2ecf20Sopenharmony_ci{ 18238c2ecf20Sopenharmony_ci pci_unregister_driver(&pm2fb_driver); 18248c2ecf20Sopenharmony_ci} 18258c2ecf20Sopenharmony_ci#endif 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci#ifdef MODULE 18288c2ecf20Sopenharmony_cimodule_exit(pm2fb_exit); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_cimodule_param(mode_option, charp, 0); 18318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); 18328c2ecf20Sopenharmony_cimodule_param_named(mode, mode_option, charp, 0); 18338c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)"); 18348c2ecf20Sopenharmony_cimodule_param(lowhsync, bool, 0); 18358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode"); 18368c2ecf20Sopenharmony_cimodule_param(lowvsync, bool, 0); 18378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode"); 18388c2ecf20Sopenharmony_cimodule_param(noaccel, bool, 0); 18398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(noaccel, "Disable acceleration"); 18408c2ecf20Sopenharmony_cimodule_param(hwcursor, int, 0644); 18418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(hwcursor, "Enable hardware cursor " 18428c2ecf20Sopenharmony_ci "(1=enable, 0=disable, default=1)"); 18438c2ecf20Sopenharmony_cimodule_param(nomtrr, bool, 0); 18448c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)"); 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jim Hague <jim.hague@acm.org>"); 18478c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Permedia2 framebuffer device driver"); 18488c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 18498c2ecf20Sopenharmony_ci#endif 1850