]>
Commit | Line | Data |
---|---|---|
81dee67e SM |
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> | |
6 | #include<linux/mm.h> | |
7 | #include<linux/slab.h> | |
8 | #include<linux/delay.h> | |
9 | #include<linux/fb.h> | |
10 | #include<linux/ioport.h> | |
11 | #include<linux/init.h> | |
12 | #include<linux/pci.h> | |
13 | #include<linux/vmalloc.h> | |
14 | #include<linux/pagemap.h> | |
15 | #include <linux/console.h> | |
16 | #ifdef CONFIG_MTRR | |
17 | #include <asm/mtrr.h> | |
18 | #endif | |
19 | #include<linux/platform_device.h> | |
20 | #include<linux/screen_info.h> | |
21 | ||
22 | #include "sm750.h" | |
23 | #include "sm750_hw.h" | |
24 | #include "ddk750.h" | |
25 | #include "sm750_accel.h" | |
26 | ||
e188ea32 | 27 | int hw_sm750_map(struct lynx_share *share, struct pci_dev *pdev) |
81dee67e SM |
28 | { |
29 | int ret; | |
eb0f4271 | 30 | struct sm750_share *spec_share; |
29d87336 | 31 | |
81dee67e | 32 | |
bdec7773 | 33 | spec_share = container_of(share, struct sm750_share, share); |
81dee67e SM |
34 | ret = 0; |
35 | ||
d2a60377 | 36 | share->vidreg_start = pci_resource_start(pdev, 1); |
81dee67e SM |
37 | share->vidreg_size = MB(2); |
38 | ||
e936351a | 39 | pr_info("mmio phyAddr = %lx\n", share->vidreg_start); |
81dee67e SM |
40 | |
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 | |
44 | * successfully | |
45 | * */ | |
9a52ae2d AS |
46 | ret = pci_request_region(pdev, 1, "sm750fb"); |
47 | if (ret) { | |
81dee67e SM |
48 | pr_err("Can not request PCI regions.\n"); |
49 | goto exit; | |
50 | } | |
51 | ||
52 | /* now map mmio and vidmem*/ | |
d2a60377 | 53 | share->pvReg = ioremap_nocache(share->vidreg_start, share->vidreg_size); |
6d1b3d64 | 54 | if (!share->pvReg) { |
81dee67e SM |
55 | pr_err("mmio failed\n"); |
56 | ret = -EFAULT; | |
57 | goto exit; | |
5e83e283 | 58 | } else { |
d2a60377 | 59 | pr_info("mmio virtual addr = %p\n", share->pvReg); |
81dee67e SM |
60 | } |
61 | ||
29d87336 | 62 | |
81dee67e SM |
63 | share->accel.dprBase = share->pvReg + DE_BASE_ADDR_TYPE1; |
64 | share->accel.dpPortBase = share->pvReg + DE_PORT_ADDR_TYPE1; | |
65 | ||
bdec7773 | 66 | ddk750_set_mmio(share->pvReg, share->devid, share->revid); |
81dee67e | 67 | |
d2a60377 | 68 | share->vidmem_start = pci_resource_start(pdev, 0); |
81dee67e SM |
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. | |
73 | * */ | |
74 | share->vidmem_size = hw_sm750_getVMSize(share); | |
e936351a | 75 | pr_info("video memory phyAddr = %lx, size = %u bytes\n", |
d2a60377 | 76 | share->vidmem_start, share->vidmem_size); |
81dee67e SM |
77 | |
78 | /* reserve the vidmem space of smi adaptor */ | |
79 | #if 0 | |
9a52ae2d AS |
80 | ret = pci_request_region(pdev, 0, _moduleName_); |
81 | if (ret) { | |
81dee67e SM |
82 | pr_err("Can not request PCI regions.\n"); |
83 | goto exit; | |
84 | } | |
85 | #endif | |
86 | ||
2e043a92 | 87 | share->pvMem = ioremap_wc(share->vidmem_start, share->vidmem_size); |
81dee67e | 88 | |
6d1b3d64 | 89 | if (!share->pvMem) { |
81dee67e SM |
90 | pr_err("Map video memory failed\n"); |
91 | ret = -EFAULT; | |
92 | goto exit; | |
5e83e283 | 93 | } else { |
d2a60377 | 94 | pr_info("video memory vaddr = %p\n", share->pvMem); |
81dee67e SM |
95 | } |
96 | exit: | |
97 | return ret; | |
98 | } | |
99 | ||
100 | ||
101 | ||
eb0f4271 | 102 | int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) |
81dee67e | 103 | { |
eb0f4271 GD |
104 | struct sm750_share *spec_share; |
105 | struct init_status *parm; | |
29d87336 | 106 | |
bdec7773 | 107 | spec_share = container_of(share, struct sm750_share, share); |
81dee67e | 108 | parm = &spec_share->state.initParm; |
6d1b3d64 | 109 | if (parm->chip_clk == 0) |
d5fca403 | 110 | parm->chip_clk = (getChipType() == SM750LE) ? |
81dee67e SM |
111 | DEFAULT_SM750LE_CHIP_CLOCK : |
112 | DEFAULT_SM750_CHIP_CLOCK; | |
113 | ||
6d1b3d64 | 114 | if (parm->mem_clk == 0) |
81dee67e | 115 | parm->mem_clk = parm->chip_clk; |
6d1b3d64 | 116 | if (parm->master_clk == 0) |
81dee67e SM |
117 | parm->master_clk = parm->chip_clk/3; |
118 | ||
119 | ddk750_initHw((initchip_param_t *)&spec_share->state.initParm); | |
120 | /* for sm718,open pci burst */ | |
6d1b3d64 | 121 | if (share->devid == 0x718) { |
81dee67e | 122 | POKE32(SYSTEM_CTRL, |
d2a60377 | 123 | FIELD_SET(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, PCI_BURST, ON)); |
81dee67e SM |
124 | } |
125 | ||
126 | /* sm750 use sii164, it can be setup with default value | |
127 | * by on power, so initDVIDisp can be skipped */ | |
128 | #if 0 | |
129 | ddk750_initDVIDisp(); | |
130 | #endif | |
131 | ||
4bcdffee | 132 | if (getChipType() != SM750LE) { |
81dee67e | 133 | /* does user need CRT ?*/ |
6d1b3d64 | 134 | if (spec_share->state.nocrt) { |
81dee67e SM |
135 | POKE32(MISC_CTRL, |
136 | FIELD_SET(PEEK32(MISC_CTRL), | |
137 | MISC_CTRL, | |
d2a60377 | 138 | DAC_POWER, OFF)); |
81dee67e SM |
139 | /* shut off dpms */ |
140 | POKE32(SYSTEM_CTRL, | |
141 | FIELD_SET(PEEK32(SYSTEM_CTRL), | |
142 | SYSTEM_CTRL, | |
d2a60377 | 143 | DPMS, VNHN)); |
5e83e283 | 144 | } else { |
81dee67e SM |
145 | POKE32(MISC_CTRL, |
146 | FIELD_SET(PEEK32(MISC_CTRL), | |
147 | MISC_CTRL, | |
d2a60377 | 148 | DAC_POWER, ON)); |
81dee67e SM |
149 | /* turn on dpms */ |
150 | POKE32(SYSTEM_CTRL, | |
151 | FIELD_SET(PEEK32(SYSTEM_CTRL), | |
152 | SYSTEM_CTRL, | |
d2a60377 | 153 | DPMS, VPHP)); |
81dee67e SM |
154 | } |
155 | ||
e0ded448 | 156 | switch (spec_share->state.pnltype) { |
990e5666 AS |
157 | case sm750_doubleTFT: |
158 | case sm750_24TFT: | |
159 | case sm750_dualTFT: | |
160 | POKE32(PANEL_DISPLAY_CTRL, | |
161 | FIELD_VALUE(PEEK32(PANEL_DISPLAY_CTRL), | |
162 | PANEL_DISPLAY_CTRL, | |
163 | TFT_DISP, | |
164 | spec_share->state.pnltype)); | |
165 | break; | |
81dee67e | 166 | } |
5e83e283 | 167 | } else { |
81dee67e SM |
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. | |
171 | */ | |
202add2a | 172 | swI2CInit(0, 1); |
81dee67e SM |
173 | |
174 | ||
202add2a AS |
175 | /* Customer may NOT use CH7301 DVI chip, which has to be |
176 | initialized differently. | |
177 | */ | |
4bcdffee | 178 | if (swI2CReadReg(0xec, 0x4a) == 0x95) { |
202add2a AS |
179 | /* The following register values for CH7301 are from |
180 | Chrontel app note and our experiment. | |
181 | */ | |
81dee67e | 182 | pr_info("yes,CH7301 DVI chip found\n"); |
202add2a AS |
183 | swI2CWriteReg(0xec, 0x1d, 0x16); |
184 | swI2CWriteReg(0xec, 0x21, 0x9); | |
185 | swI2CWriteReg(0xec, 0x49, 0xC0); | |
81dee67e | 186 | pr_info("okay,CH7301 DVI chip setup done\n"); |
202add2a | 187 | } |
81dee67e SM |
188 | } |
189 | ||
190 | /* init 2d engine */ | |
7b05cbe8 | 191 | if (!share->accel_off) |
81dee67e | 192 | hw_sm750_initAccel(share); |
81dee67e SM |
193 | |
194 | return 0; | |
195 | } | |
196 | ||
197 | ||
eb0f4271 | 198 | resource_size_t hw_sm750_getVMSize(struct lynx_share *share) |
81dee67e SM |
199 | { |
200 | resource_size_t ret; | |
29d87336 | 201 | |
81dee67e SM |
202 | ret = ddk750_getVMSize(); |
203 | return ret; | |
204 | } | |
205 | ||
206 | ||
207 | ||
e188ea32 | 208 | int hw_sm750_output_checkMode(struct lynxfb_output *output, struct fb_var_screeninfo *var) |
81dee67e | 209 | { |
29d87336 | 210 | |
81dee67e SM |
211 | return 0; |
212 | } | |
213 | ||
214 | ||
e188ea32 AS |
215 | int hw_sm750_output_setMode(struct lynxfb_output *output, |
216 | struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix) | |
81dee67e SM |
217 | { |
218 | int ret; | |
219 | disp_output_t dispSet; | |
220 | int channel; | |
29d87336 | 221 | |
81dee67e SM |
222 | ret = 0; |
223 | dispSet = 0; | |
224 | channel = *output->channel; | |
225 | ||
226 | ||
6d1b3d64 AS |
227 | if (getChipType() != SM750LE) { |
228 | if (channel == sm750_primary) { | |
81dee67e | 229 | pr_info("primary channel\n"); |
6d1b3d64 | 230 | if (output->paths & sm750_panel) |
81dee67e | 231 | dispSet |= do_LCD1_PRI; |
6d1b3d64 | 232 | if (output->paths & sm750_crt) |
81dee67e SM |
233 | dispSet |= do_CRT_PRI; |
234 | ||
5e83e283 | 235 | } else { |
81dee67e | 236 | pr_info("secondary channel\n"); |
6d1b3d64 | 237 | if (output->paths & sm750_panel) |
81dee67e | 238 | dispSet |= do_LCD1_SEC; |
6d1b3d64 | 239 | if (output->paths & sm750_crt) |
81dee67e SM |
240 | dispSet |= do_CRT_SEC; |
241 | ||
242 | } | |
243 | ddk750_setLogicalDispOut(dispSet); | |
5e83e283 | 244 | } else { |
81dee67e SM |
245 | /* just open DISPLAY_CONTROL_750LE register bit 3:0*/ |
246 | u32 reg; | |
40403c1b | 247 | |
81dee67e SM |
248 | reg = PEEK32(DISPLAY_CONTROL_750LE); |
249 | reg |= 0xf; | |
d2a60377 | 250 | POKE32(DISPLAY_CONTROL_750LE, reg); |
81dee67e SM |
251 | } |
252 | ||
a1fe154f | 253 | pr_info("ddk setlogicdispout done\n"); |
81dee67e SM |
254 | return ret; |
255 | } | |
256 | ||
e188ea32 | 257 | void hw_sm750_output_clear(struct lynxfb_output *output) |
81dee67e | 258 | { |
29d87336 | 259 | |
81dee67e SM |
260 | return; |
261 | } | |
262 | ||
e188ea32 | 263 | int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc, struct fb_var_screeninfo *var) |
81dee67e | 264 | { |
eb0f4271 | 265 | struct lynx_share *share; |
29d87336 | 266 | |
81dee67e | 267 | |
bdec7773 | 268 | share = container_of(crtc, struct lynxfb_par, crtc)->share; |
81dee67e | 269 | |
e0ded448 | 270 | switch (var->bits_per_pixel) { |
990e5666 AS |
271 | case 8: |
272 | case 16: | |
273 | break; | |
274 | case 32: | |
275 | if (share->revid == SM750LE_REVISION_ID) { | |
276 | pr_debug("750le do not support 32bpp\n"); | |
81dee67e | 277 | return -EINVAL; |
990e5666 AS |
278 | } |
279 | break; | |
280 | default: | |
281 | return -EINVAL; | |
81dee67e SM |
282 | |
283 | } | |
284 | ||
285 | return 0; | |
286 | } | |
287 | ||
288 | ||
289 | /* | |
290 | set the controller's mode for @crtc charged with @var and @fix parameters | |
291 | */ | |
e188ea32 AS |
292 | int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc, |
293 | struct fb_var_screeninfo *var, | |
294 | struct fb_fix_screeninfo *fix) | |
81dee67e | 295 | { |
bdec7773 | 296 | int ret, fmt; |
81dee67e SM |
297 | u32 reg; |
298 | mode_parameter_t modparm; | |
299 | clock_type_t clock; | |
eb0f4271 GD |
300 | struct lynx_share *share; |
301 | struct lynxfb_par *par; | |
81dee67e | 302 | |
29d87336 | 303 | |
81dee67e | 304 | ret = 0; |
d2a60377 | 305 | par = container_of(crtc, struct lynxfb_par, crtc); |
81dee67e SM |
306 | share = par->share; |
307 | #if 1 | |
6d1b3d64 | 308 | if (!share->accel_off) { |
81dee67e | 309 | /* set 2d engine pixel format according to mode bpp */ |
6d1b3d64 | 310 | switch (var->bits_per_pixel) { |
990e5666 AS |
311 | case 8: |
312 | fmt = 0; | |
313 | break; | |
314 | case 16: | |
315 | fmt = 1; | |
316 | break; | |
317 | case 32: | |
318 | default: | |
319 | fmt = 2; | |
320 | break; | |
81dee67e | 321 | } |
d2a60377 | 322 | hw_set2dformat(&share->accel, fmt); |
81dee67e SM |
323 | } |
324 | #endif | |
325 | ||
326 | /* set timing */ | |
81dee67e SM |
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; | |
d5fca403 | 330 | modparm.clock_phase_polarity = (var->sync & FB_SYNC_COMP_HIGH_ACT) ? POS:NEG; |
81dee67e SM |
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; | |
339 | ||
340 | /* choose pll */ | |
6d1b3d64 | 341 | if (crtc->channel != sm750_secondary) |
81dee67e SM |
342 | clock = PRIMARY_PLL; |
343 | else | |
344 | clock = SECONDARY_PLL; | |
345 | ||
d2a60377 SA |
346 | pr_debug("Request pixel clock = %lu\n", modparm.pixel_clock); |
347 | ret = ddk750_setModeTiming(&modparm, clock); | |
6d1b3d64 | 348 | if (ret) { |
81dee67e SM |
349 | pr_err("Set mode timing failed\n"); |
350 | goto exit; | |
351 | } | |
352 | ||
6d1b3d64 | 353 | if (crtc->channel != sm750_secondary) { |
81dee67e SM |
354 | /* set pitch, offset ,width,start address ,etc... */ |
355 | POKE32(PANEL_FB_ADDRESS, | |
d2a60377 SA |
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)); | |
81dee67e SM |
359 | |
360 | reg = var->xres * (var->bits_per_pixel >> 3); | |
361 | /* crtc->channel is not equal to par->index on numeric,be aware of that */ | |
bdec7773 | 362 | reg = PADDING(crtc->line_pad, reg); |
81dee67e SM |
363 | |
364 | POKE32(PANEL_FB_WIDTH, | |
d2a60377 SA |
365 | FIELD_VALUE(0, PANEL_FB_WIDTH, WIDTH, reg)| |
366 | FIELD_VALUE(0, PANEL_FB_WIDTH, OFFSET, fix->line_length)); | |
81dee67e SM |
367 | |
368 | POKE32(PANEL_WINDOW_WIDTH, | |
d5fca403 | 369 | FIELD_VALUE(0, PANEL_WINDOW_WIDTH, WIDTH, var->xres - 1)| |
d2a60377 | 370 | FIELD_VALUE(0, PANEL_WINDOW_WIDTH, X, var->xoffset)); |
81dee67e SM |
371 | |
372 | POKE32(PANEL_WINDOW_HEIGHT, | |
d2a60377 SA |
373 | FIELD_VALUE(0, PANEL_WINDOW_HEIGHT, HEIGHT, var->yres_virtual - 1)| |
374 | FIELD_VALUE(0, PANEL_WINDOW_HEIGHT, Y, var->yoffset)); | |
81dee67e | 375 | |
d2a60377 | 376 | POKE32(PANEL_PLANE_TL, 0); |
81dee67e SM |
377 | |
378 | POKE32(PANEL_PLANE_BR, | |
d2a60377 | 379 | FIELD_VALUE(0, PANEL_PLANE_BR, BOTTOM, var->yres - 1)| |
bdec7773 | 380 | FIELD_VALUE(0, PANEL_PLANE_BR, RIGHT, var->xres - 1)); |
81dee67e SM |
381 | |
382 | /* set pixel format */ | |
383 | reg = PEEK32(PANEL_DISPLAY_CTRL); | |
384 | POKE32(PANEL_DISPLAY_CTRL, | |
385 | FIELD_VALUE(reg, | |
d2a60377 | 386 | PANEL_DISPLAY_CTRL, FORMAT, |
81dee67e SM |
387 | (var->bits_per_pixel >> 4) |
388 | )); | |
5e83e283 | 389 | } else { |
81dee67e | 390 | /* not implemented now */ |
d2a60377 | 391 | POKE32(CRT_FB_ADDRESS, crtc->oScreen); |
81dee67e SM |
392 | reg = var->xres * (var->bits_per_pixel >> 3); |
393 | /* crtc->channel is not equal to par->index on numeric,be aware of that */ | |
d2a60377 | 394 | reg = PADDING(crtc->line_pad, reg); |
81dee67e SM |
395 | |
396 | POKE32(CRT_FB_WIDTH, | |
d2a60377 SA |
397 | FIELD_VALUE(0, CRT_FB_WIDTH, WIDTH, reg)| |
398 | FIELD_VALUE(0, CRT_FB_WIDTH, OFFSET, fix->line_length)); | |
81dee67e SM |
399 | |
400 | /* SET PIXEL FORMAT */ | |
401 | reg = PEEK32(CRT_DISPLAY_CTRL); | |
d2a60377 SA |
402 | reg = FIELD_VALUE(reg, CRT_DISPLAY_CTRL, FORMAT, var->bits_per_pixel >> 4); |
403 | POKE32(CRT_DISPLAY_CTRL, reg); | |
81dee67e SM |
404 | |
405 | } | |
406 | ||
407 | ||
408 | exit: | |
409 | return ret; | |
410 | } | |
411 | ||
e188ea32 | 412 | void hw_sm750_crtc_clear(struct lynxfb_crtc *crtc) |
81dee67e | 413 | { |
29d87336 | 414 | |
81dee67e SM |
415 | return; |
416 | } | |
417 | ||
e188ea32 | 418 | int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index, |
d2a60377 | 419 | ushort red, ushort green, ushort blue) |
81dee67e | 420 | { |
d5fca403 | 421 | static unsigned int add[] = {PANEL_PALETTE_RAM, CRT_PALETTE_RAM}; |
40403c1b | 422 | |
d2a60377 | 423 | POKE32(add[crtc->channel] + index*4, (red<<16)|(green<<8)|blue); |
81dee67e SM |
424 | return 0; |
425 | } | |
426 | ||
14a974c5 AS |
427 | int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank) |
428 | { | |
bdec7773 | 429 | int dpms, crtdb; |
29d87336 | 430 | |
4bcdffee | 431 | switch (blank) { |
bdec7773 | 432 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) |
990e5666 | 433 | case FB_BLANK_UNBLANK: |
81dee67e | 434 | #else |
990e5666 | 435 | case VESA_NO_BLANKING: |
81dee67e | 436 | #endif |
990e5666 AS |
437 | dpms = CRT_DISPLAY_CTRL_DPMS_0; |
438 | crtdb = CRT_DISPLAY_CTRL_BLANK_OFF; | |
439 | break; | |
bdec7773 | 440 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) |
990e5666 AS |
441 | case FB_BLANK_NORMAL: |
442 | dpms = CRT_DISPLAY_CTRL_DPMS_0; | |
443 | crtdb = CRT_DISPLAY_CTRL_BLANK_ON; | |
444 | break; | |
81dee67e | 445 | #endif |
bdec7773 | 446 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) |
990e5666 | 447 | case FB_BLANK_VSYNC_SUSPEND: |
81dee67e | 448 | #else |
990e5666 | 449 | case VESA_VSYNC_SUSPEND: |
81dee67e | 450 | #endif |
990e5666 AS |
451 | dpms = CRT_DISPLAY_CTRL_DPMS_2; |
452 | crtdb = CRT_DISPLAY_CTRL_BLANK_ON; | |
453 | break; | |
bdec7773 | 454 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) |
990e5666 | 455 | case FB_BLANK_HSYNC_SUSPEND: |
81dee67e | 456 | #else |
990e5666 | 457 | case VESA_HSYNC_SUSPEND: |
81dee67e | 458 | #endif |
990e5666 AS |
459 | dpms = CRT_DISPLAY_CTRL_DPMS_1; |
460 | crtdb = CRT_DISPLAY_CTRL_BLANK_ON; | |
461 | break; | |
bdec7773 | 462 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) |
990e5666 | 463 | case FB_BLANK_POWERDOWN: |
81dee67e | 464 | #else |
990e5666 | 465 | case VESA_POWERDOWN: |
81dee67e | 466 | #endif |
990e5666 AS |
467 | dpms = CRT_DISPLAY_CTRL_DPMS_3; |
468 | crtdb = CRT_DISPLAY_CTRL_BLANK_ON; | |
469 | break; | |
470 | default: | |
471 | return -EINVAL; | |
81dee67e SM |
472 | } |
473 | ||
6d1b3d64 | 474 | if (output->paths & sm750_crt) { |
d2a60377 SA |
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)); | |
81dee67e SM |
477 | } |
478 | return 0; | |
479 | } | |
480 | ||
e188ea32 | 481 | int hw_sm750_setBLANK(struct lynxfb_output *output, int blank) |
81dee67e | 482 | { |
d2a60377 | 483 | unsigned int dpms, pps, crtdb; |
29d87336 | 484 | |
81dee67e SM |
485 | dpms = pps = crtdb = 0; |
486 | ||
4bcdffee | 487 | switch (blank) { |
bdec7773 | 488 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) |
990e5666 | 489 | case FB_BLANK_UNBLANK: |
81dee67e | 490 | #else |
990e5666 | 491 | case VESA_NO_BLANKING: |
81dee67e | 492 | #endif |
a1fe154f | 493 | pr_info("flag = FB_BLANK_UNBLANK\n"); |
990e5666 AS |
494 | dpms = SYSTEM_CTRL_DPMS_VPHP; |
495 | pps = PANEL_DISPLAY_CTRL_DATA_ENABLE; | |
496 | crtdb = CRT_DISPLAY_CTRL_BLANK_OFF; | |
497 | break; | |
bdec7773 | 498 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) |
990e5666 | 499 | case FB_BLANK_NORMAL: |
a1fe154f | 500 | pr_info("flag = FB_BLANK_NORMAL\n"); |
990e5666 AS |
501 | dpms = SYSTEM_CTRL_DPMS_VPHP; |
502 | pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; | |
503 | crtdb = CRT_DISPLAY_CTRL_BLANK_ON; | |
504 | break; | |
81dee67e | 505 | #endif |
bdec7773 | 506 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) |
990e5666 | 507 | case FB_BLANK_VSYNC_SUSPEND: |
81dee67e | 508 | #else |
990e5666 | 509 | case VESA_VSYNC_SUSPEND: |
81dee67e | 510 | #endif |
990e5666 AS |
511 | dpms = SYSTEM_CTRL_DPMS_VNHP; |
512 | pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; | |
513 | crtdb = CRT_DISPLAY_CTRL_BLANK_ON; | |
514 | break; | |
bdec7773 | 515 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) |
990e5666 | 516 | case FB_BLANK_HSYNC_SUSPEND: |
81dee67e | 517 | #else |
990e5666 | 518 | case VESA_HSYNC_SUSPEND: |
81dee67e | 519 | #endif |
990e5666 AS |
520 | dpms = SYSTEM_CTRL_DPMS_VPHN; |
521 | pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; | |
522 | crtdb = CRT_DISPLAY_CTRL_BLANK_ON; | |
523 | break; | |
bdec7773 | 524 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) |
990e5666 | 525 | case FB_BLANK_POWERDOWN: |
81dee67e | 526 | #else |
990e5666 | 527 | case VESA_POWERDOWN: |
81dee67e | 528 | #endif |
990e5666 AS |
529 | dpms = SYSTEM_CTRL_DPMS_VNHN; |
530 | pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; | |
531 | crtdb = CRT_DISPLAY_CTRL_BLANK_ON; | |
532 | break; | |
81dee67e SM |
533 | } |
534 | ||
6d1b3d64 | 535 | if (output->paths & sm750_crt) { |
81dee67e | 536 | |
bdec7773 IA |
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)); | |
81dee67e SM |
539 | } |
540 | ||
7b05cbe8 | 541 | if (output->paths & sm750_panel) |
d2a60377 | 542 | POKE32(PANEL_DISPLAY_CTRL, FIELD_VALUE(PEEK32(PANEL_DISPLAY_CTRL), PANEL_DISPLAY_CTRL, DATA, pps)); |
81dee67e SM |
543 | |
544 | return 0; | |
545 | } | |
546 | ||
547 | ||
eb0f4271 | 548 | void hw_sm750_initAccel(struct lynx_share *share) |
81dee67e SM |
549 | { |
550 | u32 reg; | |
40403c1b | 551 | |
81dee67e SM |
552 | enable2DEngine(1); |
553 | ||
6d1b3d64 | 554 | if (getChipType() == SM750LE) { |
81dee67e | 555 | reg = PEEK32(DE_STATE1); |
bdec7773 IA |
556 | reg = FIELD_SET(reg, DE_STATE1, DE_ABORT, ON); |
557 | POKE32(DE_STATE1, reg); | |
81dee67e SM |
558 | |
559 | reg = PEEK32(DE_STATE1); | |
bdec7773 | 560 | reg = FIELD_SET(reg, DE_STATE1, DE_ABORT, OFF); |
d2a60377 | 561 | POKE32(DE_STATE1, reg); |
81dee67e | 562 | |
5e83e283 | 563 | } else { |
81dee67e SM |
564 | /* engine reset */ |
565 | reg = PEEK32(SYSTEM_CTRL); | |
bdec7773 | 566 | reg = FIELD_SET(reg, SYSTEM_CTRL, DE_ABORT, ON); |
d2a60377 | 567 | POKE32(SYSTEM_CTRL, reg); |
81dee67e SM |
568 | |
569 | reg = PEEK32(SYSTEM_CTRL); | |
bdec7773 | 570 | reg = FIELD_SET(reg, SYSTEM_CTRL, DE_ABORT, OFF); |
d2a60377 | 571 | POKE32(SYSTEM_CTRL, reg); |
81dee67e SM |
572 | } |
573 | ||
574 | /* call 2d init */ | |
575 | share->accel.de_init(&share->accel); | |
576 | } | |
577 | ||
6fa7db83 | 578 | int hw_sm750le_deWait(void) |
81dee67e | 579 | { |
d5fca403 | 580 | int i = 0x10000000; |
40403c1b | 581 | |
6d1b3d64 | 582 | while (i--) { |
81dee67e | 583 | unsigned int dwVal = PEEK32(DE_STATE2); |
40403c1b | 584 | |
6d1b3d64 | 585 | if ((FIELD_GET(dwVal, DE_STATE2, DE_STATUS) == DE_STATE2_DE_STATUS_IDLE) && |
d2a60377 | 586 | (FIELD_GET(dwVal, DE_STATE2, DE_FIFO) == DE_STATE2_DE_FIFO_EMPTY) && |
4bcdffee | 587 | (FIELD_GET(dwVal, DE_STATE2, DE_MEM_FIFO) == DE_STATE2_DE_MEM_FIFO_EMPTY)) { |
81dee67e SM |
588 | return 0; |
589 | } | |
590 | } | |
591 | /* timeout error */ | |
592 | return -1; | |
593 | } | |
594 | ||
595 | ||
6fa7db83 | 596 | int hw_sm750_deWait(void) |
81dee67e | 597 | { |
d5fca403 | 598 | int i = 0x10000000; |
40403c1b | 599 | |
6d1b3d64 | 600 | while (i--) { |
81dee67e | 601 | unsigned int dwVal = PEEK32(SYSTEM_CTRL); |
40403c1b | 602 | |
6d1b3d64 | 603 | if ((FIELD_GET(dwVal, SYSTEM_CTRL, DE_STATUS) == SYSTEM_CTRL_DE_STATUS_IDLE) && |
bdec7773 | 604 | (FIELD_GET(dwVal, SYSTEM_CTRL, DE_FIFO) == SYSTEM_CTRL_DE_FIFO_EMPTY) && |
4bcdffee | 605 | (FIELD_GET(dwVal, SYSTEM_CTRL, DE_MEM_FIFO) == SYSTEM_CTRL_DE_MEM_FIFO_EMPTY)) { |
81dee67e SM |
606 | return 0; |
607 | } | |
608 | } | |
609 | /* timeout error */ | |
610 | return -1; | |
611 | } | |
612 | ||
613 | int hw_sm750_pan_display(struct lynxfb_crtc *crtc, | |
202add2a AS |
614 | const struct fb_var_screeninfo *var, |
615 | const struct fb_info *info) | |
81dee67e | 616 | { |
202add2a AS |
617 | uint32_t total; |
618 | /* check params */ | |
619 | if ((var->xoffset + var->xres > var->xres_virtual) || | |
620 | (var->yoffset + var->yres > var->yres_virtual)) { | |
621 | return -EINVAL; | |
622 | } | |
623 | ||
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)); | |
631 | } else { | |
632 | POKE32(CRT_FB_ADDRESS, | |
633 | FIELD_VALUE(PEEK32(CRT_FB_ADDRESS), | |
634 | CRT_FB_ADDRESS, ADDRESS, total)); | |
635 | } | |
636 | return 0; | |
81dee67e | 637 | } |