1 /* 2 * Silicon Motion SM7XX frame buffer device 3 * 4 * Copyright (C) 2006 Silicon Motion Technology Corp. 5 * Authors: Ge Wang, gewang@siliconmotion.com 6 * Boyod boyod.yang@siliconmotion.com.cn 7 * 8 * Copyright (C) 2009 Lemote, Inc. 9 * Author: Wu Zhangjin, wuzhangjin@gmail.com 10 * 11 * Copyright (C) 2011 Igalia, S.L. 12 * Author: Javier M. Mellid <jmunhoz@igalia.com> 13 * 14 * This file is subject to the terms and conditions of the GNU General Public 15 * License. See the file COPYING in the main directory of this archive for 16 * more details. 17 * 18 * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips 19 */ 20 21 #include <linux/aperture.h> 22 #include <linux/io.h> 23 #include <linux/fb.h> 24 #include <linux/pci.h> 25 #include <linux/init.h> 26 #include <linux/slab.h> 27 #include <linux/uaccess.h> 28 #include <linux/module.h> 29 #include <linux/console.h> 30 #include <linux/screen_info.h> 31 32 #include <linux/pm.h> 33 34 #include "sm712.h" 35 36 /* 37 * Private structure 38 */ 39 struct smtcfb_info { 40 struct pci_dev *pdev; 41 struct fb_info *fb; 42 u16 chip_id; 43 u8 chip_rev_id; 44 45 void __iomem *lfb; /* linear frame buffer */ 46 void __iomem *dp_regs; /* drawing processor control regs */ 47 void __iomem *vp_regs; /* video processor control regs */ 48 void __iomem *cp_regs; /* capture processor control regs */ 49 void __iomem *mmio; /* memory map IO port */ 50 51 u_int width; 52 u_int height; 53 u_int hz; 54 55 u32 colreg[17]; 56 }; 57 58 void __iomem *smtc_regbaseaddress; /* Memory Map IO starting address */ 59 60 static const struct fb_var_screeninfo smtcfb_var = { 61 .xres = 1024, 62 .yres = 600, 63 .xres_virtual = 1024, 64 .yres_virtual = 600, 65 .bits_per_pixel = 16, 66 .red = {16, 8, 0}, 67 .green = {8, 8, 0}, 68 .blue = {0, 8, 0}, 69 .activate = FB_ACTIVATE_NOW, 70 .height = -1, 71 .width = -1, 72 .vmode = FB_VMODE_NONINTERLACED, 73 .nonstd = 0, 74 .accel_flags = FB_ACCELF_TEXT, 75 }; 76 77 static struct fb_fix_screeninfo smtcfb_fix = { 78 .id = "smXXXfb", 79 .type = FB_TYPE_PACKED_PIXELS, 80 .visual = FB_VISUAL_TRUECOLOR, 81 .line_length = 800 * 3, 82 .accel = FB_ACCEL_SMI_LYNX, 83 .type_aux = 0, 84 .xpanstep = 0, 85 .ypanstep = 0, 86 .ywrapstep = 0, 87 }; 88 89 struct vesa_mode { 90 char index[6]; 91 u16 lfb_width; 92 u16 lfb_height; 93 u16 lfb_depth; 94 }; 95 96 static const struct vesa_mode vesa_mode_table[] = { 97 {"0x301", 640, 480, 8}, 98 {"0x303", 800, 600, 8}, 99 {"0x305", 1024, 768, 8}, 100 {"0x307", 1280, 1024, 8}, 101 102 {"0x311", 640, 480, 16}, 103 {"0x314", 800, 600, 16}, 104 {"0x317", 1024, 768, 16}, 105 {"0x31A", 1280, 1024, 16}, 106 107 {"0x312", 640, 480, 24}, 108 {"0x315", 800, 600, 24}, 109 {"0x318", 1024, 768, 24}, 110 {"0x31B", 1280, 1024, 24}, 111 }; 112 113 /********************************************************************** 114 SM712 Mode table. 115 **********************************************************************/ 116 static const struct modeinit vgamode[] = { 117 { 118 /* mode#0: 640 x 480 16Bpp 60Hz */ 119 640, 480, 16, 60, 120 /* Init_MISC */ 121 0xE3, 122 { /* Init_SR0_SR4 */ 123 0x03, 0x01, 0x0F, 0x00, 0x0E, 124 }, 125 { /* Init_SR10_SR24 */ 126 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, 127 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 128 0xC4, 0x30, 0x02, 0x01, 0x01, 129 }, 130 { /* Init_SR30_SR75 */ 131 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, 132 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, 133 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, 134 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, 135 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, 136 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, 137 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, 138 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, 139 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, 140 }, 141 { /* Init_SR80_SR93 */ 142 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, 143 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, 144 0x00, 0x00, 0x00, 0x00, 145 }, 146 { /* Init_SRA0_SRAF */ 147 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, 148 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, 149 }, 150 { /* Init_GR00_GR08 */ 151 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 152 0xFF, 153 }, 154 { /* Init_AR00_AR14 */ 155 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 156 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 157 0x41, 0x00, 0x0F, 0x00, 0x00, 158 }, 159 { /* Init_CR00_CR18 */ 160 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, 161 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 162 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, 163 0xFF, 164 }, 165 { /* Init_CR30_CR4D */ 166 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, 167 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, 168 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, 169 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, 170 }, 171 { /* Init_CR90_CRA7 */ 172 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, 173 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, 174 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 175 }, 176 }, 177 { 178 /* mode#1: 640 x 480 24Bpp 60Hz */ 179 640, 480, 24, 60, 180 /* Init_MISC */ 181 0xE3, 182 { /* Init_SR0_SR4 */ 183 0x03, 0x01, 0x0F, 0x00, 0x0E, 184 }, 185 { /* Init_SR10_SR24 */ 186 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, 187 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 188 0xC4, 0x30, 0x02, 0x01, 0x01, 189 }, 190 { /* Init_SR30_SR75 */ 191 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, 192 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, 193 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, 194 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, 195 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, 196 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, 197 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, 198 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, 199 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, 200 }, 201 { /* Init_SR80_SR93 */ 202 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, 203 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, 204 0x00, 0x00, 0x00, 0x00, 205 }, 206 { /* Init_SRA0_SRAF */ 207 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, 208 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, 209 }, 210 { /* Init_GR00_GR08 */ 211 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 212 0xFF, 213 }, 214 { /* Init_AR00_AR14 */ 215 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 216 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 217 0x41, 0x00, 0x0F, 0x00, 0x00, 218 }, 219 { /* Init_CR00_CR18 */ 220 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, 221 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 222 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, 223 0xFF, 224 }, 225 { /* Init_CR30_CR4D */ 226 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, 227 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, 228 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, 229 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, 230 }, 231 { /* Init_CR90_CRA7 */ 232 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, 233 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, 234 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 235 }, 236 }, 237 { 238 /* mode#0: 640 x 480 32Bpp 60Hz */ 239 640, 480, 32, 60, 240 /* Init_MISC */ 241 0xE3, 242 { /* Init_SR0_SR4 */ 243 0x03, 0x01, 0x0F, 0x00, 0x0E, 244 }, 245 { /* Init_SR10_SR24 */ 246 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, 247 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 248 0xC4, 0x30, 0x02, 0x01, 0x01, 249 }, 250 { /* Init_SR30_SR75 */ 251 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, 252 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, 253 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, 254 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, 255 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, 256 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, 257 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, 258 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, 259 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, 260 }, 261 { /* Init_SR80_SR93 */ 262 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, 263 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, 264 0x00, 0x00, 0x00, 0x00, 265 }, 266 { /* Init_SRA0_SRAF */ 267 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, 268 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, 269 }, 270 { /* Init_GR00_GR08 */ 271 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 272 0xFF, 273 }, 274 { /* Init_AR00_AR14 */ 275 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 276 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 277 0x41, 0x00, 0x0F, 0x00, 0x00, 278 }, 279 { /* Init_CR00_CR18 */ 280 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, 281 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 282 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, 283 0xFF, 284 }, 285 { /* Init_CR30_CR4D */ 286 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, 287 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, 288 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, 289 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, 290 }, 291 { /* Init_CR90_CRA7 */ 292 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, 293 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, 294 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 295 }, 296 }, 297 298 { /* mode#2: 800 x 600 16Bpp 60Hz */ 299 800, 600, 16, 60, 300 /* Init_MISC */ 301 0x2B, 302 { /* Init_SR0_SR4 */ 303 0x03, 0x01, 0x0F, 0x03, 0x0E, 304 }, 305 { /* Init_SR10_SR24 */ 306 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, 307 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 308 0xC4, 0x30, 0x02, 0x01, 0x01, 309 }, 310 { /* Init_SR30_SR75 */ 311 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, 312 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, 313 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, 314 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, 315 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, 316 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, 317 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, 318 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, 319 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, 320 }, 321 { /* Init_SR80_SR93 */ 322 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, 323 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, 324 0x00, 0x00, 0x00, 0x00, 325 }, 326 { /* Init_SRA0_SRAF */ 327 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, 328 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, 329 }, 330 { /* Init_GR00_GR08 */ 331 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 332 0xFF, 333 }, 334 { /* Init_AR00_AR14 */ 335 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 336 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 337 0x41, 0x00, 0x0F, 0x00, 0x00, 338 }, 339 { /* Init_CR00_CR18 */ 340 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, 341 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 342 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, 343 0xFF, 344 }, 345 { /* Init_CR30_CR4D */ 346 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, 347 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, 348 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, 349 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, 350 }, 351 { /* Init_CR90_CRA7 */ 352 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, 353 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, 354 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, 355 }, 356 }, 357 { /* mode#3: 800 x 600 24Bpp 60Hz */ 358 800, 600, 24, 60, 359 0x2B, 360 { /* Init_SR0_SR4 */ 361 0x03, 0x01, 0x0F, 0x03, 0x0E, 362 }, 363 { /* Init_SR10_SR24 */ 364 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, 365 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 366 0xC4, 0x30, 0x02, 0x01, 0x01, 367 }, 368 { /* Init_SR30_SR75 */ 369 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36, 370 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF, 371 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, 372 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36, 373 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, 374 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36, 375 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, 376 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, 377 0x02, 0x45, 0x30, 0x30, 0x40, 0x20, 378 }, 379 { /* Init_SR80_SR93 */ 380 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36, 381 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36, 382 0x00, 0x00, 0x00, 0x00, 383 }, 384 { /* Init_SRA0_SRAF */ 385 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, 386 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, 387 }, 388 { /* Init_GR00_GR08 */ 389 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 390 0xFF, 391 }, 392 { /* Init_AR00_AR14 */ 393 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 394 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 395 0x41, 0x00, 0x0F, 0x00, 0x00, 396 }, 397 { /* Init_CR00_CR18 */ 398 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, 399 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 400 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, 401 0xFF, 402 }, 403 { /* Init_CR30_CR4D */ 404 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, 405 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, 406 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, 407 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, 408 }, 409 { /* Init_CR90_CRA7 */ 410 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, 411 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, 412 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, 413 }, 414 }, 415 { /* mode#7: 800 x 600 32Bpp 60Hz */ 416 800, 600, 32, 60, 417 /* Init_MISC */ 418 0x2B, 419 { /* Init_SR0_SR4 */ 420 0x03, 0x01, 0x0F, 0x03, 0x0E, 421 }, 422 { /* Init_SR10_SR24 */ 423 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, 424 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 425 0xC4, 0x30, 0x02, 0x01, 0x01, 426 }, 427 { /* Init_SR30_SR75 */ 428 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, 429 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, 430 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, 431 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, 432 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, 433 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, 434 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, 435 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, 436 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, 437 }, 438 { /* Init_SR80_SR93 */ 439 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, 440 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, 441 0x00, 0x00, 0x00, 0x00, 442 }, 443 { /* Init_SRA0_SRAF */ 444 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, 445 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, 446 }, 447 { /* Init_GR00_GR08 */ 448 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 449 0xFF, 450 }, 451 { /* Init_AR00_AR14 */ 452 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 453 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 454 0x41, 0x00, 0x0F, 0x00, 0x00, 455 }, 456 { /* Init_CR00_CR18 */ 457 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, 458 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 459 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, 460 0xFF, 461 }, 462 { /* Init_CR30_CR4D */ 463 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, 464 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, 465 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, 466 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, 467 }, 468 { /* Init_CR90_CRA7 */ 469 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, 470 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, 471 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, 472 }, 473 }, 474 /* We use 1024x768 table to light 1024x600 panel for lemote */ 475 { /* mode#4: 1024 x 600 16Bpp 60Hz */ 476 1024, 600, 16, 60, 477 /* Init_MISC */ 478 0xEB, 479 { /* Init_SR0_SR4 */ 480 0x03, 0x01, 0x0F, 0x00, 0x0E, 481 }, 482 { /* Init_SR10_SR24 */ 483 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20, 484 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 485 0xC4, 0x30, 0x02, 0x00, 0x01, 486 }, 487 { /* Init_SR30_SR75 */ 488 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22, 489 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF, 490 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, 491 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22, 492 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, 493 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22, 494 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, 495 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02, 496 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20, 497 }, 498 { /* Init_SR80_SR93 */ 499 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, 500 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, 501 0x00, 0x00, 0x00, 0x00, 502 }, 503 { /* Init_SRA0_SRAF */ 504 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, 505 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, 506 }, 507 { /* Init_GR00_GR08 */ 508 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 509 0xFF, 510 }, 511 { /* Init_AR00_AR14 */ 512 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 513 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 514 0x41, 0x00, 0x0F, 0x00, 0x00, 515 }, 516 { /* Init_CR00_CR18 */ 517 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, 518 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 519 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, 520 0xFF, 521 }, 522 { /* Init_CR30_CR4D */ 523 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, 524 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, 525 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00, 526 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57, 527 }, 528 { /* Init_CR90_CRA7 */ 529 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, 530 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, 531 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 532 }, 533 }, 534 { /* 1024 x 768 16Bpp 60Hz */ 535 1024, 768, 16, 60, 536 /* Init_MISC */ 537 0xEB, 538 { /* Init_SR0_SR4 */ 539 0x03, 0x01, 0x0F, 0x03, 0x0E, 540 }, 541 { /* Init_SR10_SR24 */ 542 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, 543 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 544 0xC4, 0x30, 0x02, 0x01, 0x01, 545 }, 546 { /* Init_SR30_SR75 */ 547 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, 548 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, 549 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, 550 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, 551 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, 552 0x0F, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, 553 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, 554 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, 555 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, 556 }, 557 { /* Init_SR80_SR93 */ 558 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, 559 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, 560 0x00, 0x00, 0x00, 0x00, 561 }, 562 { /* Init_SRA0_SRAF */ 563 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, 564 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, 565 }, 566 { /* Init_GR00_GR08 */ 567 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 568 0xFF, 569 }, 570 { /* Init_AR00_AR14 */ 571 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 572 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 573 0x41, 0x00, 0x0F, 0x00, 0x00, 574 }, 575 { /* Init_CR00_CR18 */ 576 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, 577 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 578 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, 579 0xFF, 580 }, 581 { /* Init_CR30_CR4D */ 582 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, 583 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, 584 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, 585 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, 586 }, 587 { /* Init_CR90_CRA7 */ 588 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, 589 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, 590 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 591 }, 592 }, 593 { /* mode#5: 1024 x 768 24Bpp 60Hz */ 594 1024, 768, 24, 60, 595 /* Init_MISC */ 596 0xEB, 597 { /* Init_SR0_SR4 */ 598 0x03, 0x01, 0x0F, 0x03, 0x0E, 599 }, 600 { /* Init_SR10_SR24 */ 601 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, 602 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 603 0xC4, 0x30, 0x02, 0x01, 0x01, 604 }, 605 { /* Init_SR30_SR75 */ 606 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, 607 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, 608 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, 609 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, 610 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, 611 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, 612 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, 613 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, 614 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, 615 }, 616 { /* Init_SR80_SR93 */ 617 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, 618 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, 619 0x00, 0x00, 0x00, 0x00, 620 }, 621 { /* Init_SRA0_SRAF */ 622 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, 623 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, 624 }, 625 { /* Init_GR00_GR08 */ 626 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 627 0xFF, 628 }, 629 { /* Init_AR00_AR14 */ 630 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 631 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 632 0x41, 0x00, 0x0F, 0x00, 0x00, 633 }, 634 { /* Init_CR00_CR18 */ 635 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, 636 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 637 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, 638 0xFF, 639 }, 640 { /* Init_CR30_CR4D */ 641 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, 642 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, 643 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, 644 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, 645 }, 646 { /* Init_CR90_CRA7 */ 647 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, 648 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, 649 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 650 }, 651 }, 652 { /* mode#4: 1024 x 768 32Bpp 60Hz */ 653 1024, 768, 32, 60, 654 /* Init_MISC */ 655 0xEB, 656 { /* Init_SR0_SR4 */ 657 0x03, 0x01, 0x0F, 0x03, 0x0E, 658 }, 659 { /* Init_SR10_SR24 */ 660 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, 661 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 662 0xC4, 0x32, 0x02, 0x01, 0x01, 663 }, 664 { /* Init_SR30_SR75 */ 665 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, 666 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, 667 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, 668 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, 669 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, 670 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, 671 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, 672 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, 673 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, 674 }, 675 { /* Init_SR80_SR93 */ 676 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, 677 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, 678 0x00, 0x00, 0x00, 0x00, 679 }, 680 { /* Init_SRA0_SRAF */ 681 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, 682 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, 683 }, 684 { /* Init_GR00_GR08 */ 685 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 686 0xFF, 687 }, 688 { /* Init_AR00_AR14 */ 689 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 690 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 691 0x41, 0x00, 0x0F, 0x00, 0x00, 692 }, 693 { /* Init_CR00_CR18 */ 694 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, 695 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 696 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, 697 0xFF, 698 }, 699 { /* Init_CR30_CR4D */ 700 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, 701 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, 702 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, 703 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, 704 }, 705 { /* Init_CR90_CRA7 */ 706 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, 707 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, 708 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 709 }, 710 }, 711 { /* mode#6: 320 x 240 16Bpp 60Hz */ 712 320, 240, 16, 60, 713 /* Init_MISC */ 714 0xEB, 715 { /* Init_SR0_SR4 */ 716 0x03, 0x01, 0x0F, 0x03, 0x0E, 717 }, 718 { /* Init_SR10_SR24 */ 719 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, 720 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 721 0xC4, 0x32, 0x02, 0x01, 0x01, 722 }, 723 { /* Init_SR30_SR75 */ 724 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, 725 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, 726 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, 727 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, 728 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, 729 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, 730 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, 731 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, 732 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, 733 }, 734 { /* Init_SR80_SR93 */ 735 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, 736 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, 737 0x00, 0x00, 0x00, 0x00, 738 }, 739 { /* Init_SRA0_SRAF */ 740 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, 741 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, 742 }, 743 { /* Init_GR00_GR08 */ 744 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 745 0xFF, 746 }, 747 { /* Init_AR00_AR14 */ 748 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 749 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 750 0x41, 0x00, 0x0F, 0x00, 0x00, 751 }, 752 { /* Init_CR00_CR18 */ 753 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, 754 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 755 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, 756 0xFF, 757 }, 758 { /* Init_CR30_CR4D */ 759 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, 760 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, 761 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, 762 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, 763 }, 764 { /* Init_CR90_CRA7 */ 765 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, 766 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, 767 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 768 }, 769 }, 770 771 { /* mode#8: 320 x 240 32Bpp 60Hz */ 772 320, 240, 32, 60, 773 /* Init_MISC */ 774 0xEB, 775 { /* Init_SR0_SR4 */ 776 0x03, 0x01, 0x0F, 0x03, 0x0E, 777 }, 778 { /* Init_SR10_SR24 */ 779 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, 780 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 781 0xC4, 0x32, 0x02, 0x01, 0x01, 782 }, 783 { /* Init_SR30_SR75 */ 784 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, 785 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, 786 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, 787 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, 788 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, 789 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, 790 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, 791 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, 792 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, 793 }, 794 { /* Init_SR80_SR93 */ 795 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, 796 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, 797 0x00, 0x00, 0x00, 0x00, 798 }, 799 { /* Init_SRA0_SRAF */ 800 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, 801 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, 802 }, 803 { /* Init_GR00_GR08 */ 804 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 805 0xFF, 806 }, 807 { /* Init_AR00_AR14 */ 808 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 809 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 810 0x41, 0x00, 0x0F, 0x00, 0x00, 811 }, 812 { /* Init_CR00_CR18 */ 813 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, 814 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 815 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, 816 0xFF, 817 }, 818 { /* Init_CR30_CR4D */ 819 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, 820 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, 821 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, 822 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, 823 }, 824 { /* Init_CR90_CRA7 */ 825 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, 826 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, 827 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 828 }, 829 }, 830 }; 831 832 static struct screen_info smtc_scr_info; 833 834 static char *mode_option; 835 836 /* process command line options, get vga parameter */ 837 static void __init sm7xx_vga_setup(char *options) 838 { 839 int i; 840 841 if (!options || !*options) 842 return; 843 844 smtc_scr_info.lfb_width = 0; 845 smtc_scr_info.lfb_height = 0; 846 smtc_scr_info.lfb_depth = 0; 847 848 pr_debug("%s = %s\n", __func__, options); 849 850 for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) { 851 if (strstr(options, vesa_mode_table[i].index)) { 852 smtc_scr_info.lfb_width = vesa_mode_table[i].lfb_width; 853 smtc_scr_info.lfb_height = 854 vesa_mode_table[i].lfb_height; 855 smtc_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth; 856 return; 857 } 858 } 859 } 860 861 static void sm712_setpalette(int regno, unsigned int red, unsigned int green, 862 unsigned int blue, struct fb_info *info) 863 { 864 /* set bit 5:4 = 01 (write LCD RAM only) */ 865 smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10); 866 867 smtc_mmiowb(regno, dac_reg); 868 smtc_mmiowb(red >> 10, dac_val); 869 smtc_mmiowb(green >> 10, dac_val); 870 smtc_mmiowb(blue >> 10, dac_val); 871 } 872 873 /* chan_to_field 874 * 875 * convert a colour value into a field position 876 * 877 * from pxafb.c 878 */ 879 880 static inline unsigned int chan_to_field(unsigned int chan, 881 struct fb_bitfield *bf) 882 { 883 chan &= 0xffff; 884 chan >>= 16 - bf->length; 885 return chan << bf->offset; 886 } 887 888 static int smtc_blank(int blank_mode, struct fb_info *info) 889 { 890 struct smtcfb_info *sfb = info->par; 891 892 /* clear DPMS setting */ 893 switch (blank_mode) { 894 case FB_BLANK_UNBLANK: 895 /* Screen On: HSync: On, VSync : On */ 896 897 switch (sfb->chip_id) { 898 case 0x710: 899 case 0x712: 900 smtc_seqw(0x6a, 0x16); 901 smtc_seqw(0x6b, 0x02); 902 break; 903 case 0x720: 904 smtc_seqw(0x6a, 0x0d); 905 smtc_seqw(0x6b, 0x02); 906 break; 907 } 908 909 smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); 910 smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); 911 smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77)); 912 smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); 913 smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03)); 914 smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); 915 break; 916 case FB_BLANK_NORMAL: 917 /* Screen Off: HSync: On, VSync : On Soft blank */ 918 smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); 919 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); 920 smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); 921 smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); 922 smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); 923 smtc_seqw(0x6a, 0x16); 924 smtc_seqw(0x6b, 0x02); 925 break; 926 case FB_BLANK_VSYNC_SUSPEND: 927 /* Screen On: HSync: On, VSync : Off */ 928 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); 929 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); 930 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20)); 931 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); 932 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); 933 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); 934 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20)); 935 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); 936 smtc_seqw(0x6a, 0x0c); 937 smtc_seqw(0x6b, 0x02); 938 break; 939 case FB_BLANK_HSYNC_SUSPEND: 940 /* Screen On: HSync: Off, VSync : On */ 941 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); 942 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); 943 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); 944 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); 945 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); 946 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); 947 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10)); 948 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); 949 smtc_seqw(0x6a, 0x0c); 950 smtc_seqw(0x6b, 0x02); 951 break; 952 case FB_BLANK_POWERDOWN: 953 /* Screen On: HSync: Off, VSync : Off */ 954 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); 955 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); 956 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); 957 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); 958 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); 959 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); 960 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30)); 961 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); 962 smtc_seqw(0x6a, 0x0c); 963 smtc_seqw(0x6b, 0x02); 964 break; 965 default: 966 return -EINVAL; 967 } 968 969 return 0; 970 } 971 972 static int smtc_setcolreg(unsigned int regno, unsigned int red, 973 unsigned int green, unsigned int blue, 974 unsigned int trans, struct fb_info *info) 975 { 976 struct smtcfb_info *sfb; 977 u32 val; 978 979 sfb = info->par; 980 981 if (regno > 255) 982 return 1; 983 984 switch (sfb->fb->fix.visual) { 985 case FB_VISUAL_DIRECTCOLOR: 986 case FB_VISUAL_TRUECOLOR: 987 /* 988 * 16/32 bit true-colour, use pseudo-palette for 16 base color 989 */ 990 if (regno >= 16) 991 break; 992 if (sfb->fb->var.bits_per_pixel == 16) { 993 u32 *pal = sfb->fb->pseudo_palette; 994 995 val = chan_to_field(red, &sfb->fb->var.red); 996 val |= chan_to_field(green, &sfb->fb->var.green); 997 val |= chan_to_field(blue, &sfb->fb->var.blue); 998 pal[regno] = pal_rgb(red, green, blue, val); 999 } else { 1000 u32 *pal = sfb->fb->pseudo_palette; 1001 1002 val = chan_to_field(red, &sfb->fb->var.red); 1003 val |= chan_to_field(green, &sfb->fb->var.green); 1004 val |= chan_to_field(blue, &sfb->fb->var.blue); 1005 pal[regno] = big_swap(val); 1006 } 1007 break; 1008 1009 case FB_VISUAL_PSEUDOCOLOR: 1010 /* color depth 8 bit */ 1011 sm712_setpalette(regno, red, green, blue, info); 1012 break; 1013 1014 default: 1015 return 1; /* unknown type */ 1016 } 1017 1018 return 0; 1019 } 1020 1021 static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, 1022 size_t count, loff_t *ppos) 1023 { 1024 unsigned long p = *ppos; 1025 1026 u32 *buffer, *dst; 1027 u32 __iomem *src; 1028 int c, i, cnt = 0, err = 0; 1029 unsigned long total_size; 1030 1031 if (!info->screen_base) 1032 return -ENODEV; 1033 1034 total_size = info->screen_size; 1035 1036 if (total_size == 0) 1037 total_size = info->fix.smem_len; 1038 1039 if (p >= total_size) 1040 return 0; 1041 1042 if (count >= total_size) 1043 count = total_size; 1044 1045 if (count + p > total_size) 1046 count = total_size - p; 1047 1048 buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); 1049 if (!buffer) 1050 return -ENOMEM; 1051 1052 src = (u32 __iomem *)(info->screen_base + p); 1053 1054 if (info->fbops->fb_sync) 1055 info->fbops->fb_sync(info); 1056 1057 while (count) { 1058 c = (count > PAGE_SIZE) ? PAGE_SIZE : count; 1059 dst = buffer; 1060 for (i = (c + 3) >> 2; i--;) { 1061 u32 val; 1062 1063 val = fb_readl(src); 1064 *dst = big_swap(val); 1065 src++; 1066 dst++; 1067 } 1068 1069 if (copy_to_user(buf, buffer, c)) { 1070 err = -EFAULT; 1071 break; 1072 } 1073 *ppos += c; 1074 buf += c; 1075 cnt += c; 1076 count -= c; 1077 } 1078 1079 kfree(buffer); 1080 1081 return (err) ? err : cnt; 1082 } 1083 1084 static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf, 1085 size_t count, loff_t *ppos) 1086 { 1087 unsigned long p = *ppos; 1088 1089 u32 *buffer, *src; 1090 u32 __iomem *dst; 1091 int c, i, cnt = 0, err = 0; 1092 unsigned long total_size; 1093 1094 if (!info->screen_base) 1095 return -ENODEV; 1096 1097 total_size = info->screen_size; 1098 1099 if (total_size == 0) 1100 total_size = info->fix.smem_len; 1101 1102 if (p > total_size) 1103 return -EFBIG; 1104 1105 if (count > total_size) { 1106 err = -EFBIG; 1107 count = total_size; 1108 } 1109 1110 if (count + p > total_size) { 1111 if (!err) 1112 err = -ENOSPC; 1113 1114 count = total_size - p; 1115 } 1116 1117 buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); 1118 if (!buffer) 1119 return -ENOMEM; 1120 1121 dst = (u32 __iomem *)(info->screen_base + p); 1122 1123 if (info->fbops->fb_sync) 1124 info->fbops->fb_sync(info); 1125 1126 while (count) { 1127 c = (count > PAGE_SIZE) ? PAGE_SIZE : count; 1128 src = buffer; 1129 1130 if (copy_from_user(src, buf, c)) { 1131 err = -EFAULT; 1132 break; 1133 } 1134 1135 for (i = (c + 3) >> 2; i--;) { 1136 fb_writel(big_swap(*src), dst); 1137 dst++; 1138 src++; 1139 } 1140 1141 *ppos += c; 1142 buf += c; 1143 cnt += c; 1144 count -= c; 1145 } 1146 1147 kfree(buffer); 1148 1149 return (cnt) ? cnt : err; 1150 } 1151 1152 static void sm7xx_set_timing(struct smtcfb_info *sfb) 1153 { 1154 int i = 0, j = 0; 1155 u32 m_nscreenstride; 1156 1157 dev_dbg(&sfb->pdev->dev, 1158 "sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n", 1159 sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz); 1160 1161 for (j = 0; j < ARRAY_SIZE(vgamode); j++) { 1162 if (vgamode[j].mmsizex != sfb->width || 1163 vgamode[j].mmsizey != sfb->height || 1164 vgamode[j].bpp != sfb->fb->var.bits_per_pixel || 1165 vgamode[j].hz != sfb->hz) 1166 continue; 1167 1168 dev_dbg(&sfb->pdev->dev, 1169 "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n", 1170 vgamode[j].mmsizex, vgamode[j].mmsizey, 1171 vgamode[j].bpp, vgamode[j].hz); 1172 1173 dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j); 1174 1175 smtc_mmiowb(0x0, 0x3c6); 1176 1177 smtc_seqw(0, 0x1); 1178 1179 smtc_mmiowb(vgamode[j].init_misc, 0x3c2); 1180 1181 /* init SEQ register SR00 - SR04 */ 1182 for (i = 0; i < SIZE_SR00_SR04; i++) 1183 smtc_seqw(i, vgamode[j].init_sr00_sr04[i]); 1184 1185 /* init SEQ register SR10 - SR24 */ 1186 for (i = 0; i < SIZE_SR10_SR24; i++) 1187 smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]); 1188 1189 /* init SEQ register SR30 - SR75 */ 1190 for (i = 0; i < SIZE_SR30_SR75; i++) 1191 if ((i + 0x30) != 0x30 && (i + 0x30) != 0x62 && 1192 (i + 0x30) != 0x6a && (i + 0x30) != 0x6b && 1193 (i + 0x30) != 0x70 && (i + 0x30) != 0x71 && 1194 (i + 0x30) != 0x74 && (i + 0x30) != 0x75) 1195 smtc_seqw(i + 0x30, 1196 vgamode[j].init_sr30_sr75[i]); 1197 1198 /* init SEQ register SR80 - SR93 */ 1199 for (i = 0; i < SIZE_SR80_SR93; i++) 1200 smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]); 1201 1202 /* init SEQ register SRA0 - SRAF */ 1203 for (i = 0; i < SIZE_SRA0_SRAF; i++) 1204 smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]); 1205 1206 /* init Graphic register GR00 - GR08 */ 1207 for (i = 0; i < SIZE_GR00_GR08; i++) 1208 smtc_grphw(i, vgamode[j].init_gr00_gr08[i]); 1209 1210 /* init Attribute register AR00 - AR14 */ 1211 for (i = 0; i < SIZE_AR00_AR14; i++) 1212 smtc_attrw(i, vgamode[j].init_ar00_ar14[i]); 1213 1214 /* init CRTC register CR00 - CR18 */ 1215 for (i = 0; i < SIZE_CR00_CR18; i++) 1216 smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]); 1217 1218 /* init CRTC register CR30 - CR4D */ 1219 for (i = 0; i < SIZE_CR30_CR4D; i++) { 1220 if ((i + 0x30) >= 0x3B && (i + 0x30) <= 0x3F) 1221 /* side-effect, don't write to CR3B-CR3F */ 1222 continue; 1223 smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]); 1224 } 1225 1226 /* init CRTC register CR90 - CRA7 */ 1227 for (i = 0; i < SIZE_CR90_CRA7; i++) 1228 smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]); 1229 } 1230 smtc_mmiowb(0x67, 0x3c2); 1231 1232 /* set VPR registers */ 1233 writel(0x0, sfb->vp_regs + 0x0C); 1234 writel(0x0, sfb->vp_regs + 0x40); 1235 1236 /* set data width */ 1237 m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64; 1238 switch (sfb->fb->var.bits_per_pixel) { 1239 case 8: 1240 writel(0x0, sfb->vp_regs + 0x0); 1241 break; 1242 case 16: 1243 writel(0x00020000, sfb->vp_regs + 0x0); 1244 break; 1245 case 24: 1246 writel(0x00040000, sfb->vp_regs + 0x0); 1247 break; 1248 case 32: 1249 writel(0x00030000, sfb->vp_regs + 0x0); 1250 break; 1251 } 1252 writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride), 1253 sfb->vp_regs + 0x10); 1254 } 1255 1256 static void smtc_set_timing(struct smtcfb_info *sfb) 1257 { 1258 switch (sfb->chip_id) { 1259 case 0x710: 1260 case 0x712: 1261 case 0x720: 1262 sm7xx_set_timing(sfb); 1263 break; 1264 } 1265 } 1266 1267 static void smtcfb_setmode(struct smtcfb_info *sfb) 1268 { 1269 switch (sfb->fb->var.bits_per_pixel) { 1270 case 32: 1271 sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR; 1272 sfb->fb->fix.line_length = sfb->fb->var.xres * 4; 1273 sfb->fb->var.red.length = 8; 1274 sfb->fb->var.green.length = 8; 1275 sfb->fb->var.blue.length = 8; 1276 sfb->fb->var.red.offset = 16; 1277 sfb->fb->var.green.offset = 8; 1278 sfb->fb->var.blue.offset = 0; 1279 break; 1280 case 24: 1281 sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR; 1282 sfb->fb->fix.line_length = sfb->fb->var.xres * 3; 1283 sfb->fb->var.red.length = 8; 1284 sfb->fb->var.green.length = 8; 1285 sfb->fb->var.blue.length = 8; 1286 sfb->fb->var.red.offset = 16; 1287 sfb->fb->var.green.offset = 8; 1288 sfb->fb->var.blue.offset = 0; 1289 break; 1290 case 8: 1291 sfb->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; 1292 sfb->fb->fix.line_length = sfb->fb->var.xres; 1293 sfb->fb->var.red.length = 3; 1294 sfb->fb->var.green.length = 3; 1295 sfb->fb->var.blue.length = 2; 1296 sfb->fb->var.red.offset = 5; 1297 sfb->fb->var.green.offset = 2; 1298 sfb->fb->var.blue.offset = 0; 1299 break; 1300 case 16: 1301 default: 1302 sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR; 1303 sfb->fb->fix.line_length = sfb->fb->var.xres * 2; 1304 sfb->fb->var.red.length = 5; 1305 sfb->fb->var.green.length = 6; 1306 sfb->fb->var.blue.length = 5; 1307 sfb->fb->var.red.offset = 11; 1308 sfb->fb->var.green.offset = 5; 1309 sfb->fb->var.blue.offset = 0; 1310 break; 1311 } 1312 1313 sfb->width = sfb->fb->var.xres; 1314 sfb->height = sfb->fb->var.yres; 1315 sfb->hz = 60; 1316 smtc_set_timing(sfb); 1317 } 1318 1319 static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 1320 { 1321 /* sanity checks */ 1322 if (var->xres_virtual < var->xres) 1323 var->xres_virtual = var->xres; 1324 1325 if (var->yres_virtual < var->yres) 1326 var->yres_virtual = var->yres; 1327 1328 /* set valid default bpp */ 1329 if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) && 1330 (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32)) 1331 var->bits_per_pixel = 16; 1332 1333 return 0; 1334 } 1335 1336 static int smtc_set_par(struct fb_info *info) 1337 { 1338 smtcfb_setmode(info->par); 1339 1340 return 0; 1341 } 1342 1343 static const struct fb_ops smtcfb_ops = { 1344 .owner = THIS_MODULE, 1345 .fb_check_var = smtc_check_var, 1346 .fb_set_par = smtc_set_par, 1347 .fb_setcolreg = smtc_setcolreg, 1348 .fb_blank = smtc_blank, 1349 .fb_fillrect = cfb_fillrect, 1350 .fb_imageblit = cfb_imageblit, 1351 .fb_copyarea = cfb_copyarea, 1352 .fb_read = smtcfb_read, 1353 .fb_write = smtcfb_write, 1354 }; 1355 1356 /* 1357 * Unmap in the memory mapped IO registers 1358 */ 1359 1360 static void smtc_unmap_mmio(struct smtcfb_info *sfb) 1361 { 1362 if (sfb && smtc_regbaseaddress) 1363 smtc_regbaseaddress = NULL; 1364 } 1365 1366 /* 1367 * Map in the screen memory 1368 */ 1369 1370 static int smtc_map_smem(struct smtcfb_info *sfb, 1371 struct pci_dev *pdev, u_long smem_len) 1372 { 1373 sfb->fb->fix.smem_start = pci_resource_start(pdev, 0); 1374 1375 if (sfb->chip_id == 0x720) 1376 /* on SM720, the framebuffer starts at the 1 MB offset */ 1377 sfb->fb->fix.smem_start += 0x00200000; 1378 1379 /* XXX: is it safe for SM720 on Big-Endian? */ 1380 if (sfb->fb->var.bits_per_pixel == 32) 1381 sfb->fb->fix.smem_start += big_addr; 1382 1383 sfb->fb->fix.smem_len = smem_len; 1384 1385 sfb->fb->screen_base = sfb->lfb; 1386 1387 if (!sfb->fb->screen_base) { 1388 dev_err(&pdev->dev, 1389 "%s: unable to map screen memory\n", sfb->fb->fix.id); 1390 return -ENOMEM; 1391 } 1392 1393 return 0; 1394 } 1395 1396 /* 1397 * Unmap in the screen memory 1398 * 1399 */ 1400 static void smtc_unmap_smem(struct smtcfb_info *sfb) 1401 { 1402 if (sfb && sfb->fb->screen_base) { 1403 if (sfb->chip_id == 0x720) 1404 sfb->fb->screen_base -= 0x00200000; 1405 iounmap(sfb->fb->screen_base); 1406 sfb->fb->screen_base = NULL; 1407 } 1408 } 1409 1410 /* 1411 * We need to wake up the device and make sure its in linear memory mode. 1412 */ 1413 static inline void sm7xx_init_hw(void) 1414 { 1415 outb_p(0x18, 0x3c4); 1416 outb_p(0x11, 0x3c5); 1417 } 1418 1419 static u_long sm7xx_vram_probe(struct smtcfb_info *sfb) 1420 { 1421 u8 vram; 1422 1423 switch (sfb->chip_id) { 1424 case 0x710: 1425 case 0x712: 1426 /* 1427 * Assume SM712 graphics chip has 4MB VRAM. 1428 * 1429 * FIXME: SM712 can have 2MB VRAM, which is used on earlier 1430 * laptops, such as IBM Thinkpad 240X. This driver would 1431 * probably crash on those machines. If anyone gets one of 1432 * those and is willing to help, run "git blame" and send me 1433 * an E-mail. 1434 */ 1435 return 0x00400000; 1436 case 0x720: 1437 outb_p(0x76, 0x3c4); 1438 vram = inb_p(0x3c5) >> 6; 1439 1440 if (vram == 0x00) 1441 return 0x00800000; /* 8 MB */ 1442 else if (vram == 0x01) 1443 return 0x01000000; /* 16 MB */ 1444 else if (vram == 0x02) 1445 return 0x00400000; /* illegal, fallback to 4 MB */ 1446 else if (vram == 0x03) 1447 return 0x00400000; /* 4 MB */ 1448 } 1449 return 0; /* unknown hardware */ 1450 } 1451 1452 static void sm7xx_resolution_probe(struct smtcfb_info *sfb) 1453 { 1454 /* get mode parameter from smtc_scr_info */ 1455 if (smtc_scr_info.lfb_width != 0) { 1456 sfb->fb->var.xres = smtc_scr_info.lfb_width; 1457 sfb->fb->var.yres = smtc_scr_info.lfb_height; 1458 sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth; 1459 goto final; 1460 } 1461 1462 /* 1463 * No parameter, default resolution is 1024x768-16. 1464 * 1465 * FIXME: earlier laptops, such as IBM Thinkpad 240X, has a 800x600 1466 * panel, also see the comments about Thinkpad 240X above. 1467 */ 1468 sfb->fb->var.xres = SCREEN_X_RES; 1469 sfb->fb->var.yres = SCREEN_Y_RES_PC; 1470 sfb->fb->var.bits_per_pixel = SCREEN_BPP; 1471 1472 #ifdef CONFIG_MIPS 1473 /* 1474 * Loongson MIPS netbooks use 1024x600 LCD panels, which is the original 1475 * target platform of this driver, but nearly all old x86 laptops have 1476 * 1024x768. Lighting 768 panels using 600's timings would partially 1477 * garble the display, so we don't want that. But it's not possible to 1478 * distinguish them reliably. 1479 * 1480 * So we change the default to 768, but keep 600 as-is on MIPS. 1481 */ 1482 sfb->fb->var.yres = SCREEN_Y_RES_NETBOOK; 1483 #endif 1484 1485 final: 1486 big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth); 1487 } 1488 1489 static int smtcfb_pci_probe(struct pci_dev *pdev, 1490 const struct pci_device_id *ent) 1491 { 1492 struct smtcfb_info *sfb; 1493 struct fb_info *info; 1494 u_long smem_size; 1495 int err; 1496 unsigned long mmio_base; 1497 1498 dev_info(&pdev->dev, "Silicon Motion display driver.\n"); 1499 1500 err = aperture_remove_conflicting_pci_devices(pdev, "smtcfb"); 1501 if (err) 1502 return err; 1503 1504 err = pci_enable_device(pdev); /* enable SMTC chip */ 1505 if (err) 1506 return err; 1507 1508 err = pci_request_region(pdev, 0, "sm7xxfb"); 1509 if (err < 0) { 1510 dev_err(&pdev->dev, "cannot reserve framebuffer region\n"); 1511 goto failed_regions; 1512 } 1513 1514 sprintf(smtcfb_fix.id, "sm%Xfb", ent->device); 1515 1516 info = framebuffer_alloc(sizeof(*sfb), &pdev->dev); 1517 if (!info) { 1518 err = -ENOMEM; 1519 goto failed_free; 1520 } 1521 1522 sfb = info->par; 1523 sfb->fb = info; 1524 sfb->chip_id = ent->device; 1525 sfb->pdev = pdev; 1526 info->flags = FBINFO_FLAG_DEFAULT; 1527 info->fbops = &smtcfb_ops; 1528 info->fix = smtcfb_fix; 1529 info->var = smtcfb_var; 1530 info->pseudo_palette = sfb->colreg; 1531 info->par = sfb; 1532 1533 pci_set_drvdata(pdev, sfb); 1534 1535 sm7xx_init_hw(); 1536 1537 /* Map address and memory detection */ 1538 mmio_base = pci_resource_start(pdev, 0); 1539 pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id); 1540 1541 smem_size = sm7xx_vram_probe(sfb); 1542 dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n", 1543 smem_size / 1048576); 1544 1545 switch (sfb->chip_id) { 1546 case 0x710: 1547 case 0x712: 1548 sfb->fb->fix.mmio_start = mmio_base + 0x00400000; 1549 sfb->fb->fix.mmio_len = 0x00400000; 1550 sfb->lfb = ioremap(mmio_base, mmio_addr); 1551 if (!sfb->lfb) { 1552 dev_err(&pdev->dev, 1553 "%s: unable to map memory mapped IO!\n", 1554 sfb->fb->fix.id); 1555 err = -ENOMEM; 1556 goto failed_fb; 1557 } 1558 1559 sfb->mmio = (smtc_regbaseaddress = 1560 sfb->lfb + 0x00700000); 1561 sfb->dp_regs = sfb->lfb + 0x00408000; 1562 sfb->vp_regs = sfb->lfb + 0x0040c000; 1563 if (sfb->fb->var.bits_per_pixel == 32) { 1564 sfb->lfb += big_addr; 1565 dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb); 1566 } 1567 1568 /* set MCLK = 14.31818 * (0x16 / 0x2) */ 1569 smtc_seqw(0x6a, 0x16); 1570 smtc_seqw(0x6b, 0x02); 1571 smtc_seqw(0x62, 0x3e); 1572 /* enable PCI burst */ 1573 smtc_seqw(0x17, 0x20); 1574 /* enable word swap */ 1575 if (sfb->fb->var.bits_per_pixel == 32) 1576 seqw17(); 1577 break; 1578 case 0x720: 1579 sfb->fb->fix.mmio_start = mmio_base; 1580 sfb->fb->fix.mmio_len = 0x00200000; 1581 sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size); 1582 if (!sfb->dp_regs) { 1583 dev_err(&pdev->dev, 1584 "%s: unable to map memory mapped IO!\n", 1585 sfb->fb->fix.id); 1586 err = -ENOMEM; 1587 goto failed_fb; 1588 } 1589 1590 sfb->lfb = sfb->dp_regs + 0x00200000; 1591 sfb->mmio = (smtc_regbaseaddress = 1592 sfb->dp_regs + 0x000c0000); 1593 sfb->vp_regs = sfb->dp_regs + 0x800; 1594 1595 smtc_seqw(0x62, 0xff); 1596 smtc_seqw(0x6a, 0x0d); 1597 smtc_seqw(0x6b, 0x02); 1598 break; 1599 default: 1600 dev_err(&pdev->dev, 1601 "No valid Silicon Motion display chip was detected!\n"); 1602 err = -ENODEV; 1603 goto failed_fb; 1604 } 1605 1606 /* probe and decide resolution */ 1607 sm7xx_resolution_probe(sfb); 1608 1609 /* can support 32 bpp */ 1610 if (sfb->fb->var.bits_per_pixel == 15) 1611 sfb->fb->var.bits_per_pixel = 16; 1612 1613 sfb->fb->var.xres_virtual = sfb->fb->var.xres; 1614 sfb->fb->var.yres_virtual = sfb->fb->var.yres; 1615 err = smtc_map_smem(sfb, pdev, smem_size); 1616 if (err) 1617 goto failed; 1618 1619 /* 1620 * The screen would be temporarily garbled when sm712fb takes over 1621 * vesafb or VGA text mode. Zero the framebuffer. 1622 */ 1623 memset_io(sfb->lfb, 0, sfb->fb->fix.smem_len); 1624 1625 err = register_framebuffer(info); 1626 if (err < 0) 1627 goto failed; 1628 1629 dev_info(&pdev->dev, 1630 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n", 1631 sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres, 1632 sfb->fb->var.yres, sfb->fb->var.bits_per_pixel); 1633 1634 return 0; 1635 1636 failed: 1637 dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n"); 1638 1639 smtc_unmap_smem(sfb); 1640 smtc_unmap_mmio(sfb); 1641 failed_fb: 1642 framebuffer_release(info); 1643 1644 failed_free: 1645 pci_release_region(pdev, 0); 1646 1647 failed_regions: 1648 pci_disable_device(pdev); 1649 1650 return err; 1651 } 1652 1653 /* 1654 * 0x710 (LynxEM) 1655 * 0x712 (LynxEM+) 1656 * 0x720 (Lynx3DM, Lynx3DM+) 1657 */ 1658 static const struct pci_device_id smtcfb_pci_table[] = { 1659 { PCI_DEVICE(0x126f, 0x710), }, 1660 { PCI_DEVICE(0x126f, 0x712), }, 1661 { PCI_DEVICE(0x126f, 0x720), }, 1662 {0,} 1663 }; 1664 1665 MODULE_DEVICE_TABLE(pci, smtcfb_pci_table); 1666 1667 static void smtcfb_pci_remove(struct pci_dev *pdev) 1668 { 1669 struct smtcfb_info *sfb; 1670 1671 sfb = pci_get_drvdata(pdev); 1672 smtc_unmap_smem(sfb); 1673 smtc_unmap_mmio(sfb); 1674 unregister_framebuffer(sfb->fb); 1675 framebuffer_release(sfb->fb); 1676 pci_release_region(pdev, 0); 1677 pci_disable_device(pdev); 1678 } 1679 1680 static int __maybe_unused smtcfb_pci_suspend(struct device *device) 1681 { 1682 struct smtcfb_info *sfb = dev_get_drvdata(device); 1683 1684 1685 /* set the hw in sleep mode use external clock and self memory refresh 1686 * so that we can turn off internal PLLs later on 1687 */ 1688 smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0)); 1689 smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7)); 1690 1691 console_lock(); 1692 fb_set_suspend(sfb->fb, 1); 1693 console_unlock(); 1694 1695 /* additionally turn off all function blocks including internal PLLs */ 1696 smtc_seqw(0x21, 0xff); 1697 1698 return 0; 1699 } 1700 1701 static int __maybe_unused smtcfb_pci_resume(struct device *device) 1702 { 1703 struct smtcfb_info *sfb = dev_get_drvdata(device); 1704 1705 1706 /* reinit hardware */ 1707 sm7xx_init_hw(); 1708 switch (sfb->chip_id) { 1709 case 0x710: 1710 case 0x712: 1711 /* set MCLK = 14.31818 * (0x16 / 0x2) */ 1712 smtc_seqw(0x6a, 0x16); 1713 smtc_seqw(0x6b, 0x02); 1714 smtc_seqw(0x62, 0x3e); 1715 /* enable PCI burst */ 1716 smtc_seqw(0x17, 0x20); 1717 if (sfb->fb->var.bits_per_pixel == 32) 1718 seqw17(); 1719 break; 1720 case 0x720: 1721 smtc_seqw(0x62, 0xff); 1722 smtc_seqw(0x6a, 0x0d); 1723 smtc_seqw(0x6b, 0x02); 1724 break; 1725 } 1726 1727 smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0)); 1728 smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb)); 1729 1730 smtcfb_setmode(sfb); 1731 1732 console_lock(); 1733 fb_set_suspend(sfb->fb, 0); 1734 console_unlock(); 1735 1736 return 0; 1737 } 1738 1739 static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume); 1740 1741 static struct pci_driver smtcfb_driver = { 1742 .name = "smtcfb", 1743 .id_table = smtcfb_pci_table, 1744 .probe = smtcfb_pci_probe, 1745 .remove = smtcfb_pci_remove, 1746 .driver.pm = &sm7xx_pm_ops, 1747 }; 1748 1749 static int __init sm712fb_init(void) 1750 { 1751 char *option = NULL; 1752 1753 if (fb_modesetting_disabled("sm712fb")) 1754 return -ENODEV; 1755 1756 if (fb_get_options("sm712fb", &option)) 1757 return -ENODEV; 1758 if (option && *option) 1759 mode_option = option; 1760 sm7xx_vga_setup(mode_option); 1761 1762 return pci_register_driver(&smtcfb_driver); 1763 } 1764 1765 module_init(sm712fb_init); 1766 1767 static void __exit sm712fb_exit(void) 1768 { 1769 pci_unregister_driver(&smtcfb_driver); 1770 } 1771 1772 module_exit(sm712fb_exit); 1773 1774 MODULE_AUTHOR("Siliconmotion "); 1775 MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards"); 1776 MODULE_LICENSE("GPL"); 1777