staging: sm750: fix whitespaces around pointers
[linux-2.6-block.git] / drivers / staging / sm750fb / sm750.c
CommitLineData
81dee67e
SM
1#include<linux/kernel.h>
2#include<linux/module.h>
3#include<linux/errno.h>
4#include<linux/string.h>
5#include<linux/mm.h>
6#include<linux/slab.h>
7#include<linux/delay.h>
8#include<linux/fb.h>
9#include<linux/ioport.h>
10#include<linux/init.h>
11#include<linux/pci.h>
12#include<linux/mm_types.h>
13#include<linux/vmalloc.h>
14#include<linux/pagemap.h>
15#include<linux/screen_info.h>
16#include<linux/vmalloc.h>
17#include<linux/pagemap.h>
18#include <linux/console.h>
19#ifdef CONFIG_MTRR
20#include <asm/mtrr.h>
21#endif
22#include <asm/fb.h>
23#include "sm750.h"
24#include "sm750_hw.h"
25#include "sm750_accel.h"
26#include "sm750_cursor.h"
27
28#include "modedb.h"
29
30int smi_indent = 0;
31
32
33/*
c52c3700
MC
34 * #ifdef __BIG_ENDIAN
35 * ssize_t lynxfb_ops_write(struct fb_info *info, const char __user *buf,
36 * size_t count, loff_t *ppos);
37 * ssize_t lynxfb_ops_read(struct fb_info *info, char __user *buf,
38 * size_t count, loff_t *ppos);
39 * #endif
81dee67e
SM
40 */
41
5ace4e10
MC
42typedef void (*PROC_SPEC_SETUP)(struct lynx_share*, char *);
43typedef int (*PROC_SPEC_MAP)(struct lynx_share*, struct pci_dev*);
44typedef int (*PROC_SPEC_INITHW)(struct lynx_share*, struct pci_dev*);
81dee67e
SM
45
46
47/* common var for all device */
48static int g_hwcursor = 1;
b30edfcd 49static int g_noaccel;
81dee67e 50#ifdef CONFIG_MTRR
b30edfcd 51static int g_nomtrr;
81dee67e 52#endif
27fa159b
MC
53static const char *g_fbmode[] = {NULL, NULL};
54static const char *g_def_fbmode = "800x600-16@60";
55static char *g_settings = NULL;
b30edfcd 56static int g_dualview;
27fa159b
MC
57static char *g_option = NULL;
58
81dee67e 59
81dee67e 60static const struct fb_videomode lynx750_ext[] = {
45e3b3da 61 /* 1024x600-60 VESA [1.71:1] */
81dee67e 62 {NULL, 60, 1024, 600, 20423, 144, 40, 18, 1, 104, 3,
c52c3700 63 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
81dee67e 64
45e3b3da 65 /* 1024x600-70 VESA */
81dee67e 66 {NULL, 70, 1024, 600, 17211, 152, 48, 21, 1, 104, 3,
c52c3700 67 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
81dee67e 68
45e3b3da 69 /* 1024x600-75 VESA */
81dee67e 70 {NULL, 75, 1024, 600, 15822, 160, 56, 23, 1, 104, 3,
c52c3700 71 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
81dee67e 72
45e3b3da 73 /* 1024x600-85 VESA */
81dee67e 74 {NULL, 85, 1024, 600, 13730, 168, 56, 26, 1, 112, 3,
c52c3700 75 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
81dee67e
SM
76
77 /* 720x480 */
78 {NULL, 60, 720, 480, 37427, 88, 16, 13, 1, 72, 3,
c52c3700 79 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
81dee67e
SM
80
81 /* 1280x720 [1.78:1] */
82 {NULL, 60, 1280, 720, 13426, 162, 86, 22, 1, 136, 3,
45e3b3da 83 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
81dee67e 84
45e3b3da
MC
85 /* 1280x768@60 */
86 {NULL, 60, 1280, 768, 12579, 192, 64, 20, 3, 128, 7,
c52c3700 87 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED},
81dee67e 88
45e3b3da 89 {NULL, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3,
c52c3700 90 FB_SYNC_HOR_HIGH_ACT|FB_VMODE_NONINTERLACED},
81dee67e
SM
91
92 /* 1360 x 768 [1.77083:1] */
93 {NULL, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3,
c52c3700 94 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
81dee67e
SM
95
96 /* 1368 x 768 [1.78:1] */
97 {NULL, 60, 1368, 768, 11647, 216, 72, 23, 1, 144, 3,
c52c3700 98 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
81dee67e 99
45e3b3da 100 /* 1440 x 900 [16:10] */
81dee67e 101 {NULL, 60, 1440, 900, 9392, 232, 80, 28, 1, 152, 3,
45e3b3da 102 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
81dee67e
SM
103
104 /* 1440x960 [15:10] */
105 {NULL, 60, 1440, 960, 8733, 240, 88, 30, 1, 152, 3,
c52c3700 106 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
81dee67e
SM
107
108 /* 1920x1080 [16:9] */
109 {NULL, 60, 1920, 1080, 6734, 148, 88, 41, 1, 44, 3,
45e3b3da 110 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
81dee67e
SM
111};
112
113
114
115
116/* no hardware cursor supported under version 2.6.10, kernel bug */
27fa159b 117static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor)
81dee67e 118{
27fa159b
MC
119 struct lynxfb_par *par;
120 struct lynxfb_crtc *crtc;
121 struct lynx_cursor *cursor;
81dee67e
SM
122
123 par = info->par;
124 crtc = &par->crtc;
125 cursor = &crtc->cursor;
126
5ace4e10 127 if (fbcursor->image.width > cursor->maxW ||
c52c3700 128 fbcursor->image.height > cursor->maxH ||
5ace4e10 129 fbcursor->image.depth > 1) {
81dee67e
SM
130 return -ENXIO;
131 }
132
133 cursor->disable(cursor);
5ace4e10 134 if (fbcursor->set & FB_CUR_SETSIZE) {
45e3b3da 135 cursor->setSize(cursor, fbcursor->image.width, fbcursor->image.height);
81dee67e
SM
136 }
137
5ace4e10 138 if (fbcursor->set & FB_CUR_SETPOS) {
45e3b3da 139 cursor->setPos(cursor, fbcursor->image.dx - info->var.xoffset,
c52c3700 140 fbcursor->image.dy - info->var.yoffset);
81dee67e
SM
141 }
142
5ace4e10 143 if (fbcursor->set & FB_CUR_SETCMAP) {
81dee67e 144 /* get the 16bit color of kernel means */
45e3b3da 145 u16 fg, bg;
81dee67e 146 fg = ((info->cmap.red[fbcursor->image.fg_color] & 0xf800))|
c52c3700
MC
147 ((info->cmap.green[fbcursor->image.fg_color] & 0xfc00) >> 5)|
148 ((info->cmap.blue[fbcursor->image.fg_color] & 0xf800) >> 11);
81dee67e
SM
149
150 bg = ((info->cmap.red[fbcursor->image.bg_color] & 0xf800))|
c52c3700
MC
151 ((info->cmap.green[fbcursor->image.bg_color] & 0xfc00) >> 5)|
152 ((info->cmap.blue[fbcursor->image.bg_color] & 0xf800) >> 11);
81dee67e 153
45e3b3da 154 cursor->setColor(cursor, fg, bg);
81dee67e
SM
155 }
156
157
5ace4e10 158 if (fbcursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
81dee67e 159 cursor->setData(cursor,
c52c3700
MC
160 fbcursor->rop,
161 fbcursor->image.data,
162 fbcursor->mask);
81dee67e
SM
163 }
164
5ace4e10 165 if (fbcursor->enable) {
81dee67e
SM
166 cursor->enable(cursor);
167 }
168
169 return 0;
170}
171
27fa159b 172static void lynxfb_ops_fillrect(struct fb_info *info, const struct fb_fillrect *region)
81dee67e 173{
27fa159b
MC
174 struct lynxfb_par *par;
175 struct lynx_share *share;
45e3b3da 176 unsigned int base, pitch, Bpp, rop;
81dee67e
SM
177 u32 color;
178
5ace4e10 179 if (info->state != FBINFO_STATE_RUNNING) {
81dee67e
SM
180 return;
181 }
182
183 par = info->par;
184 share = par->share;
185
186 /* each time 2d function begin to work,below three variable always need
187 * be set, seems we can put them together in some place */
188 base = par->crtc.oScreen;
189 pitch = info->fix.line_length;
190 Bpp = info->var.bits_per_pixel >> 3;
191
192 color = (Bpp == 1)?region->color:((u32*)info->pseudo_palette)[region->color];
5ace4e10 193 rop = (region->rop != ROP_COPY) ? HW_ROP2_XOR:HW_ROP2_COPY;
81dee67e 194
cb422f3b
LS
195 /*
196 * If not use spin_lock,system will die if user load driver
197 * and immediatly unload driver frequently (dual)
198 */
199 if (share->dual)
200 spin_lock(&share->slock);
201
81dee67e 202 share->accel.de_fillrect(&share->accel,
45e3b3da
MC
203 base, pitch, Bpp,
204 region->dx, region->dy,
205 region->width, region->height,
206 color, rop);
cb422f3b
LS
207 if (share->dual)
208 spin_unlock(&share->slock);
81dee67e
SM
209}
210
27fa159b 211static void lynxfb_ops_copyarea(struct fb_info *info, const struct fb_copyarea *region)
81dee67e 212{
27fa159b
MC
213 struct lynxfb_par *par;
214 struct lynx_share *share;
45e3b3da 215 unsigned int base, pitch, Bpp;
81dee67e
SM
216
217 par = info->par;
218 share = par->share;
219
220 /* each time 2d function begin to work,below three variable always need
221 * be set, seems we can put them together in some place */
222 base = par->crtc.oScreen;
223 pitch = info->fix.line_length;
224 Bpp = info->var.bits_per_pixel >> 3;
225
cb422f3b
LS
226 /*
227 * If not use spin_lock, system will die if user load driver
228 * and immediatly unload driver frequently (dual)
229 */
230 if (share->dual)
231 spin_lock(&share->slock);
232
81dee67e 233 share->accel.de_copyarea(&share->accel,
45e3b3da
MC
234 base, pitch, region->sx, region->sy,
235 base, pitch, Bpp, region->dx, region->dy,
236 region->width, region->height, HW_ROP2_COPY);
cb422f3b
LS
237 if (share->dual)
238 spin_unlock(&share->slock);
81dee67e
SM
239}
240
27fa159b 241static void lynxfb_ops_imageblit(struct fb_info *info, const struct fb_image *image)
81dee67e 242{
45e3b3da
MC
243 unsigned int base, pitch, Bpp;
244 unsigned int fgcol, bgcol;
27fa159b
MC
245 struct lynxfb_par *par;
246 struct lynx_share *share;
81dee67e
SM
247
248 par = info->par;
249 share = par->share;
250 /* each time 2d function begin to work,below three variable always need
251 * be set, seems we can put them together in some place */
252 base = par->crtc.oScreen;
253 pitch = info->fix.line_length;
254 Bpp = info->var.bits_per_pixel >> 3;
255
5ace4e10
MC
256 if (image->depth == 1) {
257 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
70407df7 258 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
81dee67e
SM
259 fgcol = ((u32*)info->pseudo_palette)[image->fg_color];
260 bgcol = ((u32*)info->pseudo_palette)[image->bg_color];
70407df7 261 } else {
81dee67e
SM
262 fgcol = image->fg_color;
263 bgcol = image->bg_color;
264 }
265 goto _do_work;
266 }
267 return;
268_do_work:
cb422f3b
LS
269 /*
270 * If not use spin_lock, system will die if user load driver
271 * and immediatly unload driver frequently (dual)
272 */
273 if (share->dual)
274 spin_lock(&share->slock);
275
81dee67e 276 share->accel.de_imageblit(&share->accel,
45e3b3da
MC
277 image->data, image->width>>3, 0,
278 base, pitch, Bpp,
279 image->dx, image->dy,
280 image->width, image->height,
281 fgcol, bgcol, HW_ROP2_COPY);
cb422f3b
LS
282 if (share->dual)
283 spin_unlock(&share->slock);
81dee67e
SM
284}
285
286static int lynxfb_ops_pan_display(struct fb_var_screeninfo *var,
c52c3700 287 struct fb_info *info)
81dee67e 288{
27fa159b
MC
289 struct lynxfb_par *par;
290 struct lynxfb_crtc *crtc;
c52c3700 291 int ret;
81dee67e 292
81dee67e 293
5ace4e10 294 if (!info)
c52c3700 295 return -EINVAL;
81dee67e 296
c52c3700
MC
297 ret = 0;
298 par = info->par;
299 crtc = &par->crtc;
300 ret = crtc->proc_panDisplay(crtc, var, info);
301
302 return ret;
81dee67e
SM
303}
304
27fa159b 305static int lynxfb_ops_set_par(struct fb_info *info)
81dee67e 306{
27fa159b
MC
307 struct lynxfb_par *par;
308 struct lynx_share *share;
309 struct lynxfb_crtc *crtc;
310 struct lynxfb_output *output;
311 struct fb_var_screeninfo *var;
312 struct fb_fix_screeninfo *fix;
81dee67e
SM
313 int ret;
314 unsigned int line_length;
81dee67e 315
5ace4e10 316 if (!info)
81dee67e
SM
317 return -EINVAL;
318
319 ret = 0;
320 par = info->par;
321 share = par->share;
322 crtc = &par->crtc;
323 output = &par->output;
324 var = &info->var;
325 fix = &info->fix;
326
327 /* fix structur is not so FIX ... */
328 line_length = var->xres_virtual * var->bits_per_pixel / 8;
45e3b3da 329 line_length = PADDING(crtc->line_pad, line_length);
81dee67e 330 fix->line_length = line_length;
45e3b3da 331 pr_err("fix->line_length = %d\n", fix->line_length);
81dee67e
SM
332
333 /* var->red,green,blue,transp are need to be set by driver
334 * and these data should be set before setcolreg routine
335 * */
336
5ace4e10 337 switch (var->bits_per_pixel) {
d6b0d6de
IC
338 case 8:
339 fix->visual = FB_VISUAL_PSEUDOCOLOR;
340 var->red.offset = 0;
341 var->red.length = 8;
342 var->green.offset = 0;
343 var->green.length = 8;
344 var->blue.offset = 0;
345 var->blue.length = 8;
346 var->transp.length = 0;
347 var->transp.offset = 0;
348 break;
349 case 16:
350 var->red.offset = 11;
351 var->red.length = 5;
352 var->green.offset = 5;
353 var->green.length = 6;
354 var->blue.offset = 0;
355 var->blue.length = 5;
356 var->transp.length = 0;
357 var->transp.offset = 0;
358 fix->visual = FB_VISUAL_TRUECOLOR;
359 break;
360 case 24:
361 case 32:
362 var->red.offset = 16;
363 var->red.length = 8;
364 var->green.offset = 8;
365 var->green.length = 8;
366 var->blue.offset = 0 ;
367 var->blue.length = 8;
368 fix->visual = FB_VISUAL_TRUECOLOR;
369 break;
370 default:
371 ret = -EINVAL;
372 break;
81dee67e
SM
373 }
374 var->height = var->width = -1;
375 var->accel_flags = 0;/*FB_ACCELF_TEXT;*/
376
5ace4e10 377 if (ret) {
81dee67e
SM
378 pr_err("pixel bpp format not satisfied\n.");
379 return ret;
380 }
45e3b3da 381 ret = crtc->proc_setMode(crtc, var, fix);
5ace4e10 382 if (!ret)
45e3b3da 383 ret = output->proc_setMode(output, var, fix);
81dee67e
SM
384 return ret;
385}
848f2fce 386
27fa159b 387static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
81dee67e
SM
388{
389 chan &= 0xffff;
390 chan >>= 16 - bf->length;
391 return chan << bf->offset;
392}
393
848f2fce
SM
394#ifdef CONFIG_PM
395static int lynxfb_suspend(struct pci_dev *pdev, pm_message_t mesg)
396{
397 struct fb_info *info;
398 struct lynx_share *share;
399 int ret;
400
401 if (mesg.event == pdev->dev.power.power_state.event)
402 return 0;
403
404 ret = 0;
405 share = pci_get_drvdata(pdev);
406 switch (mesg.event) {
407 case PM_EVENT_FREEZE:
408 case PM_EVENT_PRETHAW:
409 pdev->dev.power.power_state = mesg;
410 return 0;
411 }
412
413 console_lock();
414 if (mesg.event & PM_EVENT_SLEEP) {
415 info = share->fbinfo[0];
416 if (info)
417 /* 1 means do suspend*/
418 fb_set_suspend(info, 1);
419 info = share->fbinfo[1];
420 if (info)
421 /* 1 means do suspend*/
422 fb_set_suspend(info, 1);
423
424 ret = pci_save_state(pdev);
425 if (ret) {
426 pr_err("error:%d occurred in pci_save_state\n", ret);
427 return ret;
428 }
429
430 /* set chip to sleep mode*/
431 if (share->suspend)
432 (*share->suspend)(share);
433
434 pci_disable_device(pdev);
435 ret = pci_set_power_state(pdev, pci_choose_state(pdev, mesg));
436 if (ret) {
437 pr_err("error:%d occurred in pci_set_power_state\n", ret);
438 return ret;
439 }
440 }
441
442 pdev->dev.power.power_state = mesg;
443 console_unlock();
444 return ret;
445}
81dee67e 446
27fa159b 447static int lynxfb_resume(struct pci_dev *pdev)
81dee67e 448{
27fa159b
MC
449 struct fb_info *info;
450 struct lynx_share *share;
81dee67e 451
27fa159b
MC
452 struct lynxfb_par *par;
453 struct lynxfb_crtc *crtc;
454 struct lynx_cursor *cursor;
81dee67e
SM
455
456 int ret;
c52c3700 457
81dee67e
SM
458
459 ret = 0;
460 share = pci_get_drvdata(pdev);
461
462 console_lock();
463
5ace4e10 464 if ((ret = pci_set_power_state(pdev, PCI_D0)) != 0) {
45e3b3da 465 pr_err("error:%d occured in pci_set_power_state\n", ret);
81dee67e
SM
466 return ret;
467 }
468
469
5ace4e10 470 if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) {
81dee67e 471 pci_restore_state(pdev);
5ace4e10 472 if ((ret = pci_enable_device(pdev)) != 0) {
45e3b3da 473 pr_err("error:%d occured in pci_enable_device\n", ret);
81dee67e
SM
474 return ret;
475 }
476 pci_set_master(pdev);
477 }
5ace4e10 478 if (share->resume)
81dee67e
SM
479 (*share->resume)(share);
480
45e3b3da 481 hw_sm750_inithw(share, pdev);
81dee67e
SM
482
483
484 info = share->fbinfo[0];
485
5ace4e10 486 if (info) {
81dee67e
SM
487 par = info->par;
488 crtc = &par->crtc;
489 cursor = &crtc->cursor;
3de08a2d
LS
490 memset_io(cursor->vstart, 0x0, cursor->size);
491 memset_io(crtc->vScreen, 0x0, crtc->vidmem_size);
81dee67e
SM
492 lynxfb_ops_set_par(info);
493 fb_set_suspend(info, 0);
494 }
495
496 info = share->fbinfo[1];
497
5ace4e10 498 if (info) {
81dee67e
SM
499 par = info->par;
500 crtc = &par->crtc;
501 cursor = &crtc->cursor;
3de08a2d
LS
502 memset_io(cursor->vstart, 0x0, cursor->size);
503 memset_io(crtc->vScreen, 0x0, crtc->vidmem_size);
81dee67e
SM
504 lynxfb_ops_set_par(info);
505 fb_set_suspend(info, 0);
506 }
507
508
509 console_unlock();
510 return ret;
511}
512#endif
513
27fa159b 514static int lynxfb_ops_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
81dee67e 515{
27fa159b
MC
516 struct lynxfb_par *par;
517 struct lynxfb_crtc *crtc;
518 struct lynxfb_output *output;
519 struct lynx_share *share;
81dee67e
SM
520 int ret;
521 resource_size_t request;
522
c52c3700 523
81dee67e
SM
524 par = info->par;
525 crtc = &par->crtc;
526 output = &par->output;
527 share = par->share;
528 ret = 0;
529
530 pr_debug("check var:%dx%d-%d\n",
c52c3700
MC
531 var->xres,
532 var->yres,
533 var->bits_per_pixel);
81dee67e
SM
534
535
5ace4e10 536 switch (var->bits_per_pixel) {
d6b0d6de
IC
537 case 8:
538 case 16:
539 case 24: /* support 24 bpp for only lynx712/722/720 */
540 case 32:
541 break;
542 default:
45e3b3da 543 pr_err("bpp %d not supported\n", var->bits_per_pixel);
d6b0d6de
IC
544 ret = -EINVAL;
545 goto exit;
81dee67e
SM
546 }
547
5ace4e10 548 switch (var->bits_per_pixel) {
d6b0d6de
IC
549 case 8:
550 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
551 var->red.offset = 0;
552 var->red.length = 8;
553 var->green.offset = 0;
554 var->green.length = 8;
555 var->blue.offset = 0;
556 var->blue.length = 8;
557 var->transp.length = 0;
558 var->transp.offset = 0;
559 break;
560 case 16:
561 var->red.offset = 11;
562 var->red.length = 5;
563 var->green.offset = 5;
564 var->green.length = 6;
565 var->blue.offset = 0;
566 var->blue.length = 5;
567 var->transp.length = 0;
568 var->transp.offset = 0;
569 info->fix.visual = FB_VISUAL_TRUECOLOR;
570 break;
571 case 24:
572 case 32:
573 var->red.offset = 16;
574 var->red.length = 8;
575 var->green.offset = 8;
576 var->green.length = 8;
577 var->blue.offset = 0 ;
578 var->blue.length = 8;
579 info->fix.visual = FB_VISUAL_TRUECOLOR;
580 break;
581 default:
582 ret = -EINVAL;
583 break;
81dee67e
SM
584 }
585 var->height = var->width = -1;
586 var->accel_flags = 0;/*FB_ACCELF_TEXT;*/
587
588 /* check if current fb's video memory big enought to hold the onscreen */
589 request = var->xres_virtual * (var->bits_per_pixel >> 3);
590 /* defaulty crtc->channel go with par->index */
591
45e3b3da 592 request = PADDING(crtc->line_pad, request);
81dee67e 593 request = request * var->yres_virtual;
5ace4e10 594 if (crtc->vidmem_size < request) {
81dee67e
SM
595 pr_err("not enough video memory for mode\n");
596 return -ENOMEM;
597 }
598
45e3b3da 599 ret = output->proc_checkMode(output, var);
5ace4e10 600 if (!ret)
45e3b3da 601 ret = crtc->proc_checkMode(crtc, var);
81dee67e
SM
602exit:
603 return ret;
604}
605
606
45e3b3da
MC
607static int lynxfb_ops_setcolreg(unsigned regno, unsigned red,
608 unsigned green, unsigned blue,
27fa159b 609 unsigned transp, struct fb_info *info)
81dee67e 610{
27fa159b
MC
611 struct lynxfb_par *par;
612 struct lynxfb_crtc *crtc;
613 struct fb_var_screeninfo *var;
c52c3700
MC
614 int ret;
615
616 par = info->par;
617 crtc = &par->crtc;
618 var = &info->var;
619 ret = 0;
620
621 //pr_debug("regno=%d,red=%d,green=%d,blue=%d\n",regno,red,green,blue);
5ace4e10 622 if (regno > 256) {
45e3b3da 623 pr_err("regno = %d\n", regno);
c52c3700
MC
624 return -EINVAL;
625 }
626
5ace4e10 627 if (info->var.grayscale)
c52c3700
MC
628 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
629
5ace4e10 630 if (var->bits_per_pixel == 8 && info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
c52c3700
MC
631 red >>= 8;
632 green >>= 8;
633 blue >>= 8;
45e3b3da 634 ret = crtc->proc_setColReg(crtc, regno, red, green, blue);
c52c3700
MC
635 goto exit;
636 }
637
638
5ace4e10 639 if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 256) {
c52c3700 640 u32 val;
5ace4e10 641 if (var->bits_per_pixel == 16 ||
c52c3700 642 var->bits_per_pixel == 32 ||
70407df7 643 var->bits_per_pixel == 24) {
45e3b3da
MC
644 val = chan_to_field(red, &var->red);
645 val |= chan_to_field(green, &var->green);
646 val |= chan_to_field(blue, &var->blue);
c52c3700
MC
647 par->pseudo_palette[regno] = val;
648 goto exit;
649 }
650 }
651
652 ret = -EINVAL;
81dee67e
SM
653
654exit:
c52c3700 655 return ret;
81dee67e
SM
656}
657
27fa159b 658static int lynxfb_ops_blank(int blank, struct fb_info *info)
81dee67e 659{
27fa159b
MC
660 struct lynxfb_par *par;
661 struct lynxfb_output *output;
c52c3700 662
45e3b3da 663 pr_debug("blank = %d.\n", blank);
81dee67e
SM
664 par = info->par;
665 output = &par->output;
45e3b3da 666 return output->proc_setBLANK(output, blank);
81dee67e
SM
667}
668
27fa159b 669static int sm750fb_set_drv(struct lynxfb_par *par)
81dee67e 670{
c52c3700 671 int ret;
27fa159b
MC
672 struct lynx_share *share;
673 struct sm750_share *spec_share;
674 struct lynxfb_output *output;
675 struct lynxfb_crtc *crtc;
c52c3700
MC
676
677 ret = 0;
678
679 share = par->share;
45e3b3da 680 spec_share = container_of(share, struct sm750_share, share);
c52c3700
MC
681 output = &par->output;
682 crtc = &par->crtc;
683
684 crtc->vidmem_size = (share->dual)?share->vidmem_size>>1:share->vidmem_size;
685 /* setup crtc and output member */
686 spec_share->hwCursor = g_hwcursor;
687
688 crtc->proc_setMode = hw_sm750_crtc_setMode;
689 crtc->proc_checkMode = hw_sm750_crtc_checkMode;
690 crtc->proc_setColReg = hw_sm750_setColReg;
691 crtc->proc_panDisplay = hw_sm750_pan_display;
692 crtc->clear = hw_sm750_crtc_clear;
693 crtc->line_pad = 16;
694 //crtc->xpanstep = crtc->ypanstep = crtc->ywrapstep = 0;
695 crtc->xpanstep = 8;
696 crtc->ypanstep = 1;
697 crtc->ywrapstep = 0;
698
699 output->proc_setMode = hw_sm750_output_setMode;
700 output->proc_checkMode = hw_sm750_output_checkMode;
701
702 output->proc_setBLANK = (share->revid == SM750LE_REVISION_ID)?hw_sm750le_setBLANK:hw_sm750_setBLANK;
703 output->clear = hw_sm750_output_clear;
704 /* chip specific phase */
705 share->accel.de_wait = (share->revid == SM750LE_REVISION_ID)?hw_sm750le_deWait: hw_sm750_deWait;
70407df7 706 switch (spec_share->state.dataflow) {
c52c3700
MC
707 case sm750_simul_pri:
708 output->paths = sm750_pnc;
709 crtc->channel = sm750_primary;
710 crtc->oScreen = 0;
711 crtc->vScreen = share->pvMem;
712 pr_info("use simul primary mode\n");
713 break;
714 case sm750_simul_sec:
715 output->paths = sm750_pnc;
716 crtc->channel = sm750_secondary;
717 crtc->oScreen = 0;
718 crtc->vScreen = share->pvMem;
719 break;
720 case sm750_dual_normal:
5ace4e10 721 if (par->index == 0) {
c52c3700
MC
722 output->paths = sm750_panel;
723 crtc->channel = sm750_primary;
724 crtc->oScreen = 0;
725 crtc->vScreen = share->pvMem;
5ace4e10 726 } else {
c52c3700
MC
727 output->paths = sm750_crt;
728 crtc->channel = sm750_secondary;
729 /* not consider of padding stuffs for oScreen,need fix*/
730 crtc->oScreen = (share->vidmem_size >> 1);
731 crtc->vScreen = share->pvMem + crtc->oScreen;
732 }
733 break;
734 case sm750_dual_swap:
5ace4e10 735 if (par->index == 0) {
c52c3700
MC
736 output->paths = sm750_panel;
737 crtc->channel = sm750_secondary;
738 crtc->oScreen = 0;
739 crtc->vScreen = share->pvMem;
5ace4e10 740 } else {
c52c3700
MC
741 output->paths = sm750_crt;
742 crtc->channel = sm750_primary;
743 /* not consider of padding stuffs for oScreen,need fix*/
744 crtc->oScreen = (share->vidmem_size >> 1);
745 crtc->vScreen = share->pvMem + crtc->oScreen;
746 }
747 break;
748 default:
749 ret = -EINVAL;
750 }
751
752 return ret;
81dee67e
SM
753}
754
755static struct fb_ops lynxfb_ops={
756 .owner = THIS_MODULE,
757 .fb_check_var = lynxfb_ops_check_var,
758 .fb_set_par = lynxfb_ops_set_par,
759 .fb_setcolreg = lynxfb_ops_setcolreg,
760 .fb_blank = lynxfb_ops_blank,
81dee67e
SM
761 .fb_fillrect = cfb_fillrect,
762 .fb_imageblit = cfb_imageblit,
763 .fb_copyarea = cfb_copyarea,
764 /* cursor */
765 .fb_cursor = lynxfb_ops_cursor,
766};
767
768
27fa159b 769static int lynxfb_set_fbinfo(struct fb_info *info, int index)
81dee67e 770{
c52c3700 771 int i;
27fa159b
MC
772 struct lynxfb_par *par;
773 struct lynx_share *share;
774 struct lynxfb_crtc *crtc;
775 struct lynxfb_output *output;
776 struct fb_var_screeninfo *var;
777 struct fb_fix_screeninfo *fix;
778
779 const struct fb_videomode *pdb[] = {
45e3b3da 780 lynx750_ext, NULL, vesa_modes,
c52c3700 781 };
45e3b3da 782 int cdb[] = {ARRAY_SIZE(lynx750_ext), 0, VESA_MODEDB_SIZE};
27fa159b 783 static const char *mdb_desc[] ={
c52c3700
MC
784 "driver prepared modes",
785 "kernel prepared default modedb",
786 "kernel HELPERS prepared vesa_modes",
787 };
788
789
27fa159b 790 static const char *fixId[2] = {
45e3b3da 791 "sm750_fb1", "sm750_fb2",
c52c3700
MC
792 };
793
45e3b3da 794 int ret, line_length;
c52c3700
MC
795
796 ret = 0;
797 par = (struct lynxfb_par *)info->par;
798 share = par->share;
799 crtc = &par->crtc;
800 output = &par->output;
801 var = &info->var;
802 fix = &info->fix;
803
804 /* set index */
805 par->index = index;
806 output->channel = &crtc->channel;
81dee67e 807 sm750fb_set_drv(par);
c52c3700
MC
808 lynxfb_ops.fb_pan_display = lynxfb_ops_pan_display;
809
810
811 /* set current cursor variable and proc pointer,
812 * must be set after crtc member initialized */
813 crtc->cursor.offset = crtc->oScreen + crtc->vidmem_size - 1024;
814 crtc->cursor.mmio = share->pvReg + 0x800f0 + (int)crtc->channel * 0x140;
815
45e3b3da 816 pr_info("crtc->cursor.mmio = %p\n", crtc->cursor.mmio);
c52c3700
MC
817 crtc->cursor.maxH = crtc->cursor.maxW = 64;
818 crtc->cursor.size = crtc->cursor.maxH*crtc->cursor.maxW*2/8;
819 crtc->cursor.disable = hw_cursor_disable;
820 crtc->cursor.enable = hw_cursor_enable;
821 crtc->cursor.setColor = hw_cursor_setColor;
822 crtc->cursor.setPos = hw_cursor_setPos;
823 crtc->cursor.setSize = hw_cursor_setSize;
824 crtc->cursor.setData = hw_cursor_setData;
825 crtc->cursor.vstart = share->pvMem + crtc->cursor.offset;
826
827
828 crtc->cursor.share = share;
829 memset_io(crtc->cursor.vstart, 0, crtc->cursor.size);
5ace4e10 830 if (!g_hwcursor) {
c52c3700
MC
831 lynxfb_ops.fb_cursor = NULL;
832 crtc->cursor.disable(&crtc->cursor);
833 }
834
835
836 /* set info->fbops, must be set before fb_find_mode */
5ace4e10 837 if (!share->accel_off) {
c52c3700
MC
838 /* use 2d acceleration */
839 lynxfb_ops.fb_fillrect = lynxfb_ops_fillrect;
840 lynxfb_ops.fb_copyarea = lynxfb_ops_copyarea;
841 lynxfb_ops.fb_imageblit = lynxfb_ops_imageblit;
842 }
843 info->fbops = &lynxfb_ops;
844
5ace4e10 845 if (!g_fbmode[index]) {
c52c3700 846 g_fbmode[index] = g_def_fbmode;
5ace4e10 847 if (index)
c52c3700
MC
848 g_fbmode[index] = g_fbmode[0];
849 }
81dee67e
SM
850
851
5ace4e10 852 for (i=0;i<3;i++) {
81dee67e 853
45e3b3da
MC
854 ret = fb_find_mode(var, info, g_fbmode[index],
855 pdb[i], cdb[i], NULL, 8);
81dee67e 856
5ace4e10 857 if (ret == 1) {
81dee67e 858 pr_info("success! use specified mode:%s in %s\n",
c52c3700
MC
859 g_fbmode[index],
860 mdb_desc[i]);
81dee67e 861 break;
5ace4e10 862 } else if (ret == 2) {
81dee67e 863 pr_warn("use specified mode:%s in %s,with an ignored refresh rate\n",
c52c3700
MC
864 g_fbmode[index],
865 mdb_desc[i]);
81dee67e 866 break;
5ace4e10 867 } else if (ret == 3) {
81dee67e 868 pr_warn("wanna use default mode\n");
c52c3700 869 // break;
5ace4e10 870 } else if (ret == 4) {
81dee67e 871 pr_warn("fall back to any valid mode\n");
5ace4e10 872 } else {
45e3b3da 873 pr_warn("ret = %d,fb_find_mode failed,with %s\n", ret, mdb_desc[i]);
81dee67e
SM
874 }
875 }
876
c52c3700
MC
877 /* some member of info->var had been set by fb_find_mode */
878
879 pr_info("Member of info->var is :\n\
880 xres=%d\n\
881 yres=%d\n\
882 xres_virtual=%d\n\
883 yres_virtual=%d\n\
884 xoffset=%d\n\
885 yoffset=%d\n\
886 bits_per_pixel=%d\n \
45e3b3da
MC
887 ...\n", var->xres, var->yres, var->xres_virtual, var->yres_virtual,
888 var->xoffset, var->yoffset, var->bits_per_pixel);
c52c3700
MC
889
890 /* set par */
891 par->info = info;
892
893 /* set info */
894 line_length = PADDING(crtc->line_pad,
895 (var->xres_virtual * var->bits_per_pixel/8));
896
897 info->pseudo_palette = &par->pseudo_palette[0];
898 info->screen_base = crtc->vScreen;
45e3b3da 899 pr_debug("screen_base vaddr = %p\n", info->screen_base);
81dee67e
SM
900 info->screen_size = line_length * var->yres_virtual;
901 info->flags = FBINFO_FLAG_DEFAULT|0;
902
c52c3700
MC
903 /* set info->fix */
904 fix->type = FB_TYPE_PACKED_PIXELS;
905 fix->type_aux = 0;
906 fix->xpanstep = crtc->xpanstep;
907 fix->ypanstep = crtc->ypanstep;
908 fix->ywrapstep = crtc->ywrapstep;
909 fix->accel = FB_ACCEL_SMI;
81dee67e 910
45e3b3da 911 strlcpy(fix->id, fixId[index], sizeof(fix->id));
81dee67e
SM
912
913
914 fix->smem_start = crtc->oScreen + share->vidmem_start;
45e3b3da 915 pr_info("fix->smem_start = %lx\n", fix->smem_start);
c52c3700
MC
916 /* according to mmap experiment from user space application,
917 * fix->mmio_len should not larger than virtual size
918 * (xres_virtual x yres_virtual x ByPP)
919 * Below line maybe buggy when user mmap fb dev node and write
920 * data into the bound over virtual size
921 * */
922 fix->smem_len = crtc->vidmem_size;
45e3b3da 923 pr_info("fix->smem_len = %x\n", fix->smem_len);
c52c3700
MC
924 info->screen_size = fix->smem_len;
925 fix->line_length = line_length;
926 fix->mmio_start = share->vidreg_start;
45e3b3da 927 pr_info("fix->mmio_start = %lx\n", fix->mmio_start);
c52c3700 928 fix->mmio_len = share->vidreg_size;
45e3b3da 929 pr_info("fix->mmio_len = %x\n", fix->mmio_len);
5ace4e10 930 switch (var->bits_per_pixel) {
c52c3700
MC
931 case 8:
932 fix->visual = FB_VISUAL_PSEUDOCOLOR;
933 break;
934 case 16:
935 case 32:
936 fix->visual = FB_VISUAL_TRUECOLOR;
937 break;
938 }
939
940 /* set var */
941 var->activate = FB_ACTIVATE_NOW;
942 var->accel_flags = 0;
943 var->vmode = FB_VMODE_NONINTERLACED;
944
945 pr_debug("#1 show info->cmap : \nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
45e3b3da
MC
946 info->cmap.start, info->cmap.len,
947 info->cmap.red, info->cmap.green, info->cmap.blue,
c52c3700
MC
948 info->cmap.transp);
949
5ace4e10 950 if ((ret = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) {
c52c3700
MC
951 pr_err("Could not allcate memory for cmap.\n");
952 goto exit;
953 }
954
955 pr_debug("#2 show info->cmap : \nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
45e3b3da
MC
956 info->cmap.start, info->cmap.len,
957 info->cmap.red, info->cmap.green, info->cmap.blue,
c52c3700 958 info->cmap.transp);
81dee67e
SM
959
960exit:
45e3b3da 961 lynxfb_ops_check_var(var, info);
c52c3700
MC
962 // lynxfb_ops_set_par(info);
963 return ret;
81dee67e
SM
964}
965
c52c3700 966/* chip specific g_option configuration routine */
27fa159b 967static void sm750fb_setup(struct lynx_share *share, char *src)
81dee67e 968{
27fa159b
MC
969 struct sm750_share *spec_share;
970 char *opt;
81dee67e 971#ifdef CAP_EXPENSION
27fa159b 972 char *exp_res;
81dee67e
SM
973#endif
974 int swap;
c52c3700 975
81dee67e 976
45e3b3da 977 spec_share = container_of(share, struct sm750_share, share);
81dee67e 978#ifdef CAP_EXPENSIION
c52c3700 979 exp_res = NULL;
81dee67e 980#endif
c52c3700
MC
981 swap = 0;
982
983 spec_share->state.initParm.chip_clk = 0;
984 spec_share->state.initParm.mem_clk = 0;
985 spec_share->state.initParm.master_clk = 0;
986 spec_share->state.initParm.powerMode = 0;
987 spec_share->state.initParm.setAllEngOff = 0;
988 spec_share->state.initParm.resetMemory = 1;
989
990 /*defaultly turn g_hwcursor on for both view */
991 g_hwcursor = 3;
992
5ace4e10 993 if (!src || !*src) {
c52c3700
MC
994 pr_warn("no specific g_option.\n");
995 goto NO_PARAM;
996 }
997
5ace4e10 998 while ((opt = strsep(&src, ":")) != NULL && *opt != 0) {
45e3b3da
MC
999 pr_err("opt=%s\n", opt);
1000 pr_err("src=%s\n", src);
c52c3700 1001
5ace4e10 1002 if (!strncmp(opt, "swap", strlen("swap")))
c52c3700 1003 swap = 1;
5ace4e10 1004 else if (!strncmp(opt, "nocrt", strlen("nocrt")))
c52c3700 1005 spec_share->state.nocrt = 1;
5ace4e10 1006 else if (!strncmp(opt, "36bit", strlen("36bit")))
c52c3700 1007 spec_share->state.pnltype = sm750_doubleTFT;
5ace4e10 1008 else if (!strncmp(opt, "18bit", strlen("18bit")))
c52c3700 1009 spec_share->state.pnltype = sm750_dualTFT;
5ace4e10 1010 else if (!strncmp(opt, "24bit", strlen("24bit")))
c52c3700 1011 spec_share->state.pnltype = sm750_24TFT;
81dee67e 1012#ifdef CAP_EXPANSION
5ace4e10 1013 else if (!strncmp(opt, "exp:", strlen("exp:")))
c52c3700 1014 exp_res = opt + strlen("exp:");
81dee67e 1015#endif
5ace4e10 1016 else if (!strncmp(opt, "nohwc0", strlen("nohwc0")))
c52c3700 1017 g_hwcursor &= ~0x1;
5ace4e10 1018 else if (!strncmp(opt, "nohwc1", strlen("nohwc1")))
c52c3700 1019 g_hwcursor &= ~0x2;
5ace4e10 1020 else if (!strncmp(opt, "nohwc", strlen("nohwc")))
c52c3700 1021 g_hwcursor = 0;
70407df7 1022 else {
5ace4e10 1023 if (!g_fbmode[0]) {
c52c3700 1024 g_fbmode[0] = opt;
45e3b3da 1025 pr_info("find fbmode0 : %s\n", g_fbmode[0]);
5ace4e10 1026 } else if (!g_fbmode[1]) {
c52c3700 1027 g_fbmode[1] = opt;
45e3b3da 1028 pr_info("find fbmode1 : %s\n", g_fbmode[1]);
5ace4e10 1029 } else {
c52c3700
MC
1030 pr_warn("How many view you wann set?\n");
1031 }
1032 }
1033 }
81dee67e 1034#ifdef CAP_EXPANSION
5ace4e10 1035 if (getExpRes(exp_res, &spec_share->state.xLCD, &spec_share->state.yLCD)) {
c52c3700
MC
1036 /* seems exp_res is not valid*/
1037 spec_share->state.xLCD = spec_share->state.yLCD = 0;
1038 }
81dee67e
SM
1039#endif
1040
1041NO_PARAM:
5ace4e10
MC
1042 if (share->revid != SM750LE_REVISION_ID) {
1043 if (share->dual) {
1044 if (swap)
c52c3700
MC
1045 spec_share->state.dataflow = sm750_dual_swap;
1046 else
1047 spec_share->state.dataflow = sm750_dual_normal;
5ace4e10
MC
1048 } else {
1049 if (swap)
c52c3700
MC
1050 spec_share->state.dataflow = sm750_simul_sec;
1051 else
1052 spec_share->state.dataflow = sm750_simul_pri;
1053 }
5ace4e10 1054 } else {
c52c3700
MC
1055 /* SM750LE only have one crt channel */
1056 spec_share->state.dataflow = sm750_simul_sec;
1057 /* sm750le do not have complex attributes*/
1058 spec_share->state.nocrt = 0;
1059 }
81dee67e
SM
1060}
1061
27fa159b 1062static int lynxfb_pci_probe(struct pci_dev *pdev,
c52c3700 1063 const struct pci_device_id * ent)
81dee67e 1064{
27fa159b
MC
1065 struct fb_info *info[] = {NULL, NULL};
1066 struct lynx_share *share = NULL;
81dee67e
SM
1067
1068 struct sm750_share *spec_share = NULL;
1069 size_t spec_offset = 0;
1070 int fbidx;
c52c3700 1071
81dee67e
SM
1072
1073 /* enable device */
5ace4e10 1074 if (pci_enable_device(pdev)) {
81dee67e
SM
1075 pr_err("can not enable device.\n");
1076 goto err_enable;
1077 }
1078
1079 /* though offset of share in sm750_share is 0,
1080 * we use this marcro as the same */
45e3b3da 1081 spec_offset = offsetof(struct sm750_share, share);
81dee67e 1082
45e3b3da 1083 spec_share = kzalloc(sizeof(*spec_share), GFP_KERNEL);
5ace4e10 1084 if (!spec_share) {
81dee67e
SM
1085 pr_err("Could not allocate memory for share.\n");
1086 goto err_share;
1087 }
1088
1089 /* setting share structure */
5ace4e10 1090 share = (struct lynx_share *)(&(spec_share->share));
81dee67e
SM
1091 share->fbinfo[0] = share->fbinfo[1] = NULL;
1092 share->devid = pdev->device;
1093 share->revid = pdev->revision;
1094
45e3b3da 1095 pr_info("share->revid = %02x\n", share->revid);
81dee67e
SM
1096 share->pdev = pdev;
1097#ifdef CONFIG_MTRR
1098 share->mtrr_off = g_nomtrr;
1099 share->mtrr.vram = 0;
1100 share->mtrr.vram_added = 0;
1101#endif
1102 share->accel_off = g_noaccel;
1103 share->dual = g_dualview;
1104 spin_lock_init(&share->slock);
1105
5ace4e10 1106 if (!share->accel_off) {
81dee67e
SM
1107 /* hook deInit and 2d routines, notes that below hw_xxx
1108 * routine can work on most of lynx chips
1109 * if some chip need specific function,please hook it in smXXX_set_drv
1110 * routine */
1111 share->accel.de_init = hw_de_init;
1112 share->accel.de_fillrect = hw_fillrect;
1113 share->accel.de_copyarea = hw_copyarea;
1114 share->accel.de_imageblit = hw_imageblit;
1115 pr_info("enable 2d acceleration\n");
5ace4e10 1116 } else {
81dee67e
SM
1117 pr_info("disable 2d acceleration\n");
1118 }
1119
1120 /* call chip specific setup routine */
45e3b3da 1121 sm750fb_setup(share, g_settings);
81dee67e
SM
1122
1123 /* call chip specific mmap routine */
5ace4e10 1124 if (hw_sm750_map(share, pdev)) {
81dee67e
SM
1125 pr_err("Memory map failed\n");
1126 goto err_map;
1127 }
1128
1129#ifdef CONFIG_MTRR
5ace4e10 1130 if (!share->mtrr_off) {
81dee67e
SM
1131 pr_info("enable mtrr\n");
1132 share->mtrr.vram = mtrr_add(share->vidmem_start,
c52c3700 1133 share->vidmem_size,
45e3b3da 1134 MTRR_TYPE_WRCOMB, 1);
81dee67e 1135
5ace4e10 1136 if (share->mtrr.vram < 0) {
81dee67e
SM
1137 /* don't block driver with the failure of MTRR */
1138 pr_err("Unable to setup MTRR.\n");
5ace4e10 1139 } else {
81dee67e
SM
1140 share->mtrr.vram_added = 1;
1141 pr_info("MTRR added succesfully\n");
1142 }
1143 }
1144#endif
1145
3de08a2d 1146 memset_io(share->pvMem, 0, share->vidmem_size);
81dee67e 1147
45e3b3da 1148 pr_info("sm%3x mmio address = %p\n", share->devid, share->pvReg);
81dee67e 1149
45e3b3da 1150 pci_set_drvdata(pdev, share);
81dee67e
SM
1151
1152 /* call chipInit routine */
45e3b3da 1153 hw_sm750_inithw(share, pdev);
81dee67e
SM
1154
1155 /* allocate frame buffer info structor according to g_dualview */
c52c3700 1156 fbidx = 0;
81dee67e 1157ALLOC_FB:
45e3b3da 1158 info[fbidx] = framebuffer_alloc(sizeof(struct lynxfb_par), &pdev->dev);
5ace4e10 1159 if (!info[fbidx]) {
45e3b3da 1160 pr_err("Could not allocate framebuffer #%d.\n", fbidx);
5ace4e10 1161 if (fbidx == 0)
c52c3700
MC
1162 goto err_info0_alloc;
1163 else
1164 goto err_info1_alloc;
70407df7 1165 } else {
27fa159b 1166 struct lynxfb_par *par;
c52c3700 1167 int errno;
45e3b3da 1168 pr_info("framebuffer #%d alloc okay\n", fbidx);
c52c3700
MC
1169 share->fbinfo[fbidx] = info[fbidx];
1170 par = info[fbidx]->par;
1171 par->share = share;
1172
1173 /* set fb_info structure */
5ace4e10 1174 if (lynxfb_set_fbinfo(info[fbidx], fbidx)) {
45e3b3da 1175 pr_err("Failed to initial fb_info #%d.\n", fbidx);
5ace4e10 1176 if (fbidx == 0)
c52c3700 1177 goto err_info0_set;
81dee67e 1178 else
c52c3700 1179 goto err_info1_set;
81dee67e 1180 }
81dee67e 1181
c52c3700 1182 /* register frame buffer*/
45e3b3da 1183 pr_info("Ready to register framebuffer #%d.\n", fbidx);
c52c3700
MC
1184 errno = register_framebuffer(info[fbidx]);
1185 if (errno < 0) {
45e3b3da 1186 pr_err("Failed to register fb_info #%d. err %d\n", fbidx, errno);
5ace4e10 1187 if (fbidx == 0)
c52c3700
MC
1188 goto err_register0;
1189 else
1190 goto err_register1;
81dee67e 1191 }
45e3b3da 1192 pr_info("Accomplished register framebuffer #%d.\n", fbidx);
c52c3700 1193 }
81dee67e 1194
c52c3700
MC
1195 /* no dual view by far */
1196 fbidx++;
5ace4e10 1197 if (share->dual && fbidx < 2)
c52c3700 1198 goto ALLOC_FB;
81dee67e
SM
1199
1200 return 0;
1201
1202err_register1:
1203err_info1_set:
1204 framebuffer_release(info[1]);
1205err_info1_alloc:
1206 unregister_framebuffer(info[0]);
1207err_register0:
1208err_info0_set:
1209 framebuffer_release(info[0]);
1210err_info0_alloc:
1211err_map:
1212 kfree(spec_share);
1213err_share:
1214err_enable:
1215 return -ENODEV;
1216}
1217
27fa159b 1218static void __exit lynxfb_pci_remove(struct pci_dev *pdev)
81dee67e 1219{
27fa159b
MC
1220 struct fb_info *info;
1221 struct lynx_share *share;
1222 void *spec_share;
1223 struct lynxfb_par *par;
81dee67e
SM
1224 int cnt;
1225
1226 cnt = 2;
1227 share = pci_get_drvdata(pdev);
1228
5ace4e10 1229 while (cnt-- > 0) {
81dee67e 1230 info = share->fbinfo[cnt];
5ace4e10 1231 if (!info)
81dee67e
SM
1232 continue;
1233 par = info->par;
1234
1235 unregister_framebuffer(info);
1236 /* clean crtc & output allocations*/
1237 par->crtc.clear(&par->crtc);
1238 par->output.clear(&par->output);
1239 /* release frame buffer*/
1240 framebuffer_release(info);
1241 }
1242#ifdef CONFIG_MTRR
5ace4e10 1243 if (share->mtrr.vram_added)
45e3b3da 1244 mtrr_del(share->mtrr.vram, share->vidmem_start, share->vidmem_size);
81dee67e
SM
1245#endif
1246 // pci_release_regions(pdev);
1247
1248 iounmap(share->pvReg);
1249 iounmap(share->pvMem);
45e3b3da 1250 spec_share = container_of(share, struct sm750_share, share);
81dee67e
SM
1251 kfree(g_settings);
1252 kfree(spec_share);
45e3b3da 1253 pci_set_drvdata(pdev, NULL);
81dee67e
SM
1254}
1255
27fa159b 1256static int __init lynxfb_setup(char *options)
81dee67e
SM
1257{
1258 int len;
27fa159b 1259 char *opt, *tmp;
c52c3700 1260
81dee67e 1261
5ace4e10 1262 if (!options || !*options) {
81dee67e
SM
1263 pr_warn("no options.\n");
1264 return 0;
1265 }
1266
45e3b3da 1267 pr_info("options:%s\n", options);
81dee67e
SM
1268
1269 len = strlen(options) + 1;
a99e334d 1270 g_settings = kzalloc(len, GFP_KERNEL);
5ace4e10 1271 if (!g_settings)
81dee67e
SM
1272 return -ENOMEM;
1273
81dee67e
SM
1274 tmp = g_settings;
1275
c52c3700 1276 /* Notes:
81dee67e
SM
1277 char * strsep(char **s,const char * ct);
1278 @s: the string to be searched
1279 @ct :the characters to search for
1280
1281 strsep() updates @options to pointer after the first found token
1282 it also returns the pointer ahead the token.
1283 */
5ace4e10 1284 while ((opt = strsep(&options, ":"))!=NULL) {
81dee67e 1285 /* options that mean for any lynx chips are configured here */
5ace4e10 1286 if (!strncmp(opt, "noaccel", strlen("noaccel")))
81dee67e
SM
1287 g_noaccel = 1;
1288#ifdef CONFIG_MTRR
5ace4e10 1289 else if (!strncmp(opt, "nomtrr", strlen("nomtrr")))
81dee67e
SM
1290 g_nomtrr = 1;
1291#endif
5ace4e10 1292 else if (!strncmp(opt, "dual", strlen("dual")))
81dee67e 1293 g_dualview = 1;
70407df7 1294 else {
45e3b3da 1295 strcat(tmp, opt);
81dee67e 1296 tmp += strlen(opt);
5ace4e10 1297 if (options != NULL)
81dee67e
SM
1298 *tmp++ = ':';
1299 else
1300 *tmp++ = 0;
1301 }
1302 }
1303
1304 /* misc g_settings are transport to chip specific routines */
45e3b3da 1305 pr_info("parameter left for chip specific analysis:%s\n", g_settings);
81dee67e
SM
1306 return 0;
1307}
1308
1309static struct pci_device_id smi_pci_table[] = {
1310 { PCI_DEVICE(0x126f, 0x0750), },
1311 {0,}
1312};
1313
45e3b3da 1314MODULE_DEVICE_TABLE(pci, smi_pci_table);
81dee67e
SM
1315
1316static struct pci_driver lynxfb_driver = {
1317 .name = "sm750fb",
1318 .id_table = smi_pci_table,
1319 .probe = lynxfb_pci_probe,
1320 .remove = lynxfb_pci_remove,
1321#ifdef CONFIG_PM
1322 .suspend = lynxfb_suspend,
1323 .resume = lynxfb_resume,
1324#endif
1325};
1326
1327
1328static int __init lynxfb_init(void)
1329{
1330 char *option ;
1331 int ret;
1332
1333#ifdef MODULE
1334 option = g_option;
1335#else
5ace4e10 1336 if (fb_get_options("sm750fb", &option))
81dee67e
SM
1337 return -ENODEV;
1338#endif
1339
1340 lynxfb_setup(option);
1341 ret = pci_register_driver(&lynxfb_driver);
1342 return ret;
1343}
1344module_init(lynxfb_init);
1345
1346static void __exit lynxfb_exit(void)
1347{
1348 pci_unregister_driver(&lynxfb_driver);
1349}
1350module_exit(lynxfb_exit);
1351
45e3b3da 1352module_param(g_option, charp, S_IRUGO);
81dee67e
SM
1353
1354MODULE_PARM_DESC(g_option,
c52c3700
MC
1355 "\n\t\tCommon options:\n"
1356 "\t\tnoaccel:disable 2d capabilities\n"
1357 "\t\tnomtrr:disable MTRR attribute for video memory\n"
1358 "\t\tdualview:dual frame buffer feature enabled\n"
1359 "\t\tnohwc:disable hardware cursor\n"
1360 "\t\tUsual example:\n"
1361 "\t\tinsmod ./sm750fb.ko g_option=\"noaccel,nohwc,1280x1024-8@60\"\n"
1362 );
81dee67e
SM
1363
1364MODULE_AUTHOR("monk liu <monk.liu@siliconmotion.com>");
1365MODULE_AUTHOR("Sudip Mukherjee <sudip@vectorindia.org>");
1366MODULE_DESCRIPTION("Frame buffer driver for SM750 chipset");
1367MODULE_LICENSE("GPL v2");