1 #include <linux/version.h>
2 #include<linux/module.h>
3 #include<linux/kernel.h>
4 #include<linux/errno.h>
5 #include<linux/string.h>
8 #include<linux/delay.h>
10 #include<linux/ioport.h>
11 #include<linux/init.h>
13 #include<linux/vmalloc.h>
14 #include<linux/pagemap.h>
15 #include <linux/console.h>
19 #include<linux/platform_device.h>
20 #include<linux/screen_info.h>
25 #include "sm750_accel.h"
27 int hw_sm750_map(struct lynx_share *share, struct pci_dev *pdev)
30 struct sm750_share *spec_share;
33 spec_share = container_of(share, struct sm750_share, share);
36 share->vidreg_start = pci_resource_start(pdev, 1);
37 share->vidreg_size = MB(2);
39 pr_info("mmio phyAddr = %lx\n", share->vidreg_start);
41 /* reserve the vidreg space of smi adaptor
42 * if you do this, u need to add release region code
43 * in lynxfb_remove, or memory will not be mapped again
46 ret = pci_request_region(pdev, 1, "sm750fb");
48 pr_err("Can not request PCI regions.\n");
52 /* now map mmio and vidmem*/
53 share->pvReg = ioremap_nocache(share->vidreg_start, share->vidreg_size);
55 pr_err("mmio failed\n");
59 pr_info("mmio virtual addr = %p\n", share->pvReg);
63 share->accel.dprBase = share->pvReg + DE_BASE_ADDR_TYPE1;
64 share->accel.dpPortBase = share->pvReg + DE_PORT_ADDR_TYPE1;
66 ddk750_set_mmio(share->pvReg, share->devid, share->revid);
68 share->vidmem_start = pci_resource_start(pdev, 0);
69 /* don't use pdev_resource[x].end - resource[x].start to
70 * calculate the resource size,its only the maximum available
71 * size but not the actual size,use
72 * @hw_sm750_getVMSize function can be safe.
74 share->vidmem_size = hw_sm750_getVMSize(share);
75 pr_info("video memory phyAddr = %lx, size = %u bytes\n",
76 share->vidmem_start, share->vidmem_size);
78 /* reserve the vidmem space of smi adaptor */
80 ret = pci_request_region(pdev, 0, _moduleName_);
82 pr_err("Can not request PCI regions.\n");
87 share->pvMem = ioremap_wc(share->vidmem_start, share->vidmem_size);
90 pr_err("Map video memory failed\n");
94 pr_info("video memory vaddr = %p\n", share->pvMem);
102 int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev)
104 struct sm750_share *spec_share;
105 struct init_status *parm;
107 spec_share = container_of(share, struct sm750_share, share);
108 parm = &spec_share->state.initParm;
109 if (parm->chip_clk == 0)
110 parm->chip_clk = (getChipType() == SM750LE) ?
111 DEFAULT_SM750LE_CHIP_CLOCK :
112 DEFAULT_SM750_CHIP_CLOCK;
114 if (parm->mem_clk == 0)
115 parm->mem_clk = parm->chip_clk;
116 if (parm->master_clk == 0)
117 parm->master_clk = parm->chip_clk/3;
119 ddk750_initHw((initchip_param_t *)&spec_share->state.initParm);
120 /* for sm718,open pci burst */
121 if (share->devid == 0x718) {
123 FIELD_SET(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, PCI_BURST, ON));
126 /* sm750 use sii164, it can be setup with default value
127 * by on power, so initDVIDisp can be skipped */
129 ddk750_initDVIDisp();
132 if (getChipType() != SM750LE) {
133 /* does user need CRT ?*/
134 if (spec_share->state.nocrt) {
136 FIELD_SET(PEEK32(MISC_CTRL),
141 FIELD_SET(PEEK32(SYSTEM_CTRL),
146 FIELD_SET(PEEK32(MISC_CTRL),
151 FIELD_SET(PEEK32(SYSTEM_CTRL),
156 switch (spec_share->state.pnltype) {
157 case sm750_doubleTFT:
160 POKE32(PANEL_DISPLAY_CTRL,
161 FIELD_VALUE(PEEK32(PANEL_DISPLAY_CTRL),
164 spec_share->state.pnltype));
168 /* for 750LE ,no DVI chip initilization makes Monitor no signal */
169 /* Set up GPIO for software I2C to program DVI chip in the
170 Xilinx SP605 board, in order to have video signal.
175 /* Customer may NOT use CH7301 DVI chip, which has to be
176 initialized differently.
178 if (swI2CReadReg(0xec, 0x4a) == 0x95) {
179 /* The following register values for CH7301 are from
180 Chrontel app note and our experiment.
182 pr_info("yes,CH7301 DVI chip found\n");
183 swI2CWriteReg(0xec, 0x1d, 0x16);
184 swI2CWriteReg(0xec, 0x21, 0x9);
185 swI2CWriteReg(0xec, 0x49, 0xC0);
186 pr_info("okay,CH7301 DVI chip setup done\n");
191 if (!share->accel_off)
192 hw_sm750_initAccel(share);
198 resource_size_t hw_sm750_getVMSize(struct lynx_share *share)
202 ret = ddk750_getVMSize();
208 int hw_sm750_output_checkMode(struct lynxfb_output *output, struct fb_var_screeninfo *var)
215 int hw_sm750_output_setMode(struct lynxfb_output *output,
216 struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix)
219 disp_output_t dispSet;
224 channel = *output->channel;
227 if (getChipType() != SM750LE) {
228 if (channel == sm750_primary) {
229 pr_info("primary channel\n");
230 if (output->paths & sm750_panel)
231 dispSet |= do_LCD1_PRI;
232 if (output->paths & sm750_crt)
233 dispSet |= do_CRT_PRI;
236 pr_info("secondary channel\n");
237 if (output->paths & sm750_panel)
238 dispSet |= do_LCD1_SEC;
239 if (output->paths & sm750_crt)
240 dispSet |= do_CRT_SEC;
243 ddk750_setLogicalDispOut(dispSet);
245 /* just open DISPLAY_CONTROL_750LE register bit 3:0*/
248 reg = PEEK32(DISPLAY_CONTROL_750LE);
250 POKE32(DISPLAY_CONTROL_750LE, reg);
253 pr_info("ddk setlogicdispout done\n");
257 void hw_sm750_output_clear(struct lynxfb_output *output)
263 int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc, struct fb_var_screeninfo *var)
265 struct lynx_share *share;
268 share = container_of(crtc, struct lynxfb_par, crtc)->share;
270 switch (var->bits_per_pixel) {
275 if (share->revid == SM750LE_REVISION_ID) {
276 pr_debug("750le do not support 32bpp\n");
290 set the controller's mode for @crtc charged with @var and @fix parameters
292 int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc,
293 struct fb_var_screeninfo *var,
294 struct fb_fix_screeninfo *fix)
298 mode_parameter_t modparm;
300 struct lynx_share *share;
301 struct lynxfb_par *par;
305 par = container_of(crtc, struct lynxfb_par, crtc);
308 if (!share->accel_off) {
309 /* set 2d engine pixel format according to mode bpp */
310 switch (var->bits_per_pixel) {
322 hw_set2dformat(&share->accel, fmt);
327 modparm.pixel_clock = ps_to_hz(var->pixclock);
328 modparm.vertical_sync_polarity = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? POS:NEG;
329 modparm.horizontal_sync_polarity = (var->sync & FB_SYNC_VERT_HIGH_ACT) ? POS:NEG;
330 modparm.clock_phase_polarity = (var->sync & FB_SYNC_COMP_HIGH_ACT) ? POS:NEG;
331 modparm.horizontal_display_end = var->xres;
332 modparm.horizontal_sync_width = var->hsync_len;
333 modparm.horizontal_sync_start = var->xres + var->right_margin;
334 modparm.horizontal_total = var->xres + var->left_margin + var->right_margin + var->hsync_len;
335 modparm.vertical_display_end = var->yres;
336 modparm.vertical_sync_height = var->vsync_len;
337 modparm.vertical_sync_start = var->yres + var->lower_margin;
338 modparm.vertical_total = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
341 if (crtc->channel != sm750_secondary)
344 clock = SECONDARY_PLL;
346 pr_debug("Request pixel clock = %lu\n", modparm.pixel_clock);
347 ret = ddk750_setModeTiming(&modparm, clock);
349 pr_err("Set mode timing failed\n");
353 if (crtc->channel != sm750_secondary) {
354 /* set pitch, offset ,width,start address ,etc... */
355 POKE32(PANEL_FB_ADDRESS,
356 FIELD_SET(0, PANEL_FB_ADDRESS, STATUS, CURRENT)|
357 FIELD_SET(0, PANEL_FB_ADDRESS, EXT, LOCAL)|
358 FIELD_VALUE(0, PANEL_FB_ADDRESS, ADDRESS, crtc->oScreen));
360 reg = var->xres * (var->bits_per_pixel >> 3);
361 /* crtc->channel is not equal to par->index on numeric,be aware of that */
362 reg = PADDING(crtc->line_pad, reg);
364 POKE32(PANEL_FB_WIDTH,
365 FIELD_VALUE(0, PANEL_FB_WIDTH, WIDTH, reg)|
366 FIELD_VALUE(0, PANEL_FB_WIDTH, OFFSET, fix->line_length));
368 POKE32(PANEL_WINDOW_WIDTH,
369 FIELD_VALUE(0, PANEL_WINDOW_WIDTH, WIDTH, var->xres - 1)|
370 FIELD_VALUE(0, PANEL_WINDOW_WIDTH, X, var->xoffset));
372 POKE32(PANEL_WINDOW_HEIGHT,
373 FIELD_VALUE(0, PANEL_WINDOW_HEIGHT, HEIGHT, var->yres_virtual - 1)|
374 FIELD_VALUE(0, PANEL_WINDOW_HEIGHT, Y, var->yoffset));
376 POKE32(PANEL_PLANE_TL, 0);
378 POKE32(PANEL_PLANE_BR,
379 FIELD_VALUE(0, PANEL_PLANE_BR, BOTTOM, var->yres - 1)|
380 FIELD_VALUE(0, PANEL_PLANE_BR, RIGHT, var->xres - 1));
382 /* set pixel format */
383 reg = PEEK32(PANEL_DISPLAY_CTRL);
384 POKE32(PANEL_DISPLAY_CTRL,
386 PANEL_DISPLAY_CTRL, FORMAT,
387 (var->bits_per_pixel >> 4)
390 /* not implemented now */
391 POKE32(CRT_FB_ADDRESS, crtc->oScreen);
392 reg = var->xres * (var->bits_per_pixel >> 3);
393 /* crtc->channel is not equal to par->index on numeric,be aware of that */
394 reg = PADDING(crtc->line_pad, reg);
397 FIELD_VALUE(0, CRT_FB_WIDTH, WIDTH, reg)|
398 FIELD_VALUE(0, CRT_FB_WIDTH, OFFSET, fix->line_length));
400 /* SET PIXEL FORMAT */
401 reg = PEEK32(CRT_DISPLAY_CTRL);
402 reg = FIELD_VALUE(reg, CRT_DISPLAY_CTRL, FORMAT, var->bits_per_pixel >> 4);
403 POKE32(CRT_DISPLAY_CTRL, reg);
412 void hw_sm750_crtc_clear(struct lynxfb_crtc *crtc)
418 int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index,
419 ushort red, ushort green, ushort blue)
421 static unsigned int add[] = {PANEL_PALETTE_RAM, CRT_PALETTE_RAM};
423 POKE32(add[crtc->channel] + index*4, (red<<16)|(green<<8)|blue);
427 int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank)
432 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
433 case FB_BLANK_UNBLANK:
435 case VESA_NO_BLANKING:
437 dpms = CRT_DISPLAY_CTRL_DPMS_0;
438 crtdb = CRT_DISPLAY_CTRL_BLANK_OFF;
440 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
441 case FB_BLANK_NORMAL:
442 dpms = CRT_DISPLAY_CTRL_DPMS_0;
443 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
446 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
447 case FB_BLANK_VSYNC_SUSPEND:
449 case VESA_VSYNC_SUSPEND:
451 dpms = CRT_DISPLAY_CTRL_DPMS_2;
452 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
454 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
455 case FB_BLANK_HSYNC_SUSPEND:
457 case VESA_HSYNC_SUSPEND:
459 dpms = CRT_DISPLAY_CTRL_DPMS_1;
460 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
462 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
463 case FB_BLANK_POWERDOWN:
467 dpms = CRT_DISPLAY_CTRL_DPMS_3;
468 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
474 if (output->paths & sm750_crt) {
475 POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL), CRT_DISPLAY_CTRL, DPMS, dpms));
476 POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL), CRT_DISPLAY_CTRL, BLANK, crtdb));
481 int hw_sm750_setBLANK(struct lynxfb_output *output, int blank)
483 unsigned int dpms, pps, crtdb;
485 dpms = pps = crtdb = 0;
488 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
489 case FB_BLANK_UNBLANK:
491 case VESA_NO_BLANKING:
493 pr_info("flag = FB_BLANK_UNBLANK\n");
494 dpms = SYSTEM_CTRL_DPMS_VPHP;
495 pps = PANEL_DISPLAY_CTRL_DATA_ENABLE;
496 crtdb = CRT_DISPLAY_CTRL_BLANK_OFF;
498 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
499 case FB_BLANK_NORMAL:
500 pr_info("flag = FB_BLANK_NORMAL\n");
501 dpms = SYSTEM_CTRL_DPMS_VPHP;
502 pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
503 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
506 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
507 case FB_BLANK_VSYNC_SUSPEND:
509 case VESA_VSYNC_SUSPEND:
511 dpms = SYSTEM_CTRL_DPMS_VNHP;
512 pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
513 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
515 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
516 case FB_BLANK_HSYNC_SUSPEND:
518 case VESA_HSYNC_SUSPEND:
520 dpms = SYSTEM_CTRL_DPMS_VPHN;
521 pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
522 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
524 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
525 case FB_BLANK_POWERDOWN:
529 dpms = SYSTEM_CTRL_DPMS_VNHN;
530 pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
531 crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
535 if (output->paths & sm750_crt) {
537 POKE32(SYSTEM_CTRL, FIELD_VALUE(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, DPMS, dpms));
538 POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL), CRT_DISPLAY_CTRL, BLANK, crtdb));
541 if (output->paths & sm750_panel)
542 POKE32(PANEL_DISPLAY_CTRL, FIELD_VALUE(PEEK32(PANEL_DISPLAY_CTRL), PANEL_DISPLAY_CTRL, DATA, pps));
548 void hw_sm750_initAccel(struct lynx_share *share)
554 if (getChipType() == SM750LE) {
555 reg = PEEK32(DE_STATE1);
556 reg = FIELD_SET(reg, DE_STATE1, DE_ABORT, ON);
557 POKE32(DE_STATE1, reg);
559 reg = PEEK32(DE_STATE1);
560 reg = FIELD_SET(reg, DE_STATE1, DE_ABORT, OFF);
561 POKE32(DE_STATE1, reg);
565 reg = PEEK32(SYSTEM_CTRL);
566 reg = FIELD_SET(reg, SYSTEM_CTRL, DE_ABORT, ON);
567 POKE32(SYSTEM_CTRL, reg);
569 reg = PEEK32(SYSTEM_CTRL);
570 reg = FIELD_SET(reg, SYSTEM_CTRL, DE_ABORT, OFF);
571 POKE32(SYSTEM_CTRL, reg);
575 share->accel.de_init(&share->accel);
578 int hw_sm750le_deWait(void)
583 unsigned int dwVal = PEEK32(DE_STATE2);
585 if ((FIELD_GET(dwVal, DE_STATE2, DE_STATUS) == DE_STATE2_DE_STATUS_IDLE) &&
586 (FIELD_GET(dwVal, DE_STATE2, DE_FIFO) == DE_STATE2_DE_FIFO_EMPTY) &&
587 (FIELD_GET(dwVal, DE_STATE2, DE_MEM_FIFO) == DE_STATE2_DE_MEM_FIFO_EMPTY)) {
596 int hw_sm750_deWait(void)
601 unsigned int dwVal = PEEK32(SYSTEM_CTRL);
603 if ((FIELD_GET(dwVal, SYSTEM_CTRL, DE_STATUS) == SYSTEM_CTRL_DE_STATUS_IDLE) &&
604 (FIELD_GET(dwVal, SYSTEM_CTRL, DE_FIFO) == SYSTEM_CTRL_DE_FIFO_EMPTY) &&
605 (FIELD_GET(dwVal, SYSTEM_CTRL, DE_MEM_FIFO) == SYSTEM_CTRL_DE_MEM_FIFO_EMPTY)) {
613 int hw_sm750_pan_display(struct lynxfb_crtc *crtc,
614 const struct fb_var_screeninfo *var,
615 const struct fb_info *info)
619 if ((var->xoffset + var->xres > var->xres_virtual) ||
620 (var->yoffset + var->yres > var->yres_virtual)) {
624 total = var->yoffset * info->fix.line_length +
625 ((var->xoffset * var->bits_per_pixel) >> 3);
626 total += crtc->oScreen;
627 if (crtc->channel == sm750_primary) {
628 POKE32(PANEL_FB_ADDRESS,
629 FIELD_VALUE(PEEK32(PANEL_FB_ADDRESS),
630 PANEL_FB_ADDRESS, ADDRESS, total));
632 POKE32(CRT_FB_ADDRESS,
633 FIELD_VALUE(PEEK32(CRT_FB_ADDRESS),
634 CRT_FB_ADDRESS, ADDRESS, total));