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