^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Permedia2 framebuffer driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * 2.5/2.6 driver:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2003 Jim Hague (jim.hague@acm.org)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * based on 2.4 driver:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * and additional input from James Simmon's port of Hannu Mallat's tdfx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * have no access to other pm2fb implementations. Sparc (and thus
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * hopefully other big-endian) devices now work, thanks to a lot of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * testing work by Ron Murray. I have no access to CVision hardware,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * and therefore for now I am omitting the CVision code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * Multiple boards support has been on the TODO list for ages.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * Don't expect this to change.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * License. See the file COPYING in the main directory of this archive for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <video/permedia2.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <video/cvisionppc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #error "The endianness of the target host has not been defined."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #if !defined(CONFIG_PCI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #error "Only generic PCI cards supported."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #undef PM2FB_MASTER_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #ifdef PM2FB_MASTER_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define DPRINTK(a, b...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) printk(KERN_DEBUG "pm2fb: %s: " a, __func__ , ## b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define DPRINTK(a, b...) no_printk(a, ##b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define PM2_PIXMAP_SIZE (1600 * 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * Driver data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static int hwcursor = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static char *mode_option;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * The XFree GLINT driver will (I think to implement hardware cursor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * support on TVP4010 and similar where there is no RAMDAC - see
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * comment in set_video) always request +ve sync regardless of what
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * the mode requires. This screws me because I have a Sun
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * fixed-frequency monitor which absolutely has to have -ve sync. So
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * these flags allow the user to specify that requests for +ve sync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * should be silently turned in -ve sync.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static bool lowhsync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static bool lowvsync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static bool noaccel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static bool nomtrr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * The hardware state of the graphics card that isn't part of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * screeninfo.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct pm2fb_par
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) pm2type_t type; /* Board type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) unsigned char __iomem *v_regs;/* virtual address of p_regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) u32 memclock; /* memclock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u32 video; /* video flags before blanking */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) u32 mem_config; /* MemConfig reg at probe */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) u32 mem_control; /* MemControl reg at probe */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) u32 boot_address; /* BootAddress reg at probe */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) u32 palette[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) int wc_cookie;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * if we don't use modedb.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static struct fb_fix_screeninfo pm2fb_fix = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .id = "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .type = FB_TYPE_PACKED_PIXELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .visual = FB_VISUAL_PSEUDOCOLOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .xpanstep = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) .ypanstep = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) .ywrapstep = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .accel = FB_ACCEL_3DLABS_PERMEDIA2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * Default video mode. In case the modedb doesn't work.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static const struct fb_var_screeninfo pm2fb_var = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) /* "640x480, 8 bpp @ 60 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .xres = 640,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .yres = 480,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .xres_virtual = 640,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) .yres_virtual = 480,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) .bits_per_pixel = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) .red = {0, 8, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .blue = {0, 8, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) .green = {0, 8, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .activate = FB_ACTIVATE_NOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) .height = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) .width = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) .accel_flags = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .pixclock = 39721,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .left_margin = 40,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) .right_margin = 24,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) .upper_margin = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) .lower_margin = 11,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) .hsync_len = 96,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) .vsync_len = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) .vmode = FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * Utility functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static inline u32 pm2_RD(struct pm2fb_par *p, s32 off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return fb_readl(p->v_regs + off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static inline void pm2_WR(struct pm2fb_par *p, s32 off, u32 v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) fb_writel(v, p->v_regs + off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static inline u32 pm2_RDAC_RD(struct pm2fb_par *p, s32 idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return pm2_RD(p, PM2R_RD_INDEXED_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static inline u32 pm2v_RDAC_RD(struct pm2fb_par *p, s32 idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return pm2_RD(p, PM2VR_RD_INDEXED_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static inline void pm2_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) pm2_WR(p, PM2R_RD_INDEXED_DATA, v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) static inline void pm2v_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) #define WAIT_FIFO(p, a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static inline void WAIT_FIFO(struct pm2fb_par *p, u32 a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) while (pm2_RD(p, PM2R_IN_FIFO_SPACE) < a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * partial products for the supported horizontal resolutions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) #define PACKPP(p0, p1, p2) (((p2) << 6) | ((p1) << 3) | (p0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static const struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) u16 width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) u16 pp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) } pp_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) { 32, PACKPP(1, 0, 0) }, { 64, PACKPP(1, 1, 0) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) { 96, PACKPP(1, 1, 1) }, { 128, PACKPP(2, 1, 1) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) { 160, PACKPP(2, 2, 1) }, { 192, PACKPP(2, 2, 2) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) { 224, PACKPP(3, 2, 1) }, { 256, PACKPP(3, 2, 2) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) { 288, PACKPP(3, 3, 1) }, { 320, PACKPP(3, 3, 2) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) { 384, PACKPP(3, 3, 3) }, { 416, PACKPP(4, 3, 1) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) { 448, PACKPP(4, 3, 2) }, { 512, PACKPP(4, 3, 3) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) { 544, PACKPP(4, 4, 1) }, { 576, PACKPP(4, 4, 2) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) { 640, PACKPP(4, 4, 3) }, { 768, PACKPP(4, 4, 4) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) { 800, PACKPP(5, 4, 1) }, { 832, PACKPP(5, 4, 2) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) { 896, PACKPP(5, 4, 3) }, { 1024, PACKPP(5, 4, 4) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) { 1056, PACKPP(5, 5, 1) }, { 1088, PACKPP(5, 5, 2) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) { 1152, PACKPP(5, 5, 3) }, { 1280, PACKPP(5, 5, 4) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) { 1536, PACKPP(5, 5, 5) }, { 1568, PACKPP(6, 5, 1) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) { 1600, PACKPP(6, 5, 2) }, { 1664, PACKPP(6, 5, 3) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) { 1792, PACKPP(6, 5, 4) }, { 2048, PACKPP(6, 5, 5) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) { 0, 0 } };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static u32 partprod(u32 xres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (pp_table[i].width == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) DPRINTK("invalid width %u\n", xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return pp_table[i].pp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) static u32 to3264(u32 timing, int bpp, int is64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) switch (bpp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) timing *= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) timing >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) timing >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (is64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) timing >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return timing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static void pm2_mnp(u32 clk, unsigned char *mm, unsigned char *nn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) unsigned char *pp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) unsigned char m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) unsigned char n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) unsigned char p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) u32 f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) s32 curr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) s32 delta = 100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) *mm = *nn = *pp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) for (n = 2; n < 15; n++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) for (m = 2; m; m++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) f = PM2_REFERENCE_CLOCK * m / n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) if (f >= 150000 && f <= 300000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) for (p = 0; p < 5; p++, f >>= 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) curr = (clk > f) ? clk - f : f - clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) if (curr < delta) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) delta = curr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) *mm = m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) *nn = n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) *pp = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) static void pm2v_mnp(u32 clk, unsigned char *mm, unsigned char *nn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) unsigned char *pp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) unsigned char m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) unsigned char n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) unsigned char p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) u32 f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) s32 delta = 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) *mm = *nn = *pp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) for (m = 1; m < 128; m++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) for (n = 2 * m + 1; n; n++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) for (p = 0; p < 2; p++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) f = (PM2_REFERENCE_CLOCK >> (p + 1)) * n / m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (clk > f - delta && clk < f + delta) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) delta = (clk > f) ? clk - f : f - clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) *mm = m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) *nn = n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) *pp = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) static void clear_palette(struct pm2fb_par *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) int i = 256;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) WAIT_FIFO(p, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) while (i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) WAIT_FIFO(p, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) static void reset_card(struct pm2fb_par *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (p->type == PM2_TYPE_PERMEDIA2V)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) pm2_WR(p, PM2R_RESET_STATUS, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) DPRINTK("FIFO disconnect enabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) pm2_WR(p, PM2R_FIFO_DISCON, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) /* Restore stashed memory config information from probe */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) WAIT_FIFO(p, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) pm2_WR(p, PM2R_MEM_CONTROL, p->mem_control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) pm2_WR(p, PM2R_BOOT_ADDRESS, p->boot_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) pm2_WR(p, PM2R_MEM_CONFIG, p->mem_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) static void reset_config(struct pm2fb_par *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) WAIT_FIFO(p, 53);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) ~(PM2F_VGA_ENABLE | PM2F_VGA_FIXED));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) pm2_WR(p, PM2R_FIFO_CONTROL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) pm2_WR(p, PM2R_APERTURE_ONE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) pm2_WR(p, PM2R_APERTURE_TWO, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) pm2_WR(p, PM2R_RASTERIZER_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) pm2_WR(p, PM2R_LB_READ_FORMAT, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) pm2_WR(p, PM2R_LB_READ_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) pm2_WR(p, PM2R_FB_WINDOW_BASE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) pm2_WR(p, PM2R_LB_WINDOW_BASE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) pm2_WR(p, PM2R_FB_READ_PIXEL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) pm2_WR(p, PM2R_DITHER_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) pm2_WR(p, PM2R_DEPTH_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) pm2_WR(p, PM2R_STENCIL_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) pm2_WR(p, PM2R_YUV_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) pm2_WR(p, PM2R_COLOR_DDA_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) pm2_WR(p, PM2R_FOG_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) pm2_WR(p, PM2R_STATISTICS_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) pm2_WR(p, PM2R_SCISSOR_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) pm2_WR(p, PM2R_RD_PIXEL_MASK, 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) switch (p->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) case PM2_TYPE_PERMEDIA2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) case PM2_TYPE_PERMEDIA2V:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) static void set_aperture(struct pm2fb_par *p, u32 depth)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) * The hardware is little-endian. When used in big-endian
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) * hosts, the on-chip aperture settings are used where
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) * possible to translate from host to card byte order.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) WAIT_FIFO(p, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) #ifdef __LITTLE_ENDIAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) switch (depth) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) case 24: /* RGB->BGR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) * We can't use the aperture to translate host to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) * card byte order here, so we switch to BGR mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) * in pm2fb_set_par().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) case 8: /* B->B */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) case 16: /* HL->LH */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_HALFWORDSWAP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) case 32: /* RGBA->ABGR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_BYTESWAP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) /* We don't use aperture two, so this may be superflous */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) pm2_WR(p, PM2R_APERTURE_TWO, PM2F_APERTURE_STANDARD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) static void set_color(struct pm2fb_par *p, unsigned char regno,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) unsigned char r, unsigned char g, unsigned char b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) WAIT_FIFO(p, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, regno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) pm2_WR(p, PM2R_RD_PALETTE_DATA, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) pm2_WR(p, PM2R_RD_PALETTE_DATA, g);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) pm2_WR(p, PM2R_RD_PALETTE_DATA, b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) static void set_memclock(struct pm2fb_par *par, u32 clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) unsigned char m, n, p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) switch (par->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) case PM2_TYPE_PERMEDIA2V:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) pm2v_mnp(clk/2, &m, &n, &p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) WAIT_FIFO(par, 12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) pm2v_RDAC_WR(par, PM2VI_RD_MCLK_FEEDBACK, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) rmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) for (i = 256; i; i--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) if (pm2v_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) case PM2_TYPE_PERMEDIA2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) pm2_mnp(clk, &m, &n, &p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) WAIT_FIFO(par, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_1, m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_2, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) rmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) for (i = 256; i; i--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) static void set_pixclock(struct pm2fb_par *par, u32 clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) unsigned char m, n, p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) switch (par->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) case PM2_TYPE_PERMEDIA2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) pm2_mnp(clk, &m, &n, &p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) WAIT_FIFO(par, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) rmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) for (i = 256; i; i--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) case PM2_TYPE_PERMEDIA2V:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) pm2v_mnp(clk/2, &m, &n, &p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) WAIT_FIFO(par, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) pm2v_RDAC_WR(par, PM2VI_RD_CLK0_PRESCALE, m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) pm2v_RDAC_WR(par, PM2VI_RD_CLK0_FEEDBACK, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) pm2v_RDAC_WR(par, PM2VI_RD_CLK0_POSTSCALE, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) static void set_video(struct pm2fb_par *p, u32 video)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) u32 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) u32 vsync = video;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) DPRINTK("video = 0x%x\n", video);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) * The hardware cursor needs +vsync to recognise vert retrace.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) * We may not be using the hardware cursor, but the X Glint
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) * driver may well. So always set +hsync/+vsync and then set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) * the RAMDAC to invert the sync if necessary.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) vsync &= ~(PM2F_HSYNC_MASK | PM2F_VSYNC_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) vsync |= PM2F_HSYNC_ACT_HIGH | PM2F_VSYNC_ACT_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) WAIT_FIFO(p, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) pm2_WR(p, PM2R_VIDEO_CONTROL, vsync);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) switch (p->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) case PM2_TYPE_PERMEDIA2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) tmp = PM2F_RD_PALETTE_WIDTH_8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) tmp |= 4; /* invert hsync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) tmp |= 8; /* invert vsync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) case PM2_TYPE_PERMEDIA2V:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) tmp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) tmp |= 1; /* invert hsync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) tmp |= 4; /* invert vsync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) pm2v_RDAC_WR(p, PM2VI_RD_SYNC_CONTROL, tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) * pm2fb_check_var - Optional function. Validates a var passed in.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * @var: frame buffer variable screen structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) * @info: frame buffer structure that represents a single frame buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) * Checks to see if the hardware supports the state requested by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) * var passed in.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) * Returns negative errno on error, or zero on success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) u32 lpitch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) if (var->bits_per_pixel != 8 && var->bits_per_pixel != 16 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) if (var->xres != var->xres_virtual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) DPRINTK("virtual x resolution != "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) "physical x resolution not supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) if (var->yres > var->yres_virtual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) DPRINTK("virtual y resolution < "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) "physical y resolution not possible\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) /* permedia cannot blit over 2048 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (var->yres_virtual > 2047) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) var->yres_virtual = 2047;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (var->xoffset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) DPRINTK("xoffset not supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) DPRINTK("interlace not supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) if (var->xres < 320 || var->xres > 1600) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) DPRINTK("width not supported: %u\n", var->xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (var->yres < 200 || var->yres > 1200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) DPRINTK("height not supported: %u\n", var->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if (lpitch * var->yres_virtual > info->fix.smem_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) DPRINTK("no memory for screen (%ux%ux%u)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) var->xres, var->yres_virtual, var->bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) DPRINTK("pixclock too high (%ldKHz)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) PICOS2KHZ(var->pixclock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) var->transp.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) var->red.offset = 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) var->red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) var->green.offset = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) var->green.length = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) var->transp.offset = 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) var->transp.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) var->red.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) var->green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) #ifdef __BIG_ENDIAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) var->red.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) var->blue.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) var->red.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) var->green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) var->height = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) var->width = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) var->accel_flags = 0; /* Can't mmap if this is on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) DPRINTK("Checking graphics mode at %dx%d depth %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) var->xres, var->yres, var->bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) * pm2fb_set_par - Alters the hardware state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) * @info: frame buffer structure that represents a single frame buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) * Using the fb_var_screeninfo in fb_info we set the resolution of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) * this particular framebuffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) static int pm2fb_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) struct pm2fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) u32 pixclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) u32 width = (info->var.xres_virtual + 7) & ~7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) u32 height = info->var.yres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) u32 depth = (info->var.bits_per_pixel + 7) & ~7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) u32 hsstart, hsend, hbend, htotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) u32 vsstart, vsend, vbend, vtotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) u32 stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) u32 base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) u32 video = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) u32 clrmode = PM2F_RD_COLOR_MODE_RGB | PM2F_RD_GUI_ACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) u32 txtmap = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) u32 pixsize = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) u32 clrformat = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) u32 misc = 1; /* 8-bit DAC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) u32 xres = (info->var.xres + 31) & ~31;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) int data64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) reset_card(par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) reset_config(par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) clear_palette(par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) if (par->memclock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) set_memclock(par, par->memclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) depth = (depth > 32) ? 32 : depth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) data64 = depth > 8 || par->type == PM2_TYPE_PERMEDIA2V;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) pixclock = PICOS2KHZ(info->var.pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (pixclock > PM2_MAX_PIXCLOCK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) DPRINTK("pixclock too high (%uKHz)\n", pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) hsstart = to3264(info->var.right_margin, depth, data64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) hsend = hsstart + to3264(info->var.hsync_len, depth, data64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) hbend = hsend + to3264(info->var.left_margin, depth, data64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) htotal = to3264(xres, depth, data64) + hbend - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) vsstart = (info->var.lower_margin)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) ? info->var.lower_margin - 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) : 0; /* FIXME! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) vsend = info->var.lower_margin + info->var.vsync_len - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) vbend = info->var.lower_margin + info->var.vsync_len +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) info->var.upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) vtotal = info->var.yres + vbend - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) stride = to3264(width, depth, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) if (data64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) video |= PM2F_DATA_64_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) if (lowhsync) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) DPRINTK("ignoring +hsync, using -hsync.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) video |= PM2F_HSYNC_ACT_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) video |= PM2F_HSYNC_ACT_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) video |= PM2F_HSYNC_ACT_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) if (lowvsync) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) DPRINTK("ignoring +vsync, using -vsync.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) video |= PM2F_VSYNC_ACT_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) video |= PM2F_VSYNC_ACT_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) video |= PM2F_VSYNC_ACT_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) DPRINTK("interlaced not supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) video |= PM2F_LINE_DOUBLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) video |= PM2F_VIDEO_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) par->video = video;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) info->fix.visual =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) (depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) info->fix.line_length = info->var.xres * depth / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) info->cmap.len = 256;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) * Settings calculated. Now write them out.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) if (par->type == PM2_TYPE_PERMEDIA2V) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) WAIT_FIFO(par, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) set_aperture(par, depth);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) WAIT_FIFO(par, 19);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) switch (depth) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) pm2_WR(par, PM2R_FB_READ_PIXEL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) clrformat = 0x2e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) pm2_WR(par, PM2R_FB_READ_PIXEL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB565;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) txtmap = PM2F_TEXTEL_SIZE_16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) pixsize = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) clrformat = 0x70;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) misc |= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) pm2_WR(par, PM2R_FB_READ_PIXEL, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGBA8888;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) txtmap = PM2F_TEXTEL_SIZE_32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) pixsize = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) clrformat = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) misc |= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) pm2_WR(par, PM2R_FB_READ_PIXEL, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB888;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) txtmap = PM2F_TEXTEL_SIZE_24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) pixsize = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) clrformat = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) misc |= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) pm2_WR(par, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) pm2_WR(par, PM2R_LB_READ_MODE, partprod(xres));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) pm2_WR(par, PM2R_TEXTURE_MAP_FORMAT, txtmap | partprod(xres));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) pm2_WR(par, PM2R_H_TOTAL, htotal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) pm2_WR(par, PM2R_HS_START, hsstart);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) pm2_WR(par, PM2R_HS_END, hsend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) pm2_WR(par, PM2R_HG_END, hbend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) pm2_WR(par, PM2R_HB_END, hbend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) pm2_WR(par, PM2R_V_TOTAL, vtotal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) pm2_WR(par, PM2R_VS_START, vsstart);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) pm2_WR(par, PM2R_VS_END, vsend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) pm2_WR(par, PM2R_VB_END, vbend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) pm2_WR(par, PM2R_SCREEN_STRIDE, stride);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) pm2_WR(par, PM2R_WINDOW_ORIGIN, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) pm2_WR(par, PM2R_SCREEN_SIZE, (height << 16) | width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) pm2_WR(par, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) pm2_WR(par, PM2R_SCREEN_BASE, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) set_video(par, video);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) WAIT_FIFO(par, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) switch (par->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) case PM2_TYPE_PERMEDIA2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, clrmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) (depth == 8) ? 0 : PM2F_COLOR_KEY_TEST_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) case PM2_TYPE_PERMEDIA2V:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) pm2v_RDAC_WR(par, PM2VI_RD_DAC_CONTROL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) pm2v_RDAC_WR(par, PM2VI_RD_COLOR_FORMAT, clrformat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) pm2v_RDAC_WR(par, PM2VI_RD_MISC_CONTROL, misc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) pm2v_RDAC_WR(par, PM2VI_RD_OVERLAY_KEY, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) set_pixclock(par, pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) DPRINTK("Setting graphics mode at %dx%d depth %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) info->var.xres, info->var.yres, info->var.bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) * pm2fb_setcolreg - Sets a color register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) * @regno: boolean, 0 copy local, 1 get_user() function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) * @red: frame buffer colormap structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) * @green: The green value which can be up to 16 bits wide
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) * @blue: The blue value which can be up to 16 bits wide.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) * @transp: If supported the alpha value which can be up to 16 bits wide.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) * @info: frame buffer info structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) * Set a single color register. The values supplied have a 16 bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) * magnitude which needs to be scaled in this function for the hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) * Pretty much a direct lift from tdfxfb.c.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) * Returns negative errno on error, or zero on success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) unsigned blue, unsigned transp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) struct pm2fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) if (regno >= info->cmap.len) /* no. of hw registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) * Program hardware... do anything you want with transp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) /* grayscale works only partially under directcolor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) /* grayscale = 0.30*R + 0.59*G + 0.11*B */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) if (info->var.grayscale)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) /* Directcolor:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) * var->{color}.offset contains start of bitfield
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) * var->{color}.length contains length of bitfield
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) * {hardwarespecific} contains width of DAC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) * cmap[X] is programmed to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) * (X << red.offset) | (X << green.offset) | (X << blue.offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) * RAMDAC[X] is programmed to (red, green, blue)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) * Pseudocolor:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) * uses offset = 0 && length = DAC register width.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) * var->{color}.offset is 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) * var->{color}.length contains width of DAC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) * cmap is not used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) * DAC[X] is programmed to (red, green, blue)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) * Truecolor:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) * does not use RAMDAC (usually has 3 of them).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) * var->{color}.offset contains start of bitfield
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) * var->{color}.length contains length of bitfield
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) * cmap is programmed to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) * (red << red.offset) | (green << green.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) * (blue << blue.offset) | (transp << transp.offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) * RAMDAC does not exist
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF -(val)) >> 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) switch (info->fix.visual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) case FB_VISUAL_TRUECOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) case FB_VISUAL_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) red = CNVT_TOHW(red, info->var.red.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) green = CNVT_TOHW(green, info->var.green.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) blue = CNVT_TOHW(blue, info->var.blue.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) transp = CNVT_TOHW(transp, info->var.transp.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) case FB_VISUAL_DIRECTCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) /* example here assumes 8 bit DAC. Might be different
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) * for your hardware */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) red = CNVT_TOHW(red, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) green = CNVT_TOHW(green, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) blue = CNVT_TOHW(blue, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) /* hey, there is bug in transp handling... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) transp = CNVT_TOHW(transp, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) #undef CNVT_TOHW
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) /* Truecolor has hardware independent palette */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) if (regno >= 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) v = (red << info->var.red.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) (green << info->var.green.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) (blue << info->var.blue.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) (transp << info->var.transp.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) par->palette[regno] = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) set_color(par, regno, red, green, blue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) * pm2fb_pan_display - Pans the display.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) * @var: frame buffer variable screen structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) * @info: frame buffer structure that represents a single frame buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) * Pan (or wrap, depending on the `vmode' field) the display using the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) * `xoffset' and `yoffset' fields of the `var' structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) * If the values don't fit, return -EINVAL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) * Returns negative errno on error, or zero on success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) static int pm2fb_pan_display(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) struct pm2fb_par *p = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) u32 base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) u32 depth = (info->var.bits_per_pixel + 7) & ~7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) u32 xres = (info->var.xres + 31) & ~31;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) depth = (depth > 32) ? 32 : depth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) base = to3264(var->yoffset * xres + var->xoffset, depth, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) WAIT_FIFO(p, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) pm2_WR(p, PM2R_SCREEN_BASE, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) * pm2fb_blank - Blanks the display.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) * @blank_mode: the blank mode we want.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) * @info: frame buffer structure that represents a single frame buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) * Blank the screen if blank_mode != 0, else unblank. Return 0 if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) * blanking succeeded, != 0 if un-/blanking failed due to e.g. a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) * video mode which doesn't support it. Implements VESA suspend
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) * and powerdown modes on hardware that supports disabling hsync/vsync:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) * blank_mode == 2: suspend vsync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) * blank_mode == 3: suspend hsync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) * blank_mode == 4: powerdown
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) * Returns negative errno on error, or zero on success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) static int pm2fb_blank(int blank_mode, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) struct pm2fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) u32 video = par->video;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) DPRINTK("blank_mode %d\n", blank_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) switch (blank_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) case FB_BLANK_UNBLANK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) /* Screen: On */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) video |= PM2F_VIDEO_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) case FB_BLANK_NORMAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) /* Screen: Off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) video &= ~PM2F_VIDEO_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) case FB_BLANK_VSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) /* VSync: Off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) case FB_BLANK_HSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) /* HSync: Off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) case FB_BLANK_POWERDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) /* HSync: Off, VSync: Off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK | PM2F_BLANK_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) set_video(par, video);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) static int pm2fb_sync(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) struct pm2fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) WAIT_FIFO(par, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) pm2_WR(par, PM2R_SYNC, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) static void pm2fb_fillrect(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) const struct fb_fillrect *region)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) struct pm2fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) struct fb_fillrect modded;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) int vxres, vyres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) ((u32 *)info->pseudo_palette)[region->color] : region->color;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) if (info->state != FBINFO_STATE_RUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) if ((info->flags & FBINFO_HWACCEL_DISABLED) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) region->rop != ROP_COPY ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) cfb_fillrect(info, region);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) vxres = info->var.xres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) vyres = info->var.yres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) memcpy(&modded, region, sizeof(struct fb_fillrect));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) if (!modded.width || !modded.height ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) modded.dx >= vxres || modded.dy >= vyres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) if (modded.dx + modded.width > vxres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) modded.width = vxres - modded.dx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) if (modded.dy + modded.height > vyres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) modded.height = vyres - modded.dy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) if (info->var.bits_per_pixel == 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) color |= color << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) if (info->var.bits_per_pixel <= 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) color |= color << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) WAIT_FIFO(par, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) if (info->var.bits_per_pixel != 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) WAIT_FIFO(par, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) pm2_WR(par, PM2R_FB_BLOCK_COLOR, color);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) pm2_WR(par, PM2R_RENDER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) PM2F_RENDER_RECTANGLE | PM2F_RENDER_FASTFILL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) WAIT_FIFO(par, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) pm2_WR(par, PM2R_COLOR_DDA_MODE, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) pm2_WR(par, PM2R_CONSTANT_COLOR, color);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) pm2_WR(par, PM2R_RENDER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) PM2F_RENDER_RECTANGLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) PM2F_INCREASE_X | PM2F_INCREASE_Y );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) static void pm2fb_copyarea(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) const struct fb_copyarea *area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) struct pm2fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) struct fb_copyarea modded;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) u32 vxres, vyres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) if (info->state != FBINFO_STATE_RUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) if (info->flags & FBINFO_HWACCEL_DISABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) cfb_copyarea(info, area);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) memcpy(&modded, area, sizeof(struct fb_copyarea));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) vxres = info->var.xres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) vyres = info->var.yres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) if (!modded.width || !modded.height ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) modded.sx >= vxres || modded.sy >= vyres ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) modded.dx >= vxres || modded.dy >= vyres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) if (modded.sx + modded.width > vxres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) modded.width = vxres - modded.sx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) if (modded.dx + modded.width > vxres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) modded.width = vxres - modded.dx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) if (modded.sy + modded.height > vyres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) modded.height = vyres - modded.sy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) if (modded.dy + modded.height > vyres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) modded.height = vyres - modded.dy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) WAIT_FIFO(par, 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) pm2_WR(par, PM2R_FB_SOURCE_DELTA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) ((modded.sy - modded.dy) & 0xfff) << 16 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) ((modded.sx - modded.dx) & 0xfff));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) (modded.dx < modded.sx ? PM2F_INCREASE_X : 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) (modded.dy < modded.sy ? PM2F_INCREASE_Y : 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) struct pm2fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) u32 height = image->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) u32 fgx, bgx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) const u32 *src = (const u32 *)image->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) u32 xres = (info->var.xres + 31) & ~31;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) int raster_mode = 1; /* invert bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) #ifdef __LITTLE_ENDIAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) raster_mode |= 3 << 7; /* reverse byte order */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) if (info->state != FBINFO_STATE_RUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) cfb_imageblit(info, image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) switch (info->fix.visual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) case FB_VISUAL_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) fgx = image->fg_color;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) bgx = image->bg_color;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) case FB_VISUAL_TRUECOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) fgx = par->palette[image->fg_color];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) bgx = par->palette[image->bg_color];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) if (info->var.bits_per_pixel == 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) fgx |= fgx << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) bgx |= bgx << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) if (info->var.bits_per_pixel <= 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) fgx |= fgx << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) bgx |= bgx << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) WAIT_FIFO(par, 13);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) pm2_WR(par, PM2R_SCISSOR_MIN_XY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) pm2_WR(par, PM2R_SCISSOR_MAX_XY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) (((image->dy + image->height) & 0x0fff) << 16) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) ((image->dx + image->width) & 0x0fff));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) pm2_WR(par, PM2R_SCISSOR_MODE, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) /* GXcopy & UNIT_ENABLE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) pm2_WR(par, PM2R_LOGICAL_OP_MODE, (0x3 << 1) | 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) pm2_WR(par, PM2R_RECTANGLE_ORIGIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) pm2_WR(par, PM2R_RECTANGLE_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) ((image->height & 0x0fff) << 16) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) ((image->width) & 0x0fff));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) if (info->var.bits_per_pixel == 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) pm2_WR(par, PM2R_COLOR_DDA_MODE, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) /* clear area */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) pm2_WR(par, PM2R_CONSTANT_COLOR, bgx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) pm2_WR(par, PM2R_RENDER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) PM2F_RENDER_RECTANGLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) PM2F_INCREASE_X | PM2F_INCREASE_Y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) /* BitMapPackEachScanline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode | (1 << 9));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) pm2_WR(par, PM2R_CONSTANT_COLOR, fgx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) pm2_WR(par, PM2R_RENDER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) PM2F_RENDER_RECTANGLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) PM2F_INCREASE_X | PM2F_INCREASE_Y |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) PM2F_RENDER_SYNC_ON_BIT_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) /* clear area */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) pm2_WR(par, PM2R_FB_BLOCK_COLOR, bgx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) pm2_WR(par, PM2R_RENDER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) PM2F_RENDER_RECTANGLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) PM2F_RENDER_FASTFILL |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) PM2F_INCREASE_X | PM2F_INCREASE_Y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) pm2_WR(par, PM2R_RENDER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) PM2F_RENDER_RECTANGLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) PM2F_INCREASE_X | PM2F_INCREASE_Y |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) PM2F_RENDER_FASTFILL |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) PM2F_RENDER_SYNC_ON_BIT_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) while (height--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) int width = ((image->width + 7) >> 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) + info->pixmap.scan_align - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) width >>= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) WAIT_FIFO(par, width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) while (width--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) pm2_WR(par, PM2R_BIT_MASK_PATTERN, *src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) src++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) WAIT_FIFO(par, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) pm2_WR(par, PM2R_RASTERIZER_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) pm2_WR(par, PM2R_SCISSOR_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) * Hardware cursor support.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) static const u8 cursor_bits_lookup[16] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) static int pm2vfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) struct pm2fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) u8 mode = PM2F_CURSORMODE_TYPE_X;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) int x = cursor->image.dx - info->var.xoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) int y = cursor->image.dy - info->var.yoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) if (cursor->enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) mode |= PM2F_CURSORMODE_CURSOR_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_MODE, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) if (!cursor->enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) x = 2047; /* push it outside display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0xf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_LOW, y & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HIGH, (y >> 8) & 0xf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) * If the cursor is not be changed this means either we want the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) * current cursor state (if enable is set) or we want to query what
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) * we can do with the cursor (if enable is not set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) if (!cursor->set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) if (cursor->set & FB_CUR_SETHOT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) cursor->hot.x & 0x3f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) cursor->hot.y & 0x3f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) if (cursor->set & FB_CUR_SETCMAP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) u32 fg_idx = cursor->image.fg_color;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) u32 bg_idx = cursor->image.bg_color;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) struct fb_cmap cmap = info->cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) /* the X11 driver says one should use these color registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) cmap.red[bg_idx] >> 8 );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) cmap.green[bg_idx] >> 8 );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) cmap.blue[bg_idx] >> 8 );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) cmap.red[fg_idx] >> 8 );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) cmap.green[fg_idx] >> 8 );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) cmap.blue[fg_idx] >> 8 );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) u8 *bitmap = (u8 *)cursor->image.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) u8 *mask = (u8 *)cursor->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) int pos = PM2VI_RD_CURSOR_PATTERN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) for (i = 0; i < cursor->image.height; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) int j = (cursor->image.width + 7) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) int k = 8 - j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) for (; j > 0; j--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) u8 data = *bitmap ^ *mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) if (cursor->rop == ROP_COPY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) data = *mask & *bitmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) /* Upper 4 bits of bitmap data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) pm2v_RDAC_WR(par, pos++,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) cursor_bits_lookup[data >> 4] |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) (cursor_bits_lookup[*mask >> 4] << 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) /* Lower 4 bits of bitmap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) pm2v_RDAC_WR(par, pos++,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) cursor_bits_lookup[data & 0xf] |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) (cursor_bits_lookup[*mask & 0xf] << 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) bitmap++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) mask++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) for (; k > 0; k--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) pm2v_RDAC_WR(par, pos++, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) pm2v_RDAC_WR(par, pos++, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) while (pos < (1024 + PM2VI_RD_CURSOR_PATTERN)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) pm2v_RDAC_WR(par, pos++, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) static int pm2fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) struct pm2fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) u8 mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) if (!hwcursor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) return -EINVAL; /* just to force soft_cursor() call */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) /* Too large of a cursor or wrong bpp :-( */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) if (cursor->image.width > 64 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) cursor->image.height > 64 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) cursor->image.depth > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) if (par->type == PM2_TYPE_PERMEDIA2V)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) return pm2vfb_cursor(info, cursor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) mode = 0x40;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) if (cursor->enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) mode = 0x43;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) pm2_RDAC_WR(par, PM2I_RD_CURSOR_CONTROL, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) * If the cursor is not be changed this means either we want the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) * current cursor state (if enable is set) or we want to query what
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) * we can do with the cursor (if enable is not set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) if (!cursor->set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) if (cursor->set & FB_CUR_SETPOS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) int x = cursor->image.dx - info->var.xoffset + 63;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) int y = cursor->image.dy - info->var.yoffset + 63;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) WAIT_FIFO(par, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) pm2_WR(par, PM2R_RD_CURSOR_X_LSB, x & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) pm2_WR(par, PM2R_RD_CURSOR_X_MSB, (x >> 8) & 0x7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) pm2_WR(par, PM2R_RD_CURSOR_Y_LSB, y & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) pm2_WR(par, PM2R_RD_CURSOR_Y_MSB, (y >> 8) & 0x7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) if (cursor->set & FB_CUR_SETCMAP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) u32 fg_idx = cursor->image.fg_color;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) u32 bg_idx = cursor->image.bg_color;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) WAIT_FIFO(par, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) pm2_WR(par, PM2R_RD_CURSOR_COLOR_ADDRESS, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) info->cmap.red[bg_idx] >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) info->cmap.green[bg_idx] >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) info->cmap.blue[bg_idx] >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) info->cmap.red[fg_idx] >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) info->cmap.green[fg_idx] >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) info->cmap.blue[fg_idx] >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) u8 *bitmap = (u8 *)cursor->image.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) u8 *mask = (u8 *)cursor->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) WAIT_FIFO(par, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) pm2_WR(par, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) for (i = 0; i < cursor->image.height; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) int j = (cursor->image.width + 7) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) int k = 8 - j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) WAIT_FIFO(par, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) for (; j > 0; j--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) u8 data = *bitmap ^ *mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) if (cursor->rop == ROP_COPY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) data = *mask & *bitmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) /* bitmap data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) pm2_WR(par, PM2R_RD_CURSOR_DATA, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) bitmap++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) mask++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) for (; k > 0; k--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) for (; i < 64; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) int j = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) WAIT_FIFO(par, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) while (j-- > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) mask = (u8 *)cursor->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) for (i = 0; i < cursor->image.height; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) int j = (cursor->image.width + 7) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) int k = 8 - j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) WAIT_FIFO(par, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) for (; j > 0; j--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) /* mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) pm2_WR(par, PM2R_RD_CURSOR_DATA, *mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) mask++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) for (; k > 0; k--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) for (; i < 64; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) int j = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) WAIT_FIFO(par, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) while (j-- > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) /* ------------ Hardware Independent Functions ------------ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) * Frame buffer operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) static const struct fb_ops pm2fb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) .fb_check_var = pm2fb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) .fb_set_par = pm2fb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) .fb_setcolreg = pm2fb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) .fb_blank = pm2fb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) .fb_pan_display = pm2fb_pan_display,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) .fb_fillrect = pm2fb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) .fb_copyarea = pm2fb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) .fb_imageblit = pm2fb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) .fb_sync = pm2fb_sync,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) .fb_cursor = pm2fb_cursor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) * PCI stuff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) * Device initialisation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) * Initialise and allocate resource for PCI device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) * @param pdev PCI device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) * @param id PCI device ID.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) static int pm2fb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) struct pm2fb_par *default_par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) int retval = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) err = pci_enable_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) info = framebuffer_alloc(sizeof(struct pm2fb_par), &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) default_par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) switch (pdev->device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) case PCI_DEVICE_ID_TI_TVP4020:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) strcpy(pm2fb_fix.id, "TVP4020");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) default_par->type = PM2_TYPE_PERMEDIA2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) case PCI_DEVICE_ID_3DLABS_PERMEDIA2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) strcpy(pm2fb_fix.id, "Permedia2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) default_par->type = PM2_TYPE_PERMEDIA2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) case PCI_DEVICE_ID_3DLABS_PERMEDIA2V:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) strcpy(pm2fb_fix.id, "Permedia2v");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) default_par->type = PM2_TYPE_PERMEDIA2V;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) pm2fb_fix.mmio_start = pci_resource_start(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) pm2fb_fix.mmio_len = PM2_REGS_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) #if defined(__BIG_ENDIAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) * PM2 has a 64k register file, mapped twice in 128k. Lower
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) * map is little-endian, upper map is big-endian.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) pm2fb_fix.mmio_start += PM2_REGS_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) DPRINTK("Adjusting register base for big-endian.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) /* Registers - request region and map it. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) if (!request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) "pm2fb regbase")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) printk(KERN_WARNING "pm2fb: Can't reserve regbase.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) goto err_exit_neither;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) default_par->v_regs =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) ioremap(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) if (!default_par->v_regs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) printk(KERN_WARNING "pm2fb: Can't remap %s register area.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) pm2fb_fix.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) goto err_exit_neither;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) /* Stash away memory register info for use when we reset the board */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) default_par->mem_control = pm2_RD(default_par, PM2R_MEM_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) default_par->boot_address = pm2_RD(default_par, PM2R_BOOT_ADDRESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) default_par->mem_config = pm2_RD(default_par, PM2R_MEM_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) DPRINTK("MemControl 0x%x BootAddress 0x%x MemConfig 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) default_par->mem_control, default_par->boot_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) default_par->mem_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) if (default_par->mem_control == 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) default_par->boot_address == 0x31 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) default_par->mem_config == 0x259fffff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) default_par->memclock = CVPPC_MEMCLOCK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) default_par->mem_control = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) default_par->boot_address = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) default_par->mem_config = 0xe6002021;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) if (pdev->subsystem_vendor == 0x1048 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) pdev->subsystem_device == 0x0a31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) DPRINTK("subsystem_vendor: %04x, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) "subsystem_device: %04x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) pdev->subsystem_vendor, pdev->subsystem_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) DPRINTK("We have not been initialized by VGA BIOS and "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) "are running on an Elsa Winner 2000 Office\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) DPRINTK("Initializing card timings manually...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) default_par->memclock = 100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) if (pdev->subsystem_vendor == 0x3d3d &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) pdev->subsystem_device == 0x0100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) DPRINTK("subsystem_vendor: %04x, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) "subsystem_device: %04x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) pdev->subsystem_vendor, pdev->subsystem_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) DPRINTK("We have not been initialized by VGA BIOS and "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) "are running on an 3dlabs reference board\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) DPRINTK("Initializing card timings manually...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) default_par->memclock = 74894;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) /* Now work out how big lfb is going to be. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) switch (default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) case PM2F_MEM_BANKS_1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) pm2fb_fix.smem_len = 0x200000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) case PM2F_MEM_BANKS_2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) pm2fb_fix.smem_len = 0x400000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) case PM2F_MEM_BANKS_3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) pm2fb_fix.smem_len = 0x600000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) case PM2F_MEM_BANKS_4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) pm2fb_fix.smem_len = 0x800000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) pm2fb_fix.smem_start = pci_resource_start(pdev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) /* Linear frame buffer - request region and map it. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) if (!request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) "pm2fb smem")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) printk(KERN_WARNING "pm2fb: Can't reserve smem.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) goto err_exit_mmio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) info->screen_base =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) ioremap_wc(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) if (!info->screen_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) goto err_exit_mmio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) if (!nomtrr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) default_par->wc_cookie = arch_phys_wc_add(pm2fb_fix.smem_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) pm2fb_fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) info->fbops = &pm2fb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) info->fix = pm2fb_fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) info->pseudo_palette = default_par->palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) info->flags = FBINFO_DEFAULT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) FBINFO_HWACCEL_YPAN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) FBINFO_HWACCEL_COPYAREA |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) FBINFO_HWACCEL_IMAGEBLIT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) FBINFO_HWACCEL_FILLRECT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) info->pixmap.addr = kmalloc(PM2_PIXMAP_SIZE, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) if (!info->pixmap.addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) goto err_exit_pixmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) info->pixmap.size = PM2_PIXMAP_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) info->pixmap.buf_align = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) info->pixmap.scan_align = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) info->pixmap.access_align = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) info->pixmap.flags = FB_PIXMAP_SYSTEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) if (noaccel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) printk(KERN_DEBUG "disabling acceleration\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) info->flags |= FBINFO_HWACCEL_DISABLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) info->pixmap.scan_align = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) if (!mode_option)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) mode_option = "640x480@60";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) if (!err || err == 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) info->var = pm2fb_var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) retval = fb_alloc_cmap(&info->cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) if (retval < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) goto err_exit_both;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) retval = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) if (retval < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) goto err_exit_all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) fb_info(info, "%s frame buffer device, memory = %dK\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) info->fix.id, pm2fb_fix.smem_len / 1024);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) * Our driver data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) pci_set_drvdata(pdev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) err_exit_all:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) err_exit_both:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) kfree(info->pixmap.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) err_exit_pixmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) iounmap(info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) err_exit_mmio:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) iounmap(default_par->v_regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) err_exit_neither:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) * Device removal.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) * Release all device resources.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) * @param pdev PCI device to clean up.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) static void pm2fb_remove(struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) struct fb_info *info = pci_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) struct fb_fix_screeninfo *fix = &info->fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) struct pm2fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) arch_phys_wc_del(par->wc_cookie);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727) iounmap(info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) release_mem_region(fix->smem_start, fix->smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) iounmap(par->v_regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) release_mem_region(fix->mmio_start, fix->mmio_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) kfree(info->pixmap.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) static const struct pci_device_id pm2fb_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) { 0, }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) static struct pci_driver pm2fb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) .name = "pm2fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) .id_table = pm2fb_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) .probe = pm2fb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) .remove = pm2fb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) MODULE_DEVICE_TABLE(pci, pm2fb_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) #ifndef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) * Parse user specified options.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) * This is, comma-separated options following `video=pm2fb:'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) static int __init pm2fb_setup(char *options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) char *this_opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) if (!options || !*options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) while ((this_opt = strsep(&options, ",")) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) if (!*this_opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) if (!strcmp(this_opt, "lowhsync"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) lowhsync = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) else if (!strcmp(this_opt, "lowvsync"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) lowvsync = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) else if (!strncmp(this_opt, "hwcursor=", 9))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) hwcursor = simple_strtoul(this_opt + 9, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) else if (!strncmp(this_opt, "nomtrr", 6))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780) nomtrr = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) else if (!strncmp(this_opt, "noaccel", 7))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) noaccel = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784) mode_option = this_opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) static int __init pm2fb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) #ifndef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794) char *option = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796) if (fb_get_options("pm2fb", &option))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) pm2fb_setup(option);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) return pci_register_driver(&pm2fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) module_init(pm2fb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) #ifdef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) * Cleanup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) static void __exit pm2fb_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) pci_unregister_driver(&pm2fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817) #ifdef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) module_exit(pm2fb_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) module_param(mode_option, charp, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821) MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) module_param_named(mode, mode_option, charp, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) module_param(lowhsync, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825) MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) module_param(lowvsync, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828) module_param(noaccel, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829) MODULE_PARM_DESC(noaccel, "Disable acceleration");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830) module_param(hwcursor, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832) "(1=enable, 0=disable, default=1)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) module_param(nomtrr, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) MODULE_AUTHOR("Jim Hague <jim.hague@acm.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) MODULE_DESCRIPTION("Permedia2 framebuffer device driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) #endif