]> git.karo-electronics.de Git - linux-beck.git/blob - drivers/staging/sm750fb/sm750_hw.c
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux-beck.git] / drivers / staging / sm750fb / sm750_hw.c
1 #include <linux/module.h>
2 #include <linux/kernel.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/vmalloc.h>
13 #include <linux/pagemap.h>
14 #include <linux/console.h>
15 #ifdef CONFIG_MTRR
16 #include <asm/mtrr.h>
17 #endif
18 #include <linux/platform_device.h>
19 #include <linux/screen_info.h>
20 #include <linux/sizes.h>
21
22 #include "sm750.h"
23 #include "ddk750.h"
24 #include "sm750_accel.h"
25
26 int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
27 {
28         int ret;
29
30         ret = 0;
31
32         sm750_dev->vidreg_start  = pci_resource_start(pdev, 1);
33         sm750_dev->vidreg_size = SZ_2M;
34
35         pr_info("mmio phyAddr = %lx\n", sm750_dev->vidreg_start);
36
37         /* reserve the vidreg space of smi adaptor
38          * if you do this, u need to add release region code
39          * in lynxfb_remove, or memory will not be mapped again
40          * successfully
41          * */
42         ret = pci_request_region(pdev, 1, "sm750fb");
43         if (ret) {
44                 pr_err("Can not request PCI regions.\n");
45                 goto exit;
46         }
47
48         /* now map mmio and vidmem*/
49         sm750_dev->pvReg = ioremap_nocache(sm750_dev->vidreg_start,
50                                            sm750_dev->vidreg_size);
51         if (!sm750_dev->pvReg) {
52                 pr_err("mmio failed\n");
53                 ret = -EFAULT;
54                 goto exit;
55         } else {
56                 pr_info("mmio virtual addr = %p\n", sm750_dev->pvReg);
57         }
58
59
60         sm750_dev->accel.dprBase = sm750_dev->pvReg + DE_BASE_ADDR_TYPE1;
61         sm750_dev->accel.dpPortBase = sm750_dev->pvReg + DE_PORT_ADDR_TYPE1;
62
63         ddk750_set_mmio(sm750_dev->pvReg, sm750_dev->devid, sm750_dev->revid);
64
65         sm750_dev->vidmem_start = pci_resource_start(pdev, 0);
66         /* don't use pdev_resource[x].end - resource[x].start to
67          * calculate the resource size,its only the maximum available
68          * size but not the actual size,use
69          * @ddk750_getVMSize function can be safe.
70          * */
71         sm750_dev->vidmem_size = ddk750_getVMSize();
72         pr_info("video memory phyAddr = %lx, size = %u bytes\n",
73                 sm750_dev->vidmem_start, sm750_dev->vidmem_size);
74
75         /* reserve the vidmem space of smi adaptor */
76         sm750_dev->pvMem = ioremap_wc(sm750_dev->vidmem_start,
77                                       sm750_dev->vidmem_size);
78         if (!sm750_dev->pvMem) {
79                 pr_err("Map video memory failed\n");
80                 ret = -EFAULT;
81                 goto exit;
82         } else {
83                 pr_info("video memory vaddr = %p\n", sm750_dev->pvMem);
84         }
85 exit:
86         return ret;
87 }
88
89
90
91 int hw_sm750_inithw(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
92 {
93         struct init_status *parm;
94
95         parm = &sm750_dev->initParm;
96         if (parm->chip_clk == 0)
97                 parm->chip_clk = (getChipType() == SM750LE) ?
98                                                 DEFAULT_SM750LE_CHIP_CLOCK :
99                                                 DEFAULT_SM750_CHIP_CLOCK;
100
101         if (parm->mem_clk == 0)
102                 parm->mem_clk = parm->chip_clk;
103         if (parm->master_clk == 0)
104                 parm->master_clk = parm->chip_clk/3;
105
106         ddk750_initHw((initchip_param_t *)&sm750_dev->initParm);
107         /* for sm718,open pci burst */
108         if (sm750_dev->devid == 0x718) {
109                 POKE32(SYSTEM_CTRL,
110                        PEEK32(SYSTEM_CTRL) | SYSTEM_CTRL_PCI_BURST);
111         }
112
113         if (getChipType() != SM750LE) {
114                 unsigned int val;
115                 /* does user need CRT ?*/
116                 if (sm750_dev->nocrt) {
117                         POKE32(MISC_CTRL,
118                                PEEK32(MISC_CTRL) | MISC_CTRL_DAC_POWER_OFF);
119                         /* shut off dpms */
120                         val = PEEK32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
121                         val |= SYSTEM_CTRL_DPMS_VPHN;
122                         POKE32(SYSTEM_CTRL, val);
123                 } else {
124                         POKE32(MISC_CTRL,
125                                PEEK32(MISC_CTRL) & ~MISC_CTRL_DAC_POWER_OFF);
126                         /* turn on dpms */
127                         val = PEEK32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
128                         val |= SYSTEM_CTRL_DPMS_VPHP;
129                         POKE32(SYSTEM_CTRL, val);
130                 }
131
132                 val = PEEK32(PANEL_DISPLAY_CTRL) &
133                         ~(PANEL_DISPLAY_CTRL_DUAL_DISPLAY |
134                           PANEL_DISPLAY_CTRL_DOUBLE_PIXEL);
135                 switch (sm750_dev->pnltype) {
136                 case sm750_24TFT:
137                         break;
138                 case sm750_doubleTFT:
139                         val |= PANEL_DISPLAY_CTRL_DOUBLE_PIXEL;
140                         break;
141                 case sm750_dualTFT:
142                         val |= PANEL_DISPLAY_CTRL_DUAL_DISPLAY;
143                         break;
144                 }
145                 POKE32(PANEL_DISPLAY_CTRL, val);
146         } else {
147                 /* for 750LE ,no DVI chip initialization makes Monitor no signal */
148                 /* Set up GPIO for software I2C to program DVI chip in the
149                    Xilinx SP605 board, in order to have video signal.
150                  */
151                 sm750_sw_i2c_init(0, 1);
152
153                 /* Customer may NOT use CH7301 DVI chip, which has to be
154                 initialized differently.
155                 */
156                 if (sm750_sw_i2c_read_reg(0xec, 0x4a) == 0x95) {
157                 /* The following register values for CH7301 are from
158                    Chrontel app note and our experiment.
159                 */
160                         pr_info("yes,CH7301 DVI chip found\n");
161                         sm750_sw_i2c_write_reg(0xec, 0x1d, 0x16);
162                         sm750_sw_i2c_write_reg(0xec, 0x21, 0x9);
163                         sm750_sw_i2c_write_reg(0xec, 0x49, 0xC0);
164                         pr_info("okay,CH7301 DVI chip setup done\n");
165                 }
166         }
167
168         /* init 2d engine */
169         if (!sm750_dev->accel_off)
170                 hw_sm750_initAccel(sm750_dev);
171
172         return 0;
173 }
174
175 int hw_sm750_output_setMode(struct lynxfb_output *output,
176                                                                         struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix)
177 {
178         int ret;
179         disp_output_t dispSet;
180         int channel;
181
182         ret = 0;
183         dispSet = 0;
184         channel = *output->channel;
185
186
187         if (getChipType() != SM750LE) {
188                 if (channel == sm750_primary) {
189                         pr_info("primary channel\n");
190                         if (output->paths & sm750_panel)
191                                 dispSet |= do_LCD1_PRI;
192                         if (output->paths & sm750_crt)
193                                 dispSet |= do_CRT_PRI;
194
195                 } else {
196                         pr_info("secondary channel\n");
197                         if (output->paths & sm750_panel)
198                                 dispSet |= do_LCD1_SEC;
199                         if (output->paths & sm750_crt)
200                                 dispSet |= do_CRT_SEC;
201
202                 }
203                 ddk750_setLogicalDispOut(dispSet);
204         } else {
205                 /* just open DISPLAY_CONTROL_750LE register bit 3:0*/
206                 u32 reg;
207
208                 reg = PEEK32(DISPLAY_CONTROL_750LE);
209                 reg |= 0xf;
210                 POKE32(DISPLAY_CONTROL_750LE, reg);
211         }
212
213         pr_info("ddk setlogicdispout done\n");
214         return ret;
215 }
216
217 int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc, struct fb_var_screeninfo *var)
218 {
219         struct sm750_dev *sm750_dev;
220         struct lynxfb_par *par = container_of(crtc, struct lynxfb_par, crtc);
221
222         sm750_dev = par->dev;
223
224         switch (var->bits_per_pixel) {
225         case 8:
226         case 16:
227                 break;
228         case 32:
229                 if (sm750_dev->revid == SM750LE_REVISION_ID) {
230                         pr_debug("750le do not support 32bpp\n");
231                         return -EINVAL;
232                 }
233                 break;
234         default:
235                 return -EINVAL;
236
237         }
238
239         return 0;
240 }
241
242
243 /*
244         set the controller's mode for @crtc charged with @var and @fix parameters
245 */
246 int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc,
247                                                                 struct fb_var_screeninfo *var,
248                                                                 struct fb_fix_screeninfo *fix)
249 {
250         int ret, fmt;
251         u32 reg;
252         mode_parameter_t modparm;
253         clock_type_t clock;
254         struct sm750_dev *sm750_dev;
255         struct lynxfb_par *par;
256
257
258         ret = 0;
259         par = container_of(crtc, struct lynxfb_par, crtc);
260         sm750_dev = par->dev;
261
262         if (!sm750_dev->accel_off) {
263                 /* set 2d engine pixel format according to mode bpp */
264                 switch (var->bits_per_pixel) {
265                 case 8:
266                         fmt = 0;
267                         break;
268                 case 16:
269                         fmt = 1;
270                         break;
271                 case 32:
272                 default:
273                         fmt = 2;
274                         break;
275                 }
276                 hw_set2dformat(&sm750_dev->accel, fmt);
277         }
278
279         /* set timing */
280         modparm.pixel_clock = ps_to_hz(var->pixclock);
281         modparm.vertical_sync_polarity = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? POS:NEG;
282         modparm.horizontal_sync_polarity = (var->sync & FB_SYNC_VERT_HIGH_ACT) ? POS:NEG;
283         modparm.clock_phase_polarity = (var->sync & FB_SYNC_COMP_HIGH_ACT) ? POS:NEG;
284         modparm.horizontal_display_end = var->xres;
285         modparm.horizontal_sync_width = var->hsync_len;
286         modparm.horizontal_sync_start = var->xres + var->right_margin;
287         modparm.horizontal_total = var->xres + var->left_margin + var->right_margin + var->hsync_len;
288         modparm.vertical_display_end = var->yres;
289         modparm.vertical_sync_height = var->vsync_len;
290         modparm.vertical_sync_start = var->yres + var->lower_margin;
291         modparm.vertical_total = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
292
293         /* choose pll */
294         if (crtc->channel != sm750_secondary)
295                 clock = PRIMARY_PLL;
296         else
297                 clock = SECONDARY_PLL;
298
299         pr_debug("Request pixel clock = %lu\n", modparm.pixel_clock);
300         ret = ddk750_setModeTiming(&modparm, clock);
301         if (ret) {
302                 pr_err("Set mode timing failed\n");
303                 goto exit;
304         }
305
306         if (crtc->channel != sm750_secondary) {
307                 /* set pitch, offset ,width,start address ,etc... */
308                 POKE32(PANEL_FB_ADDRESS,
309                        crtc->oScreen & PANEL_FB_ADDRESS_ADDRESS_MASK);
310
311                 reg = var->xres * (var->bits_per_pixel >> 3);
312                 /* crtc->channel is not equal to par->index on numeric,be aware of that */
313                 reg = ALIGN(reg, crtc->line_pad);
314                 reg = (reg << PANEL_FB_WIDTH_WIDTH_SHIFT) &
315                        PANEL_FB_WIDTH_WIDTH_MASK;
316                 reg |= (fix->line_length & PANEL_FB_WIDTH_OFFSET_MASK);
317                 POKE32(PANEL_FB_WIDTH, reg);
318
319                 reg = ((var->xres - 1) << PANEL_WINDOW_WIDTH_WIDTH_SHIFT) &
320                        PANEL_WINDOW_WIDTH_WIDTH_MASK;
321                 reg |= (var->xoffset & PANEL_WINDOW_WIDTH_X_MASK);
322                 POKE32(PANEL_WINDOW_WIDTH, reg);
323
324                 reg = ((var->yres_virtual - 1) <<
325                        PANEL_WINDOW_HEIGHT_HEIGHT_SHIFT);
326                 reg &= PANEL_WINDOW_HEIGHT_HEIGHT_MASK;
327                 reg |= (var->yoffset & PANEL_WINDOW_HEIGHT_Y_MASK);
328                 POKE32(PANEL_WINDOW_HEIGHT, reg);
329
330                 POKE32(PANEL_PLANE_TL, 0);
331
332                 reg = ((var->yres - 1) << PANEL_PLANE_BR_BOTTOM_SHIFT) &
333                        PANEL_PLANE_BR_BOTTOM_MASK;
334                 reg |= ((var->xres - 1) & PANEL_PLANE_BR_RIGHT_MASK);
335                 POKE32(PANEL_PLANE_BR, reg);
336
337                 /* set pixel format */
338                 reg = PEEK32(PANEL_DISPLAY_CTRL);
339                 POKE32(PANEL_DISPLAY_CTRL, reg | (var->bits_per_pixel >> 4));
340         } else {
341                 /* not implemented now */
342                 POKE32(CRT_FB_ADDRESS, crtc->oScreen);
343                 reg = var->xres * (var->bits_per_pixel >> 3);
344                 /* crtc->channel is not equal to par->index on numeric,be aware of that */
345                 reg = ALIGN(reg, crtc->line_pad) << CRT_FB_WIDTH_WIDTH_SHIFT;
346                 reg &= CRT_FB_WIDTH_WIDTH_MASK;
347                 reg |= (fix->line_length & CRT_FB_WIDTH_OFFSET_MASK);
348                 POKE32(CRT_FB_WIDTH, reg);
349
350                 /* SET PIXEL FORMAT */
351                 reg = PEEK32(CRT_DISPLAY_CTRL);
352                 reg |= ((var->bits_per_pixel >> 4) &
353                         CRT_DISPLAY_CTRL_FORMAT_MASK);
354                 POKE32(CRT_DISPLAY_CTRL, reg);
355
356         }
357
358
359 exit:
360         return ret;
361 }
362
363 int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index,
364                                                                 ushort red, ushort green, ushort blue)
365 {
366         static unsigned int add[] = {PANEL_PALETTE_RAM, CRT_PALETTE_RAM};
367
368         POKE32(add[crtc->channel] + index*4, (red<<16)|(green<<8)|blue);
369         return 0;
370 }
371
372 int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank)
373 {
374         int dpms, crtdb;
375
376         switch (blank) {
377         case FB_BLANK_UNBLANK:
378                 dpms = CRT_DISPLAY_CTRL_DPMS_0;
379                 crtdb = 0;
380                 break;
381         case FB_BLANK_NORMAL:
382                 dpms = CRT_DISPLAY_CTRL_DPMS_0;
383                 crtdb = CRT_DISPLAY_CTRL_BLANK;
384                 break;
385         case FB_BLANK_VSYNC_SUSPEND:
386                 dpms = CRT_DISPLAY_CTRL_DPMS_2;
387                 crtdb = CRT_DISPLAY_CTRL_BLANK;
388                 break;
389         case FB_BLANK_HSYNC_SUSPEND:
390                 dpms = CRT_DISPLAY_CTRL_DPMS_1;
391                 crtdb = CRT_DISPLAY_CTRL_BLANK;
392                 break;
393         case FB_BLANK_POWERDOWN:
394                 dpms = CRT_DISPLAY_CTRL_DPMS_3;
395                 crtdb = CRT_DISPLAY_CTRL_BLANK;
396                 break;
397         default:
398                 return -EINVAL;
399         }
400
401         if (output->paths & sm750_crt) {
402                 unsigned int val;
403
404                 val = PEEK32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_DPMS_MASK;
405                 POKE32(CRT_DISPLAY_CTRL, val | dpms);
406
407                 val = PEEK32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
408                 POKE32(CRT_DISPLAY_CTRL, val | crtdb);
409         }
410         return 0;
411 }
412
413 int hw_sm750_setBLANK(struct lynxfb_output *output, int blank)
414 {
415         unsigned int dpms, pps, crtdb;
416
417         dpms = pps = crtdb = 0;
418
419         switch (blank) {
420         case FB_BLANK_UNBLANK:
421                 pr_debug("flag = FB_BLANK_UNBLANK\n");
422                 dpms = SYSTEM_CTRL_DPMS_VPHP;
423                 pps = PANEL_DISPLAY_CTRL_DATA;
424                 break;
425         case FB_BLANK_NORMAL:
426                 pr_debug("flag = FB_BLANK_NORMAL\n");
427                 dpms = SYSTEM_CTRL_DPMS_VPHP;
428                 crtdb = CRT_DISPLAY_CTRL_BLANK;
429                 break;
430         case FB_BLANK_VSYNC_SUSPEND:
431                 dpms = SYSTEM_CTRL_DPMS_VNHP;
432                 crtdb = CRT_DISPLAY_CTRL_BLANK;
433                 break;
434         case FB_BLANK_HSYNC_SUSPEND:
435                 dpms = SYSTEM_CTRL_DPMS_VPHN;
436                 crtdb = CRT_DISPLAY_CTRL_BLANK;
437                 break;
438         case FB_BLANK_POWERDOWN:
439                 dpms = SYSTEM_CTRL_DPMS_VNHN;
440                 crtdb = CRT_DISPLAY_CTRL_BLANK;
441                 break;
442         }
443
444         if (output->paths & sm750_crt) {
445                 unsigned int val = PEEK32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
446
447                 POKE32(SYSTEM_CTRL, val | dpms);
448
449                 val = PEEK32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
450                 POKE32(CRT_DISPLAY_CTRL, val | crtdb);
451         }
452
453         if (output->paths & sm750_panel) {
454                 unsigned int val = PEEK32(PANEL_DISPLAY_CTRL);
455
456                 val &= ~PANEL_DISPLAY_CTRL_DATA;
457                 val |= pps;
458                 POKE32(PANEL_DISPLAY_CTRL, val);
459         }
460
461         return 0;
462 }
463
464
465 void hw_sm750_initAccel(struct sm750_dev *sm750_dev)
466 {
467         u32 reg;
468
469         enable2DEngine(1);
470
471         if (getChipType() == SM750LE) {
472                 reg = PEEK32(DE_STATE1);
473                 reg |= DE_STATE1_DE_ABORT;
474                 POKE32(DE_STATE1, reg);
475
476                 reg = PEEK32(DE_STATE1);
477                 reg &= ~DE_STATE1_DE_ABORT;
478                 POKE32(DE_STATE1, reg);
479
480         } else {
481                 /* engine reset */
482                 reg = PEEK32(SYSTEM_CTRL);
483                 reg |= SYSTEM_CTRL_DE_ABORT;
484                 POKE32(SYSTEM_CTRL, reg);
485
486                 reg = PEEK32(SYSTEM_CTRL);
487                 reg &= ~SYSTEM_CTRL_DE_ABORT;
488                 POKE32(SYSTEM_CTRL, reg);
489         }
490
491         /* call 2d init */
492         sm750_dev->accel.de_init(&sm750_dev->accel);
493 }
494
495 int hw_sm750le_deWait(void)
496 {
497         int i = 0x10000000;
498         unsigned int mask = DE_STATE2_DE_STATUS_BUSY | DE_STATE2_DE_FIFO_EMPTY |
499                 DE_STATE2_DE_MEM_FIFO_EMPTY;
500
501         while (i--) {
502                 unsigned int val = PEEK32(DE_STATE2);
503
504                 if ((val & mask) ==
505                     (DE_STATE2_DE_FIFO_EMPTY | DE_STATE2_DE_MEM_FIFO_EMPTY))
506                         return 0;
507         }
508         /* timeout error */
509         return -1;
510 }
511
512
513 int hw_sm750_deWait(void)
514 {
515         int i = 0x10000000;
516         unsigned int mask = SYSTEM_CTRL_DE_STATUS_BUSY |
517                 SYSTEM_CTRL_DE_FIFO_EMPTY |
518                 SYSTEM_CTRL_DE_MEM_FIFO_EMPTY;
519
520         while (i--) {
521                 unsigned int val = PEEK32(SYSTEM_CTRL);
522
523                 if ((val & mask) ==
524                     (SYSTEM_CTRL_DE_FIFO_EMPTY | SYSTEM_CTRL_DE_MEM_FIFO_EMPTY))
525                         return 0;
526         }
527         /* timeout error */
528         return -1;
529 }
530
531 int hw_sm750_pan_display(struct lynxfb_crtc *crtc,
532         const struct fb_var_screeninfo *var,
533         const struct fb_info *info)
534 {
535         uint32_t total;
536         /* check params */
537         if ((var->xoffset + var->xres > var->xres_virtual) ||
538             (var->yoffset + var->yres > var->yres_virtual)) {
539                 return -EINVAL;
540         }
541
542         total = var->yoffset * info->fix.line_length +
543                 ((var->xoffset * var->bits_per_pixel) >> 3);
544         total += crtc->oScreen;
545         if (crtc->channel == sm750_primary) {
546                 POKE32(PANEL_FB_ADDRESS,
547                        PEEK32(PANEL_FB_ADDRESS) |
548                        (total & PANEL_FB_ADDRESS_ADDRESS_MASK));
549         } else {
550                 POKE32(CRT_FB_ADDRESS,
551                        PEEK32(CRT_FB_ADDRESS) |
552                        (total & CRT_FB_ADDRESS_ADDRESS_MASK));
553         }
554         return 0;
555 }