1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/errno.h>
4 #include <linux/string.h>
6 #include <linux/slab.h>
7 #include <linux/delay.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>
18 #include <linux/platform_device.h>
19 #include <linux/screen_info.h>
20 #include <linux/sizes.h>
24 #include "sm750_accel.h"
26 int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
32 sm750_dev->vidreg_start = pci_resource_start(pdev, 1);
33 sm750_dev->vidreg_size = SZ_2M;
35 pr_info("mmio phyAddr = %lx\n", sm750_dev->vidreg_start);
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
42 ret = pci_request_region(pdev, 1, "sm750fb");
44 pr_err("Can not request PCI regions.\n");
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");
56 pr_info("mmio virtual addr = %p\n", sm750_dev->pvReg);
60 sm750_dev->accel.dprBase = sm750_dev->pvReg + DE_BASE_ADDR_TYPE1;
61 sm750_dev->accel.dpPortBase = sm750_dev->pvReg + DE_PORT_ADDR_TYPE1;
63 ddk750_set_mmio(sm750_dev->pvReg, sm750_dev->devid, sm750_dev->revid);
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.
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);
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");
83 pr_info("video memory vaddr = %p\n", sm750_dev->pvMem);
91 int hw_sm750_inithw(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
93 struct init_status *parm;
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;
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;
106 ddk750_initHw((initchip_param_t *)&sm750_dev->initParm);
107 /* for sm718,open pci burst */
108 if (sm750_dev->devid == 0x718) {
110 PEEK32(SYSTEM_CTRL) | SYSTEM_CTRL_PCI_BURST);
113 if (getChipType() != SM750LE) {
115 /* does user need CRT ?*/
116 if (sm750_dev->nocrt) {
118 PEEK32(MISC_CTRL) | MISC_CTRL_DAC_POWER_OFF);
120 val = PEEK32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
121 val |= SYSTEM_CTRL_DPMS_VPHN;
122 POKE32(SYSTEM_CTRL, val);
125 PEEK32(MISC_CTRL) & ~MISC_CTRL_DAC_POWER_OFF);
127 val = PEEK32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
128 val |= SYSTEM_CTRL_DPMS_VPHP;
129 POKE32(SYSTEM_CTRL, val);
132 val = PEEK32(PANEL_DISPLAY_CTRL) &
133 ~(PANEL_DISPLAY_CTRL_DUAL_DISPLAY |
134 PANEL_DISPLAY_CTRL_DOUBLE_PIXEL);
135 switch (sm750_dev->pnltype) {
138 case sm750_doubleTFT:
139 val |= PANEL_DISPLAY_CTRL_DOUBLE_PIXEL;
142 val |= PANEL_DISPLAY_CTRL_DUAL_DISPLAY;
145 POKE32(PANEL_DISPLAY_CTRL, val);
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.
151 sm750_sw_i2c_init(0, 1);
153 /* Customer may NOT use CH7301 DVI chip, which has to be
154 initialized differently.
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.
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");
169 if (!sm750_dev->accel_off)
170 hw_sm750_initAccel(sm750_dev);
175 int hw_sm750_output_setMode(struct lynxfb_output *output,
176 struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix)
179 disp_output_t dispSet;
184 channel = *output->channel;
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;
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;
203 ddk750_setLogicalDispOut(dispSet);
205 /* just open DISPLAY_CONTROL_750LE register bit 3:0*/
208 reg = PEEK32(DISPLAY_CONTROL_750LE);
210 POKE32(DISPLAY_CONTROL_750LE, reg);
213 pr_info("ddk setlogicdispout done\n");
217 int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc, struct fb_var_screeninfo *var)
219 struct sm750_dev *sm750_dev;
220 struct lynxfb_par *par = container_of(crtc, struct lynxfb_par, crtc);
222 sm750_dev = par->dev;
224 switch (var->bits_per_pixel) {
229 if (sm750_dev->revid == SM750LE_REVISION_ID) {
230 pr_debug("750le do not support 32bpp\n");
244 set the controller's mode for @crtc charged with @var and @fix parameters
246 int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc,
247 struct fb_var_screeninfo *var,
248 struct fb_fix_screeninfo *fix)
252 mode_parameter_t modparm;
254 struct sm750_dev *sm750_dev;
255 struct lynxfb_par *par;
259 par = container_of(crtc, struct lynxfb_par, crtc);
260 sm750_dev = par->dev;
262 if (!sm750_dev->accel_off) {
263 /* set 2d engine pixel format according to mode bpp */
264 switch (var->bits_per_pixel) {
276 hw_set2dformat(&sm750_dev->accel, fmt);
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;
294 if (crtc->channel != sm750_secondary)
297 clock = SECONDARY_PLL;
299 pr_debug("Request pixel clock = %lu\n", modparm.pixel_clock);
300 ret = ddk750_setModeTiming(&modparm, clock);
302 pr_err("Set mode timing failed\n");
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);
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);
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);
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);
330 POKE32(PANEL_PLANE_TL, 0);
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);
337 /* set pixel format */
338 reg = PEEK32(PANEL_DISPLAY_CTRL);
339 POKE32(PANEL_DISPLAY_CTRL, reg | (var->bits_per_pixel >> 4));
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);
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);
363 int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index,
364 ushort red, ushort green, ushort blue)
366 static unsigned int add[] = {PANEL_PALETTE_RAM, CRT_PALETTE_RAM};
368 POKE32(add[crtc->channel] + index*4, (red<<16)|(green<<8)|blue);
372 int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank)
377 case FB_BLANK_UNBLANK:
378 dpms = CRT_DISPLAY_CTRL_DPMS_0;
381 case FB_BLANK_NORMAL:
382 dpms = CRT_DISPLAY_CTRL_DPMS_0;
383 crtdb = CRT_DISPLAY_CTRL_BLANK;
385 case FB_BLANK_VSYNC_SUSPEND:
386 dpms = CRT_DISPLAY_CTRL_DPMS_2;
387 crtdb = CRT_DISPLAY_CTRL_BLANK;
389 case FB_BLANK_HSYNC_SUSPEND:
390 dpms = CRT_DISPLAY_CTRL_DPMS_1;
391 crtdb = CRT_DISPLAY_CTRL_BLANK;
393 case FB_BLANK_POWERDOWN:
394 dpms = CRT_DISPLAY_CTRL_DPMS_3;
395 crtdb = CRT_DISPLAY_CTRL_BLANK;
401 if (output->paths & sm750_crt) {
404 val = PEEK32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_DPMS_MASK;
405 POKE32(CRT_DISPLAY_CTRL, val | dpms);
407 val = PEEK32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
408 POKE32(CRT_DISPLAY_CTRL, val | crtdb);
413 int hw_sm750_setBLANK(struct lynxfb_output *output, int blank)
415 unsigned int dpms, pps, crtdb;
417 dpms = pps = crtdb = 0;
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;
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;
430 case FB_BLANK_VSYNC_SUSPEND:
431 dpms = SYSTEM_CTRL_DPMS_VNHP;
432 crtdb = CRT_DISPLAY_CTRL_BLANK;
434 case FB_BLANK_HSYNC_SUSPEND:
435 dpms = SYSTEM_CTRL_DPMS_VPHN;
436 crtdb = CRT_DISPLAY_CTRL_BLANK;
438 case FB_BLANK_POWERDOWN:
439 dpms = SYSTEM_CTRL_DPMS_VNHN;
440 crtdb = CRT_DISPLAY_CTRL_BLANK;
444 if (output->paths & sm750_crt) {
445 unsigned int val = PEEK32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
447 POKE32(SYSTEM_CTRL, val | dpms);
449 val = PEEK32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
450 POKE32(CRT_DISPLAY_CTRL, val | crtdb);
453 if (output->paths & sm750_panel) {
454 unsigned int val = PEEK32(PANEL_DISPLAY_CTRL);
456 val &= ~PANEL_DISPLAY_CTRL_DATA;
458 POKE32(PANEL_DISPLAY_CTRL, val);
465 void hw_sm750_initAccel(struct sm750_dev *sm750_dev)
471 if (getChipType() == SM750LE) {
472 reg = PEEK32(DE_STATE1);
473 reg |= DE_STATE1_DE_ABORT;
474 POKE32(DE_STATE1, reg);
476 reg = PEEK32(DE_STATE1);
477 reg &= ~DE_STATE1_DE_ABORT;
478 POKE32(DE_STATE1, reg);
482 reg = PEEK32(SYSTEM_CTRL);
483 reg |= SYSTEM_CTRL_DE_ABORT;
484 POKE32(SYSTEM_CTRL, reg);
486 reg = PEEK32(SYSTEM_CTRL);
487 reg &= ~SYSTEM_CTRL_DE_ABORT;
488 POKE32(SYSTEM_CTRL, reg);
492 sm750_dev->accel.de_init(&sm750_dev->accel);
495 int hw_sm750le_deWait(void)
498 unsigned int mask = DE_STATE2_DE_STATUS_BUSY | DE_STATE2_DE_FIFO_EMPTY |
499 DE_STATE2_DE_MEM_FIFO_EMPTY;
502 unsigned int val = PEEK32(DE_STATE2);
505 (DE_STATE2_DE_FIFO_EMPTY | DE_STATE2_DE_MEM_FIFO_EMPTY))
513 int hw_sm750_deWait(void)
516 unsigned int mask = SYSTEM_CTRL_DE_STATUS_BUSY |
517 SYSTEM_CTRL_DE_FIFO_EMPTY |
518 SYSTEM_CTRL_DE_MEM_FIFO_EMPTY;
521 unsigned int val = PEEK32(SYSTEM_CTRL);
524 (SYSTEM_CTRL_DE_FIFO_EMPTY | SYSTEM_CTRL_DE_MEM_FIFO_EMPTY))
531 int hw_sm750_pan_display(struct lynxfb_crtc *crtc,
532 const struct fb_var_screeninfo *var,
533 const struct fb_info *info)
537 if ((var->xoffset + var->xres > var->xres_virtual) ||
538 (var->yoffset + var->yres > var->yres_virtual)) {
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));
550 POKE32(CRT_FB_ADDRESS,
551 PEEK32(CRT_FB_ADDRESS) |
552 (total & CRT_FB_ADDRESS_ADDRESS_MASK));