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