diff options
author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2014-02-13 08:31:38 -0500 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2014-04-17 01:10:19 -0400 |
commit | f7018c21350204c4cf628462f229d44d03545254 (patch) | |
tree | 408787177164cf51cc06f7aabdb04fcff8d2b6aa /drivers/video/fbdev/via | |
parent | c26ef3eb3c11274bad1b64498d0a134f85755250 (diff) |
video: move fbdev to drivers/video/fbdev
The drivers/video directory is a mess. It contains generic video related
files, directories for backlight, console, linux logo, lots of fbdev
device drivers, fbdev framework files.
Make some order into the chaos by creating drivers/video/fbdev
directory, and move all fbdev related files there.
No functionality is changed, although I guess it is possible that some
subtle Makefile build order related issue could be created by this
patch.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Rob Clark <robdclark@gmail.com>
Acked-by: Jingoo Han <jg1.han@samsung.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/video/fbdev/via')
44 files changed, 12453 insertions, 0 deletions
diff --git a/drivers/video/fbdev/via/Makefile b/drivers/video/fbdev/via/Makefile new file mode 100644 index 000000000000..159f26e6adb5 --- /dev/null +++ b/drivers/video/fbdev/via/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | # | ||
2 | # Makefile for the VIA framebuffer driver (for Linux Kernel 2.6) | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_FB_VIA) += viafb.o | ||
6 | |||
7 | viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o \ | ||
8 | via_utility.o vt1636.o global.o tblDPASetting.o viamode.o \ | ||
9 | via-core.o via-gpio.o via_modesetting.o via_clock.o \ | ||
10 | via_aux.o via_aux_edid.o via_aux_vt1636.o via_aux_vt1632.o \ | ||
11 | via_aux_vt1631.o via_aux_vt1625.o via_aux_vt1622.o via_aux_vt1621.o \ | ||
12 | via_aux_sii164.o via_aux_ch7301.o | ||
diff --git a/drivers/video/fbdev/via/accel.c b/drivers/video/fbdev/via/accel.c new file mode 100644 index 000000000000..4b67b8e6030a --- /dev/null +++ b/drivers/video/fbdev/via/accel.c | |||
@@ -0,0 +1,547 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #include <linux/via-core.h> | ||
22 | #include "global.h" | ||
23 | |||
24 | /* | ||
25 | * Figure out an appropriate bytes-per-pixel setting. | ||
26 | */ | ||
27 | static int viafb_set_bpp(void __iomem *engine, u8 bpp) | ||
28 | { | ||
29 | u32 gemode; | ||
30 | |||
31 | /* Preserve the reserved bits */ | ||
32 | /* Lowest 2 bits to zero gives us no rotation */ | ||
33 | gemode = readl(engine + VIA_REG_GEMODE) & 0xfffffcfc; | ||
34 | switch (bpp) { | ||
35 | case 8: | ||
36 | gemode |= VIA_GEM_8bpp; | ||
37 | break; | ||
38 | case 16: | ||
39 | gemode |= VIA_GEM_16bpp; | ||
40 | break; | ||
41 | case 32: | ||
42 | gemode |= VIA_GEM_32bpp; | ||
43 | break; | ||
44 | default: | ||
45 | printk(KERN_WARNING "viafb_set_bpp: Unsupported bpp %d\n", bpp); | ||
46 | return -EINVAL; | ||
47 | } | ||
48 | writel(gemode, engine + VIA_REG_GEMODE); | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | |||
53 | static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height, | ||
54 | u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y, | ||
55 | u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y, | ||
56 | u32 fg_color, u32 bg_color, u8 fill_rop) | ||
57 | { | ||
58 | u32 ge_cmd = 0, tmp, i; | ||
59 | int ret; | ||
60 | |||
61 | if (!op || op > 3) { | ||
62 | printk(KERN_WARNING "hw_bitblt_1: Invalid operation: %d\n", op); | ||
63 | return -EINVAL; | ||
64 | } | ||
65 | |||
66 | if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) { | ||
67 | if (src_x < dst_x) { | ||
68 | ge_cmd |= 0x00008000; | ||
69 | src_x += width - 1; | ||
70 | dst_x += width - 1; | ||
71 | } | ||
72 | if (src_y < dst_y) { | ||
73 | ge_cmd |= 0x00004000; | ||
74 | src_y += height - 1; | ||
75 | dst_y += height - 1; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | if (op == VIA_BITBLT_FILL) { | ||
80 | switch (fill_rop) { | ||
81 | case 0x00: /* blackness */ | ||
82 | case 0x5A: /* pattern inversion */ | ||
83 | case 0xF0: /* pattern copy */ | ||
84 | case 0xFF: /* whiteness */ | ||
85 | break; | ||
86 | default: | ||
87 | printk(KERN_WARNING "hw_bitblt_1: Invalid fill rop: " | ||
88 | "%u\n", fill_rop); | ||
89 | return -EINVAL; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | ret = viafb_set_bpp(engine, dst_bpp); | ||
94 | if (ret) | ||
95 | return ret; | ||
96 | |||
97 | if (op != VIA_BITBLT_FILL) { | ||
98 | if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000) | ||
99 | || src_y & 0xFFFFF000) { | ||
100 | printk(KERN_WARNING "hw_bitblt_1: Unsupported source " | ||
101 | "x/y %d %d\n", src_x, src_y); | ||
102 | return -EINVAL; | ||
103 | } | ||
104 | tmp = src_x | (src_y << 16); | ||
105 | writel(tmp, engine + 0x08); | ||
106 | } | ||
107 | |||
108 | if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) { | ||
109 | printk(KERN_WARNING "hw_bitblt_1: Unsupported destination x/y " | ||
110 | "%d %d\n", dst_x, dst_y); | ||
111 | return -EINVAL; | ||
112 | } | ||
113 | tmp = dst_x | (dst_y << 16); | ||
114 | writel(tmp, engine + 0x0C); | ||
115 | |||
116 | if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) { | ||
117 | printk(KERN_WARNING "hw_bitblt_1: Unsupported width/height " | ||
118 | "%d %d\n", width, height); | ||
119 | return -EINVAL; | ||
120 | } | ||
121 | tmp = (width - 1) | ((height - 1) << 16); | ||
122 | writel(tmp, engine + 0x10); | ||
123 | |||
124 | if (op != VIA_BITBLT_COLOR) | ||
125 | writel(fg_color, engine + 0x18); | ||
126 | |||
127 | if (op == VIA_BITBLT_MONO) | ||
128 | writel(bg_color, engine + 0x1C); | ||
129 | |||
130 | if (op != VIA_BITBLT_FILL) { | ||
131 | tmp = src_mem ? 0 : src_addr; | ||
132 | if (dst_addr & 0xE0000007) { | ||
133 | printk(KERN_WARNING "hw_bitblt_1: Unsupported source " | ||
134 | "address %X\n", tmp); | ||
135 | return -EINVAL; | ||
136 | } | ||
137 | tmp >>= 3; | ||
138 | writel(tmp, engine + 0x30); | ||
139 | } | ||
140 | |||
141 | if (dst_addr & 0xE0000007) { | ||
142 | printk(KERN_WARNING "hw_bitblt_1: Unsupported destination " | ||
143 | "address %X\n", dst_addr); | ||
144 | return -EINVAL; | ||
145 | } | ||
146 | tmp = dst_addr >> 3; | ||
147 | writel(tmp, engine + 0x34); | ||
148 | |||
149 | if (op == VIA_BITBLT_FILL) | ||
150 | tmp = 0; | ||
151 | else | ||
152 | tmp = src_pitch; | ||
153 | if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) { | ||
154 | printk(KERN_WARNING "hw_bitblt_1: Unsupported pitch %X %X\n", | ||
155 | tmp, dst_pitch); | ||
156 | return -EINVAL; | ||
157 | } | ||
158 | tmp = VIA_PITCH_ENABLE | (tmp >> 3) | (dst_pitch << (16 - 3)); | ||
159 | writel(tmp, engine + 0x38); | ||
160 | |||
161 | if (op == VIA_BITBLT_FILL) | ||
162 | ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001; | ||
163 | else { | ||
164 | ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */ | ||
165 | if (src_mem) | ||
166 | ge_cmd |= 0x00000040; | ||
167 | if (op == VIA_BITBLT_MONO) | ||
168 | ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000; | ||
169 | else | ||
170 | ge_cmd |= 0x00000001; | ||
171 | } | ||
172 | writel(ge_cmd, engine); | ||
173 | |||
174 | if (op == VIA_BITBLT_FILL || !src_mem) | ||
175 | return 0; | ||
176 | |||
177 | tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) + | ||
178 | 3) >> 2; | ||
179 | |||
180 | for (i = 0; i < tmp; i++) | ||
181 | writel(src_mem[i], engine + VIA_MMIO_BLTBASE); | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height, | ||
187 | u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y, | ||
188 | u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y, | ||
189 | u32 fg_color, u32 bg_color, u8 fill_rop) | ||
190 | { | ||
191 | u32 ge_cmd = 0, tmp, i; | ||
192 | int ret; | ||
193 | |||
194 | if (!op || op > 3) { | ||
195 | printk(KERN_WARNING "hw_bitblt_2: Invalid operation: %d\n", op); | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | |||
199 | if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) { | ||
200 | if (src_x < dst_x) { | ||
201 | ge_cmd |= 0x00008000; | ||
202 | src_x += width - 1; | ||
203 | dst_x += width - 1; | ||
204 | } | ||
205 | if (src_y < dst_y) { | ||
206 | ge_cmd |= 0x00004000; | ||
207 | src_y += height - 1; | ||
208 | dst_y += height - 1; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | if (op == VIA_BITBLT_FILL) { | ||
213 | switch (fill_rop) { | ||
214 | case 0x00: /* blackness */ | ||
215 | case 0x5A: /* pattern inversion */ | ||
216 | case 0xF0: /* pattern copy */ | ||
217 | case 0xFF: /* whiteness */ | ||
218 | break; | ||
219 | default: | ||
220 | printk(KERN_WARNING "hw_bitblt_2: Invalid fill rop: " | ||
221 | "%u\n", fill_rop); | ||
222 | return -EINVAL; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | ret = viafb_set_bpp(engine, dst_bpp); | ||
227 | if (ret) | ||
228 | return ret; | ||
229 | |||
230 | if (op == VIA_BITBLT_FILL) | ||
231 | tmp = 0; | ||
232 | else | ||
233 | tmp = src_pitch; | ||
234 | if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) { | ||
235 | printk(KERN_WARNING "hw_bitblt_2: Unsupported pitch %X %X\n", | ||
236 | tmp, dst_pitch); | ||
237 | return -EINVAL; | ||
238 | } | ||
239 | tmp = (tmp >> 3) | (dst_pitch << (16 - 3)); | ||
240 | writel(tmp, engine + 0x08); | ||
241 | |||
242 | if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) { | ||
243 | printk(KERN_WARNING "hw_bitblt_2: Unsupported width/height " | ||
244 | "%d %d\n", width, height); | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | tmp = (width - 1) | ((height - 1) << 16); | ||
248 | writel(tmp, engine + 0x0C); | ||
249 | |||
250 | if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) { | ||
251 | printk(KERN_WARNING "hw_bitblt_2: Unsupported destination x/y " | ||
252 | "%d %d\n", dst_x, dst_y); | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | tmp = dst_x | (dst_y << 16); | ||
256 | writel(tmp, engine + 0x10); | ||
257 | |||
258 | if (dst_addr & 0xE0000007) { | ||
259 | printk(KERN_WARNING "hw_bitblt_2: Unsupported destination " | ||
260 | "address %X\n", dst_addr); | ||
261 | return -EINVAL; | ||
262 | } | ||
263 | tmp = dst_addr >> 3; | ||
264 | writel(tmp, engine + 0x14); | ||
265 | |||
266 | if (op != VIA_BITBLT_FILL) { | ||
267 | if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000) | ||
268 | || src_y & 0xFFFFF000) { | ||
269 | printk(KERN_WARNING "hw_bitblt_2: Unsupported source " | ||
270 | "x/y %d %d\n", src_x, src_y); | ||
271 | return -EINVAL; | ||
272 | } | ||
273 | tmp = src_x | (src_y << 16); | ||
274 | writel(tmp, engine + 0x18); | ||
275 | |||
276 | tmp = src_mem ? 0 : src_addr; | ||
277 | if (dst_addr & 0xE0000007) { | ||
278 | printk(KERN_WARNING "hw_bitblt_2: Unsupported source " | ||
279 | "address %X\n", tmp); | ||
280 | return -EINVAL; | ||
281 | } | ||
282 | tmp >>= 3; | ||
283 | writel(tmp, engine + 0x1C); | ||
284 | } | ||
285 | |||
286 | if (op == VIA_BITBLT_FILL) { | ||
287 | writel(fg_color, engine + 0x58); | ||
288 | } else if (op == VIA_BITBLT_MONO) { | ||
289 | writel(fg_color, engine + 0x4C); | ||
290 | writel(bg_color, engine + 0x50); | ||
291 | } | ||
292 | |||
293 | if (op == VIA_BITBLT_FILL) | ||
294 | ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001; | ||
295 | else { | ||
296 | ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */ | ||
297 | if (src_mem) | ||
298 | ge_cmd |= 0x00000040; | ||
299 | if (op == VIA_BITBLT_MONO) | ||
300 | ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000; | ||
301 | else | ||
302 | ge_cmd |= 0x00000001; | ||
303 | } | ||
304 | writel(ge_cmd, engine); | ||
305 | |||
306 | if (op == VIA_BITBLT_FILL || !src_mem) | ||
307 | return 0; | ||
308 | |||
309 | tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) + | ||
310 | 3) >> 2; | ||
311 | |||
312 | for (i = 0; i < tmp; i++) | ||
313 | writel(src_mem[i], engine + VIA_MMIO_BLTBASE); | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | int viafb_setup_engine(struct fb_info *info) | ||
319 | { | ||
320 | struct viafb_par *viapar = info->par; | ||
321 | void __iomem *engine; | ||
322 | u32 chip_name = viapar->shared->chip_info.gfx_chip_name; | ||
323 | |||
324 | engine = viapar->shared->vdev->engine_mmio; | ||
325 | if (!engine) { | ||
326 | printk(KERN_WARNING "viafb_init_accel: ioremap failed, " | ||
327 | "hardware acceleration disabled\n"); | ||
328 | return -ENOMEM; | ||
329 | } | ||
330 | |||
331 | switch (chip_name) { | ||
332 | case UNICHROME_CLE266: | ||
333 | case UNICHROME_K400: | ||
334 | case UNICHROME_K800: | ||
335 | case UNICHROME_PM800: | ||
336 | case UNICHROME_CN700: | ||
337 | case UNICHROME_CX700: | ||
338 | case UNICHROME_CN750: | ||
339 | case UNICHROME_K8M890: | ||
340 | case UNICHROME_P4M890: | ||
341 | case UNICHROME_P4M900: | ||
342 | viapar->shared->hw_bitblt = hw_bitblt_1; | ||
343 | break; | ||
344 | case UNICHROME_VX800: | ||
345 | case UNICHROME_VX855: | ||
346 | case UNICHROME_VX900: | ||
347 | viapar->shared->hw_bitblt = hw_bitblt_2; | ||
348 | break; | ||
349 | default: | ||
350 | viapar->shared->hw_bitblt = NULL; | ||
351 | } | ||
352 | |||
353 | viapar->fbmem_free -= CURSOR_SIZE; | ||
354 | viapar->shared->cursor_vram_addr = viapar->fbmem_free; | ||
355 | viapar->fbmem_used += CURSOR_SIZE; | ||
356 | |||
357 | viapar->fbmem_free -= VQ_SIZE; | ||
358 | viapar->shared->vq_vram_addr = viapar->fbmem_free; | ||
359 | viapar->fbmem_used += VQ_SIZE; | ||
360 | |||
361 | #if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE) | ||
362 | /* | ||
363 | * Set aside a chunk of framebuffer memory for the camera | ||
364 | * driver. Someday this driver probably needs a proper allocator | ||
365 | * for fbmem; for now, we just have to do this before the | ||
366 | * framebuffer initializes itself. | ||
367 | * | ||
368 | * As for the size: the engine can handle three frames, | ||
369 | * 16 bits deep, up to VGA resolution. | ||
370 | */ | ||
371 | viapar->shared->vdev->camera_fbmem_size = 3*VGA_HEIGHT*VGA_WIDTH*2; | ||
372 | viapar->fbmem_free -= viapar->shared->vdev->camera_fbmem_size; | ||
373 | viapar->fbmem_used += viapar->shared->vdev->camera_fbmem_size; | ||
374 | viapar->shared->vdev->camera_fbmem_offset = viapar->fbmem_free; | ||
375 | #endif | ||
376 | |||
377 | viafb_reset_engine(viapar); | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | void viafb_reset_engine(struct viafb_par *viapar) | ||
382 | { | ||
383 | void __iomem *engine = viapar->shared->vdev->engine_mmio; | ||
384 | int highest_reg, i; | ||
385 | u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high, | ||
386 | vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name; | ||
387 | |||
388 | /* Initialize registers to reset the 2D engine */ | ||
389 | switch (viapar->shared->chip_info.twod_engine) { | ||
390 | case VIA_2D_ENG_M1: | ||
391 | highest_reg = 0x5c; | ||
392 | break; | ||
393 | default: | ||
394 | highest_reg = 0x40; | ||
395 | break; | ||
396 | } | ||
397 | for (i = 0; i <= highest_reg; i += 4) | ||
398 | writel(0x0, engine + i); | ||
399 | |||
400 | /* Init AGP and VQ regs */ | ||
401 | switch (chip_name) { | ||
402 | case UNICHROME_K8M890: | ||
403 | case UNICHROME_P4M900: | ||
404 | case UNICHROME_VX800: | ||
405 | case UNICHROME_VX855: | ||
406 | case UNICHROME_VX900: | ||
407 | writel(0x00100000, engine + VIA_REG_CR_TRANSET); | ||
408 | writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE); | ||
409 | writel(0x02000000, engine + VIA_REG_CR_TRANSPACE); | ||
410 | break; | ||
411 | |||
412 | default: | ||
413 | writel(0x00100000, engine + VIA_REG_TRANSET); | ||
414 | writel(0x00000000, engine + VIA_REG_TRANSPACE); | ||
415 | writel(0x00333004, engine + VIA_REG_TRANSPACE); | ||
416 | writel(0x60000000, engine + VIA_REG_TRANSPACE); | ||
417 | writel(0x61000000, engine + VIA_REG_TRANSPACE); | ||
418 | writel(0x62000000, engine + VIA_REG_TRANSPACE); | ||
419 | writel(0x63000000, engine + VIA_REG_TRANSPACE); | ||
420 | writel(0x64000000, engine + VIA_REG_TRANSPACE); | ||
421 | writel(0x7D000000, engine + VIA_REG_TRANSPACE); | ||
422 | |||
423 | writel(0xFE020000, engine + VIA_REG_TRANSET); | ||
424 | writel(0x00000000, engine + VIA_REG_TRANSPACE); | ||
425 | break; | ||
426 | } | ||
427 | |||
428 | /* Enable VQ */ | ||
429 | vq_start_addr = viapar->shared->vq_vram_addr; | ||
430 | vq_end_addr = viapar->shared->vq_vram_addr + VQ_SIZE - 1; | ||
431 | |||
432 | vq_start_low = 0x50000000 | (vq_start_addr & 0xFFFFFF); | ||
433 | vq_end_low = 0x51000000 | (vq_end_addr & 0xFFFFFF); | ||
434 | vq_high = 0x52000000 | ((vq_start_addr & 0xFF000000) >> 24) | | ||
435 | ((vq_end_addr & 0xFF000000) >> 16); | ||
436 | vq_len = 0x53000000 | (VQ_SIZE >> 3); | ||
437 | |||
438 | switch (chip_name) { | ||
439 | case UNICHROME_K8M890: | ||
440 | case UNICHROME_P4M900: | ||
441 | case UNICHROME_VX800: | ||
442 | case UNICHROME_VX855: | ||
443 | case UNICHROME_VX900: | ||
444 | vq_start_low |= 0x20000000; | ||
445 | vq_end_low |= 0x20000000; | ||
446 | vq_high |= 0x20000000; | ||
447 | vq_len |= 0x20000000; | ||
448 | |||
449 | writel(0x00100000, engine + VIA_REG_CR_TRANSET); | ||
450 | writel(vq_high, engine + VIA_REG_CR_TRANSPACE); | ||
451 | writel(vq_start_low, engine + VIA_REG_CR_TRANSPACE); | ||
452 | writel(vq_end_low, engine + VIA_REG_CR_TRANSPACE); | ||
453 | writel(vq_len, engine + VIA_REG_CR_TRANSPACE); | ||
454 | writel(0x74301001, engine + VIA_REG_CR_TRANSPACE); | ||
455 | writel(0x00000000, engine + VIA_REG_CR_TRANSPACE); | ||
456 | break; | ||
457 | default: | ||
458 | writel(0x00FE0000, engine + VIA_REG_TRANSET); | ||
459 | writel(0x080003FE, engine + VIA_REG_TRANSPACE); | ||
460 | writel(0x0A00027C, engine + VIA_REG_TRANSPACE); | ||
461 | writel(0x0B000260, engine + VIA_REG_TRANSPACE); | ||
462 | writel(0x0C000274, engine + VIA_REG_TRANSPACE); | ||
463 | writel(0x0D000264, engine + VIA_REG_TRANSPACE); | ||
464 | writel(0x0E000000, engine + VIA_REG_TRANSPACE); | ||
465 | writel(0x0F000020, engine + VIA_REG_TRANSPACE); | ||
466 | writel(0x1000027E, engine + VIA_REG_TRANSPACE); | ||
467 | writel(0x110002FE, engine + VIA_REG_TRANSPACE); | ||
468 | writel(0x200F0060, engine + VIA_REG_TRANSPACE); | ||
469 | |||
470 | writel(0x00000006, engine + VIA_REG_TRANSPACE); | ||
471 | writel(0x40008C0F, engine + VIA_REG_TRANSPACE); | ||
472 | writel(0x44000000, engine + VIA_REG_TRANSPACE); | ||
473 | writel(0x45080C04, engine + VIA_REG_TRANSPACE); | ||
474 | writel(0x46800408, engine + VIA_REG_TRANSPACE); | ||
475 | |||
476 | writel(vq_high, engine + VIA_REG_TRANSPACE); | ||
477 | writel(vq_start_low, engine + VIA_REG_TRANSPACE); | ||
478 | writel(vq_end_low, engine + VIA_REG_TRANSPACE); | ||
479 | writel(vq_len, engine + VIA_REG_TRANSPACE); | ||
480 | break; | ||
481 | } | ||
482 | |||
483 | /* Set Cursor Image Base Address */ | ||
484 | writel(viapar->shared->cursor_vram_addr, engine + VIA_REG_CURSOR_MODE); | ||
485 | writel(0x0, engine + VIA_REG_CURSOR_POS); | ||
486 | writel(0x0, engine + VIA_REG_CURSOR_ORG); | ||
487 | writel(0x0, engine + VIA_REG_CURSOR_BG); | ||
488 | writel(0x0, engine + VIA_REG_CURSOR_FG); | ||
489 | return; | ||
490 | } | ||
491 | |||
492 | void viafb_show_hw_cursor(struct fb_info *info, int Status) | ||
493 | { | ||
494 | struct viafb_par *viapar = info->par; | ||
495 | u32 temp, iga_path = viapar->iga_path; | ||
496 | |||
497 | temp = readl(viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE); | ||
498 | switch (Status) { | ||
499 | case HW_Cursor_ON: | ||
500 | temp |= 0x1; | ||
501 | break; | ||
502 | case HW_Cursor_OFF: | ||
503 | temp &= 0xFFFFFFFE; | ||
504 | break; | ||
505 | } | ||
506 | switch (iga_path) { | ||
507 | case IGA2: | ||
508 | temp |= 0x80000000; | ||
509 | break; | ||
510 | case IGA1: | ||
511 | default: | ||
512 | temp &= 0x7FFFFFFF; | ||
513 | } | ||
514 | writel(temp, viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE); | ||
515 | } | ||
516 | |||
517 | void viafb_wait_engine_idle(struct fb_info *info) | ||
518 | { | ||
519 | struct viafb_par *viapar = info->par; | ||
520 | int loop = 0; | ||
521 | u32 mask; | ||
522 | void __iomem *engine = viapar->shared->vdev->engine_mmio; | ||
523 | |||
524 | switch (viapar->shared->chip_info.twod_engine) { | ||
525 | case VIA_2D_ENG_H5: | ||
526 | case VIA_2D_ENG_M1: | ||
527 | mask = VIA_CMD_RGTR_BUSY_M1 | VIA_2D_ENG_BUSY_M1 | | ||
528 | VIA_3D_ENG_BUSY_M1; | ||
529 | break; | ||
530 | default: | ||
531 | while (!(readl(engine + VIA_REG_STATUS) & | ||
532 | VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) { | ||
533 | loop++; | ||
534 | cpu_relax(); | ||
535 | } | ||
536 | mask = VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY; | ||
537 | break; | ||
538 | } | ||
539 | |||
540 | while ((readl(engine + VIA_REG_STATUS) & mask) && (loop < MAXLOOP)) { | ||
541 | loop++; | ||
542 | cpu_relax(); | ||
543 | } | ||
544 | |||
545 | if (loop >= MAXLOOP) | ||
546 | printk(KERN_ERR "viafb_wait_engine_idle: not syncing\n"); | ||
547 | } | ||
diff --git a/drivers/video/fbdev/via/accel.h b/drivers/video/fbdev/via/accel.h new file mode 100644 index 000000000000..79d5e10cc835 --- /dev/null +++ b/drivers/video/fbdev/via/accel.h | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef __ACCEL_H__ | ||
23 | #define __ACCEL_H__ | ||
24 | |||
25 | #define FB_ACCEL_VIA_UNICHROME 50 | ||
26 | |||
27 | /* MMIO Base Address Definition */ | ||
28 | #define MMIO_VGABASE 0x8000 | ||
29 | #define MMIO_CR_READ (MMIO_VGABASE + 0x3D4) | ||
30 | #define MMIO_CR_WRITE (MMIO_VGABASE + 0x3D5) | ||
31 | #define MMIO_SR_READ (MMIO_VGABASE + 0x3C4) | ||
32 | #define MMIO_SR_WRITE (MMIO_VGABASE + 0x3C5) | ||
33 | |||
34 | /* HW Cursor Status Define */ | ||
35 | #define HW_Cursor_ON 0 | ||
36 | #define HW_Cursor_OFF 1 | ||
37 | |||
38 | #define CURSOR_SIZE (8 * 1024) | ||
39 | #define VQ_SIZE (256 * 1024) | ||
40 | |||
41 | #define VIA_MMIO_BLTBASE 0x200000 | ||
42 | #define VIA_MMIO_BLTSIZE 0x200000 | ||
43 | |||
44 | /* Defines for 2D registers */ | ||
45 | #define VIA_REG_GECMD 0x000 | ||
46 | #define VIA_REG_GEMODE 0x004 | ||
47 | #define VIA_REG_SRCPOS 0x008 | ||
48 | #define VIA_REG_DSTPOS 0x00C | ||
49 | /* width and height */ | ||
50 | #define VIA_REG_DIMENSION 0x010 | ||
51 | #define VIA_REG_PATADDR 0x014 | ||
52 | #define VIA_REG_FGCOLOR 0x018 | ||
53 | #define VIA_REG_BGCOLOR 0x01C | ||
54 | /* top and left of clipping */ | ||
55 | #define VIA_REG_CLIPTL 0x020 | ||
56 | /* bottom and right of clipping */ | ||
57 | #define VIA_REG_CLIPBR 0x024 | ||
58 | #define VIA_REG_OFFSET 0x028 | ||
59 | /* color key control */ | ||
60 | #define VIA_REG_KEYCONTROL 0x02C | ||
61 | #define VIA_REG_SRCBASE 0x030 | ||
62 | #define VIA_REG_DSTBASE 0x034 | ||
63 | /* pitch of src and dst */ | ||
64 | #define VIA_REG_PITCH 0x038 | ||
65 | #define VIA_REG_MONOPAT0 0x03C | ||
66 | #define VIA_REG_MONOPAT1 0x040 | ||
67 | /* from 0x100 to 0x1ff */ | ||
68 | #define VIA_REG_COLORPAT 0x100 | ||
69 | |||
70 | /* defines for VIA 2D registers for vt3353/3409 (M1 engine)*/ | ||
71 | #define VIA_REG_GECMD_M1 0x000 | ||
72 | #define VIA_REG_GEMODE_M1 0x004 | ||
73 | #define VIA_REG_GESTATUS_M1 0x004 /* as same as VIA_REG_GEMODE */ | ||
74 | #define VIA_REG_PITCH_M1 0x008 /* pitch of src and dst */ | ||
75 | #define VIA_REG_DIMENSION_M1 0x00C /* width and height */ | ||
76 | #define VIA_REG_DSTPOS_M1 0x010 | ||
77 | #define VIA_REG_LINE_XY_M1 0x010 | ||
78 | #define VIA_REG_DSTBASE_M1 0x014 | ||
79 | #define VIA_REG_SRCPOS_M1 0x018 | ||
80 | #define VIA_REG_LINE_K1K2_M1 0x018 | ||
81 | #define VIA_REG_SRCBASE_M1 0x01C | ||
82 | #define VIA_REG_PATADDR_M1 0x020 | ||
83 | #define VIA_REG_MONOPAT0_M1 0x024 | ||
84 | #define VIA_REG_MONOPAT1_M1 0x028 | ||
85 | #define VIA_REG_OFFSET_M1 0x02C | ||
86 | #define VIA_REG_LINE_ERROR_M1 0x02C | ||
87 | #define VIA_REG_CLIPTL_M1 0x040 /* top and left of clipping */ | ||
88 | #define VIA_REG_CLIPBR_M1 0x044 /* bottom and right of clipping */ | ||
89 | #define VIA_REG_KEYCONTROL_M1 0x048 /* color key control */ | ||
90 | #define VIA_REG_FGCOLOR_M1 0x04C | ||
91 | #define VIA_REG_DSTCOLORKEY_M1 0x04C /* as same as VIA_REG_FG */ | ||
92 | #define VIA_REG_BGCOLOR_M1 0x050 | ||
93 | #define VIA_REG_SRCCOLORKEY_M1 0x050 /* as same as VIA_REG_BG */ | ||
94 | #define VIA_REG_MONOPATFGC_M1 0x058 /* Add BG color of Pattern. */ | ||
95 | #define VIA_REG_MONOPATBGC_M1 0x05C /* Add FG color of Pattern. */ | ||
96 | #define VIA_REG_COLORPAT_M1 0x100 /* from 0x100 to 0x1ff */ | ||
97 | |||
98 | /* VIA_REG_PITCH(0x38): Pitch Setting */ | ||
99 | #define VIA_PITCH_ENABLE 0x80000000 | ||
100 | |||
101 | /* defines for VIA HW cursor registers */ | ||
102 | #define VIA_REG_CURSOR_MODE 0x2D0 | ||
103 | #define VIA_REG_CURSOR_POS 0x2D4 | ||
104 | #define VIA_REG_CURSOR_ORG 0x2D8 | ||
105 | #define VIA_REG_CURSOR_BG 0x2DC | ||
106 | #define VIA_REG_CURSOR_FG 0x2E0 | ||
107 | |||
108 | /* VIA_REG_GEMODE(0x04): GE mode */ | ||
109 | #define VIA_GEM_8bpp 0x00000000 | ||
110 | #define VIA_GEM_16bpp 0x00000100 | ||
111 | #define VIA_GEM_32bpp 0x00000300 | ||
112 | |||
113 | /* VIA_REG_GECMD(0x00): 2D Engine Command */ | ||
114 | #define VIA_GEC_NOOP 0x00000000 | ||
115 | #define VIA_GEC_BLT 0x00000001 | ||
116 | #define VIA_GEC_LINE 0x00000005 | ||
117 | |||
118 | /* Rotate Command */ | ||
119 | #define VIA_GEC_ROT 0x00000008 | ||
120 | |||
121 | #define VIA_GEC_SRC_XY 0x00000000 | ||
122 | #define VIA_GEC_SRC_LINEAR 0x00000010 | ||
123 | #define VIA_GEC_DST_XY 0x00000000 | ||
124 | #define VIA_GEC_DST_LINRAT 0x00000020 | ||
125 | |||
126 | #define VIA_GEC_SRC_FB 0x00000000 | ||
127 | #define VIA_GEC_SRC_SYS 0x00000040 | ||
128 | #define VIA_GEC_DST_FB 0x00000000 | ||
129 | #define VIA_GEC_DST_SYS 0x00000080 | ||
130 | |||
131 | /* source is mono */ | ||
132 | #define VIA_GEC_SRC_MONO 0x00000100 | ||
133 | /* pattern is mono */ | ||
134 | #define VIA_GEC_PAT_MONO 0x00000200 | ||
135 | /* mono src is opaque */ | ||
136 | #define VIA_GEC_MSRC_OPAQUE 0x00000000 | ||
137 | /* mono src is transparent */ | ||
138 | #define VIA_GEC_MSRC_TRANS 0x00000400 | ||
139 | /* pattern is in frame buffer */ | ||
140 | #define VIA_GEC_PAT_FB 0x00000000 | ||
141 | /* pattern is from reg setting */ | ||
142 | #define VIA_GEC_PAT_REG 0x00000800 | ||
143 | |||
144 | #define VIA_GEC_CLIP_DISABLE 0x00000000 | ||
145 | #define VIA_GEC_CLIP_ENABLE 0x00001000 | ||
146 | |||
147 | #define VIA_GEC_FIXCOLOR_PAT 0x00002000 | ||
148 | |||
149 | #define VIA_GEC_INCX 0x00000000 | ||
150 | #define VIA_GEC_DECY 0x00004000 | ||
151 | #define VIA_GEC_INCY 0x00000000 | ||
152 | #define VIA_GEC_DECX 0x00008000 | ||
153 | /* mono pattern is opaque */ | ||
154 | #define VIA_GEC_MPAT_OPAQUE 0x00000000 | ||
155 | /* mono pattern is transparent */ | ||
156 | #define VIA_GEC_MPAT_TRANS 0x00010000 | ||
157 | |||
158 | #define VIA_GEC_MONO_UNPACK 0x00000000 | ||
159 | #define VIA_GEC_MONO_PACK 0x00020000 | ||
160 | #define VIA_GEC_MONO_DWORD 0x00000000 | ||
161 | #define VIA_GEC_MONO_WORD 0x00040000 | ||
162 | #define VIA_GEC_MONO_BYTE 0x00080000 | ||
163 | |||
164 | #define VIA_GEC_LASTPIXEL_ON 0x00000000 | ||
165 | #define VIA_GEC_LASTPIXEL_OFF 0x00100000 | ||
166 | #define VIA_GEC_X_MAJOR 0x00000000 | ||
167 | #define VIA_GEC_Y_MAJOR 0x00200000 | ||
168 | #define VIA_GEC_QUICK_START 0x00800000 | ||
169 | |||
170 | /* defines for VIA 3D registers */ | ||
171 | #define VIA_REG_STATUS 0x400 | ||
172 | #define VIA_REG_CR_TRANSET 0x41C | ||
173 | #define VIA_REG_CR_TRANSPACE 0x420 | ||
174 | #define VIA_REG_TRANSET 0x43C | ||
175 | #define VIA_REG_TRANSPACE 0x440 | ||
176 | |||
177 | /* VIA_REG_STATUS(0x400): Engine Status */ | ||
178 | |||
179 | /* Command Regulator is busy */ | ||
180 | #define VIA_CMD_RGTR_BUSY 0x00000080 | ||
181 | /* 2D Engine is busy */ | ||
182 | #define VIA_2D_ENG_BUSY 0x00000002 | ||
183 | /* 3D Engine is busy */ | ||
184 | #define VIA_3D_ENG_BUSY 0x00000001 | ||
185 | /* Virtual Queue is busy */ | ||
186 | #define VIA_VR_QUEUE_BUSY 0x00020000 | ||
187 | |||
188 | /* VIA_REG_STATUS(0x400): Engine Status for H5 */ | ||
189 | #define VIA_CMD_RGTR_BUSY_H5 0x00000010 /* Command Regulator is busy */ | ||
190 | #define VIA_2D_ENG_BUSY_H5 0x00000002 /* 2D Engine is busy */ | ||
191 | #define VIA_3D_ENG_BUSY_H5 0x00001FE1 /* 3D Engine is busy */ | ||
192 | #define VIA_VR_QUEUE_BUSY_H5 0x00000004 /* Virtual Queue is busy */ | ||
193 | |||
194 | /* VIA_REG_STATUS(0x400): Engine Status for VT3353/3409 */ | ||
195 | #define VIA_CMD_RGTR_BUSY_M1 0x00000010 /* Command Regulator is busy */ | ||
196 | #define VIA_2D_ENG_BUSY_M1 0x00000002 /* 2D Engine is busy */ | ||
197 | #define VIA_3D_ENG_BUSY_M1 0x00001FE1 /* 3D Engine is busy */ | ||
198 | #define VIA_VR_QUEUE_BUSY_M1 0x00000004 /* Virtual Queue is busy */ | ||
199 | |||
200 | #define MAXLOOP 0xFFFFFF | ||
201 | |||
202 | #define VIA_BITBLT_COLOR 1 | ||
203 | #define VIA_BITBLT_MONO 2 | ||
204 | #define VIA_BITBLT_FILL 3 | ||
205 | |||
206 | int viafb_setup_engine(struct fb_info *info); | ||
207 | void viafb_reset_engine(struct viafb_par *viapar); | ||
208 | void viafb_show_hw_cursor(struct fb_info *info, int Status); | ||
209 | void viafb_wait_engine_idle(struct fb_info *info); | ||
210 | |||
211 | #endif /* __ACCEL_H__ */ | ||
diff --git a/drivers/video/fbdev/via/chip.h b/drivers/video/fbdev/via/chip.h new file mode 100644 index 000000000000..d32a5076c20f --- /dev/null +++ b/drivers/video/fbdev/via/chip.h | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #ifndef __CHIP_H__ | ||
22 | #define __CHIP_H__ | ||
23 | |||
24 | #include "global.h" | ||
25 | |||
26 | /***************************************/ | ||
27 | /* Definition Graphic Chip Information */ | ||
28 | /***************************************/ | ||
29 | |||
30 | #define PCI_VIA_VENDOR_ID 0x1106 | ||
31 | |||
32 | /* Define VIA Graphic Chip Name */ | ||
33 | #define UNICHROME_CLE266 1 | ||
34 | #define UNICHROME_CLE266_DID 0x3122 | ||
35 | #define CLE266_REVISION_AX 0x0A | ||
36 | #define CLE266_REVISION_CX 0x0C | ||
37 | |||
38 | #define UNICHROME_K400 2 | ||
39 | #define UNICHROME_K400_DID 0x7205 | ||
40 | |||
41 | #define UNICHROME_K800 3 | ||
42 | #define UNICHROME_K800_DID 0x3108 | ||
43 | |||
44 | #define UNICHROME_PM800 4 | ||
45 | #define UNICHROME_PM800_DID 0x3118 | ||
46 | |||
47 | #define UNICHROME_CN700 5 | ||
48 | #define UNICHROME_CN700_DID 0x3344 | ||
49 | |||
50 | #define UNICHROME_CX700 6 | ||
51 | #define UNICHROME_CX700_DID 0x3157 | ||
52 | #define CX700_REVISION_700 0x0 | ||
53 | #define CX700_REVISION_700M 0x1 | ||
54 | #define CX700_REVISION_700M2 0x2 | ||
55 | |||
56 | #define UNICHROME_CN750 7 | ||
57 | #define UNICHROME_CN750_DID 0x3225 | ||
58 | |||
59 | #define UNICHROME_K8M890 8 | ||
60 | #define UNICHROME_K8M890_DID 0x3230 | ||
61 | |||
62 | #define UNICHROME_P4M890 9 | ||
63 | #define UNICHROME_P4M890_DID 0x3343 | ||
64 | |||
65 | #define UNICHROME_P4M900 10 | ||
66 | #define UNICHROME_P4M900_DID 0x3371 | ||
67 | |||
68 | #define UNICHROME_VX800 11 | ||
69 | #define UNICHROME_VX800_DID 0x1122 | ||
70 | |||
71 | #define UNICHROME_VX855 12 | ||
72 | #define UNICHROME_VX855_DID 0x5122 | ||
73 | |||
74 | #define UNICHROME_VX900 13 | ||
75 | #define UNICHROME_VX900_DID 0x7122 | ||
76 | |||
77 | /**************************************************/ | ||
78 | /* Definition TMDS Trasmitter Information */ | ||
79 | /**************************************************/ | ||
80 | |||
81 | /* Definition TMDS Trasmitter Index */ | ||
82 | #define NON_TMDS_TRANSMITTER 0x00 | ||
83 | #define VT1632_TMDS 0x01 | ||
84 | #define INTEGRATED_TMDS 0x42 | ||
85 | |||
86 | /* Definition TMDS Trasmitter I2C Slave Address */ | ||
87 | #define VT1632_TMDS_I2C_ADDR 0x10 | ||
88 | |||
89 | /**************************************************/ | ||
90 | /* Definition LVDS Trasmitter Information */ | ||
91 | /**************************************************/ | ||
92 | |||
93 | /* Definition LVDS Trasmitter Index */ | ||
94 | #define NON_LVDS_TRANSMITTER 0x00 | ||
95 | #define VT1631_LVDS 0x01 | ||
96 | #define VT1636_LVDS 0x0E | ||
97 | #define INTEGRATED_LVDS 0x41 | ||
98 | |||
99 | /* Definition Digital Transmitter Mode */ | ||
100 | #define TX_DATA_12_BITS 0x01 | ||
101 | #define TX_DATA_24_BITS 0x02 | ||
102 | #define TX_DATA_DDR_MODE 0x04 | ||
103 | #define TX_DATA_SDR_MODE 0x08 | ||
104 | |||
105 | /* Definition LVDS Trasmitter I2C Slave Address */ | ||
106 | #define VT1631_LVDS_I2C_ADDR 0x70 | ||
107 | #define VT3271_LVDS_I2C_ADDR 0x80 | ||
108 | #define VT1636_LVDS_I2C_ADDR 0x80 | ||
109 | |||
110 | struct tmds_chip_information { | ||
111 | int tmds_chip_name; | ||
112 | int tmds_chip_slave_addr; | ||
113 | int output_interface; | ||
114 | int i2c_port; | ||
115 | }; | ||
116 | |||
117 | struct lvds_chip_information { | ||
118 | int lvds_chip_name; | ||
119 | int lvds_chip_slave_addr; | ||
120 | int output_interface; | ||
121 | int i2c_port; | ||
122 | }; | ||
123 | |||
124 | /* The type of 2D engine */ | ||
125 | enum via_2d_engine { | ||
126 | VIA_2D_ENG_H2, | ||
127 | VIA_2D_ENG_H5, | ||
128 | VIA_2D_ENG_M1, | ||
129 | }; | ||
130 | |||
131 | struct chip_information { | ||
132 | int gfx_chip_name; | ||
133 | int gfx_chip_revision; | ||
134 | enum via_2d_engine twod_engine; | ||
135 | struct tmds_chip_information tmds_chip_info; | ||
136 | struct lvds_chip_information lvds_chip_info; | ||
137 | struct lvds_chip_information lvds_chip_info2; | ||
138 | }; | ||
139 | |||
140 | struct tmds_setting_information { | ||
141 | int iga_path; | ||
142 | int h_active; | ||
143 | int v_active; | ||
144 | int max_pixel_clock; | ||
145 | }; | ||
146 | |||
147 | struct lvds_setting_information { | ||
148 | int iga_path; | ||
149 | int lcd_panel_hres; | ||
150 | int lcd_panel_vres; | ||
151 | int display_method; | ||
152 | int device_lcd_dualedge; | ||
153 | int LCDDithering; | ||
154 | int lcd_mode; | ||
155 | u32 vclk; /*panel mode clock value */ | ||
156 | }; | ||
157 | |||
158 | struct GFX_DPA_SETTING { | ||
159 | int ClkRangeIndex; | ||
160 | u8 DVP0; /* CR96[3:0] */ | ||
161 | u8 DVP0DataDri_S1; /* SR2A[5] */ | ||
162 | u8 DVP0DataDri_S; /* SR1B[1] */ | ||
163 | u8 DVP0ClockDri_S1; /* SR2A[4] */ | ||
164 | u8 DVP0ClockDri_S; /* SR1E[2] */ | ||
165 | u8 DVP1; /* CR9B[3:0] */ | ||
166 | u8 DVP1Driving; /* SR65[3:0], Data and Clock driving */ | ||
167 | u8 DFPHigh; /* CR97[3:0] */ | ||
168 | u8 DFPLow; /* CR99[3:0] */ | ||
169 | |||
170 | }; | ||
171 | |||
172 | struct VT1636_DPA_SETTING { | ||
173 | u8 CLK_SEL_ST1; | ||
174 | u8 CLK_SEL_ST2; | ||
175 | }; | ||
176 | #endif /* __CHIP_H__ */ | ||
diff --git a/drivers/video/fbdev/via/debug.h b/drivers/video/fbdev/via/debug.h new file mode 100644 index 000000000000..86eacc2017f3 --- /dev/null +++ b/drivers/video/fbdev/via/debug.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #ifndef __DEBUG_H__ | ||
22 | #define __DEBUG_H__ | ||
23 | |||
24 | #ifndef VIAFB_DEBUG | ||
25 | #define VIAFB_DEBUG 0 | ||
26 | #endif | ||
27 | |||
28 | #if VIAFB_DEBUG | ||
29 | #define DEBUG_MSG(f, a...) printk(f, ## a) | ||
30 | #else | ||
31 | #define DEBUG_MSG(f, a...) | ||
32 | #endif | ||
33 | |||
34 | #define VIAFB_WARN 0 | ||
35 | #if VIAFB_WARN | ||
36 | #define WARN_MSG(f, a...) printk(f, ## a) | ||
37 | #else | ||
38 | #define WARN_MSG(f, a...) | ||
39 | #endif | ||
40 | |||
41 | #endif /* __DEBUG_H__ */ | ||
diff --git a/drivers/video/fbdev/via/dvi.c b/drivers/video/fbdev/via/dvi.c new file mode 100644 index 000000000000..7789553952d3 --- /dev/null +++ b/drivers/video/fbdev/via/dvi.c | |||
@@ -0,0 +1,478 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #include <linux/via-core.h> | ||
22 | #include <linux/via_i2c.h> | ||
23 | #include "global.h" | ||
24 | |||
25 | static void tmds_register_write(int index, u8 data); | ||
26 | static int tmds_register_read(int index); | ||
27 | static int tmds_register_read_bytes(int index, u8 *buff, int buff_len); | ||
28 | static void dvi_get_panel_size_from_DDCv1( | ||
29 | struct tmds_chip_information *tmds_chip, | ||
30 | struct tmds_setting_information *tmds_setting); | ||
31 | static int viafb_dvi_query_EDID(void); | ||
32 | |||
33 | static inline bool check_tmds_chip(int device_id_subaddr, int device_id) | ||
34 | { | ||
35 | return tmds_register_read(device_id_subaddr) == device_id; | ||
36 | } | ||
37 | |||
38 | void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, | ||
39 | struct tmds_setting_information *tmds_setting) | ||
40 | { | ||
41 | DEBUG_MSG(KERN_INFO "viafb_init_dvi_size()\n"); | ||
42 | |||
43 | viafb_dvi_sense(); | ||
44 | if (viafb_dvi_query_EDID() == 1) | ||
45 | dvi_get_panel_size_from_DDCv1(tmds_chip, tmds_setting); | ||
46 | |||
47 | return; | ||
48 | } | ||
49 | |||
50 | bool viafb_tmds_trasmitter_identify(void) | ||
51 | { | ||
52 | unsigned char sr2a = 0, sr1e = 0, sr3e = 0; | ||
53 | |||
54 | /* Turn on ouputting pad */ | ||
55 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
56 | case UNICHROME_K8M890: | ||
57 | /*=* DFP Low Pad on *=*/ | ||
58 | sr2a = viafb_read_reg(VIASR, SR2A); | ||
59 | viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1); | ||
60 | break; | ||
61 | |||
62 | case UNICHROME_P4M900: | ||
63 | case UNICHROME_P4M890: | ||
64 | /* DFP Low Pad on */ | ||
65 | sr2a = viafb_read_reg(VIASR, SR2A); | ||
66 | viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1); | ||
67 | /* DVP0 Pad on */ | ||
68 | sr1e = viafb_read_reg(VIASR, SR1E); | ||
69 | viafb_write_reg_mask(SR1E, VIASR, 0xC0, BIT6 + BIT7); | ||
70 | break; | ||
71 | |||
72 | default: | ||
73 | /* DVP0/DVP1 Pad on */ | ||
74 | sr1e = viafb_read_reg(VIASR, SR1E); | ||
75 | viafb_write_reg_mask(SR1E, VIASR, 0xF0, BIT4 + | ||
76 | BIT5 + BIT6 + BIT7); | ||
77 | /* SR3E[1]Multi-function selection: | ||
78 | 0 = Emulate I2C and DDC bus by GPIO2/3/4. */ | ||
79 | sr3e = viafb_read_reg(VIASR, SR3E); | ||
80 | viafb_write_reg_mask(SR3E, VIASR, 0x0, BIT5); | ||
81 | break; | ||
82 | } | ||
83 | |||
84 | /* Check for VT1632: */ | ||
85 | viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = VT1632_TMDS; | ||
86 | viaparinfo->chip_info-> | ||
87 | tmds_chip_info.tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR; | ||
88 | viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_31; | ||
89 | if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID)) { | ||
90 | /* | ||
91 | * Currently only support 12bits,dual edge,add 24bits mode later | ||
92 | */ | ||
93 | tmds_register_write(0x08, 0x3b); | ||
94 | |||
95 | DEBUG_MSG(KERN_INFO "\n VT1632 TMDS ! \n"); | ||
96 | DEBUG_MSG(KERN_INFO "\n %2d", | ||
97 | viaparinfo->chip_info->tmds_chip_info.tmds_chip_name); | ||
98 | DEBUG_MSG(KERN_INFO "\n %2d", | ||
99 | viaparinfo->chip_info->tmds_chip_info.i2c_port); | ||
100 | return true; | ||
101 | } else { | ||
102 | viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_2C; | ||
103 | if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID)) { | ||
104 | tmds_register_write(0x08, 0x3b); | ||
105 | DEBUG_MSG(KERN_INFO "\n VT1632 TMDS ! \n"); | ||
106 | DEBUG_MSG(KERN_INFO "\n %2d", | ||
107 | viaparinfo->chip_info-> | ||
108 | tmds_chip_info.tmds_chip_name); | ||
109 | DEBUG_MSG(KERN_INFO "\n %2d", | ||
110 | viaparinfo->chip_info-> | ||
111 | tmds_chip_info.i2c_port); | ||
112 | return true; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = INTEGRATED_TMDS; | ||
117 | |||
118 | if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) && | ||
119 | ((viafb_display_hardware_layout == HW_LAYOUT_DVI_ONLY) || | ||
120 | (viafb_display_hardware_layout == HW_LAYOUT_LCD_DVI))) { | ||
121 | DEBUG_MSG(KERN_INFO "\n Integrated TMDS ! \n"); | ||
122 | return true; | ||
123 | } | ||
124 | |||
125 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
126 | case UNICHROME_K8M890: | ||
127 | viafb_write_reg(SR2A, VIASR, sr2a); | ||
128 | break; | ||
129 | |||
130 | case UNICHROME_P4M900: | ||
131 | case UNICHROME_P4M890: | ||
132 | viafb_write_reg(SR2A, VIASR, sr2a); | ||
133 | viafb_write_reg(SR1E, VIASR, sr1e); | ||
134 | break; | ||
135 | |||
136 | default: | ||
137 | viafb_write_reg(SR1E, VIASR, sr1e); | ||
138 | viafb_write_reg(SR3E, VIASR, sr3e); | ||
139 | break; | ||
140 | } | ||
141 | |||
142 | viaparinfo->chip_info-> | ||
143 | tmds_chip_info.tmds_chip_name = NON_TMDS_TRANSMITTER; | ||
144 | viaparinfo->chip_info->tmds_chip_info. | ||
145 | tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR; | ||
146 | return false; | ||
147 | } | ||
148 | |||
149 | static void tmds_register_write(int index, u8 data) | ||
150 | { | ||
151 | viafb_i2c_writebyte(viaparinfo->chip_info->tmds_chip_info.i2c_port, | ||
152 | viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr, | ||
153 | index, data); | ||
154 | } | ||
155 | |||
156 | static int tmds_register_read(int index) | ||
157 | { | ||
158 | u8 data; | ||
159 | |||
160 | viafb_i2c_readbyte(viaparinfo->chip_info->tmds_chip_info.i2c_port, | ||
161 | (u8) viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr, | ||
162 | (u8) index, &data); | ||
163 | return data; | ||
164 | } | ||
165 | |||
166 | static int tmds_register_read_bytes(int index, u8 *buff, int buff_len) | ||
167 | { | ||
168 | viafb_i2c_readbytes(viaparinfo->chip_info->tmds_chip_info.i2c_port, | ||
169 | (u8) viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr, | ||
170 | (u8) index, buff, buff_len); | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | /* DVI Set Mode */ | ||
175 | void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, | ||
176 | u16 cxres, u16 cyres, int iga) | ||
177 | { | ||
178 | struct fb_var_screeninfo dvi_var = *var; | ||
179 | const struct fb_videomode *rb_mode; | ||
180 | int maxPixelClock; | ||
181 | |||
182 | maxPixelClock = viaparinfo->shared->tmds_setting_info.max_pixel_clock; | ||
183 | if (maxPixelClock && PICOS2KHZ(var->pixclock) / 1000 > maxPixelClock) { | ||
184 | rb_mode = viafb_get_best_rb_mode(var->xres, var->yres, 60); | ||
185 | if (rb_mode) | ||
186 | viafb_fill_var_timing_info(&dvi_var, rb_mode); | ||
187 | } | ||
188 | |||
189 | viafb_fill_crtc_timing(&dvi_var, cxres, cyres, iga); | ||
190 | } | ||
191 | |||
192 | /* Sense DVI Connector */ | ||
193 | int viafb_dvi_sense(void) | ||
194 | { | ||
195 | u8 RegSR1E = 0, RegSR3E = 0, RegCR6B = 0, RegCR91 = 0, | ||
196 | RegCR93 = 0, RegCR9B = 0, data; | ||
197 | int ret = false; | ||
198 | |||
199 | DEBUG_MSG(KERN_INFO "viafb_dvi_sense!!\n"); | ||
200 | |||
201 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { | ||
202 | /* DI1 Pad on */ | ||
203 | RegSR1E = viafb_read_reg(VIASR, SR1E); | ||
204 | viafb_write_reg(SR1E, VIASR, RegSR1E | 0x30); | ||
205 | |||
206 | /* CR6B[0]VCK Input Selection: 1 = External clock. */ | ||
207 | RegCR6B = viafb_read_reg(VIACR, CR6B); | ||
208 | viafb_write_reg(CR6B, VIACR, RegCR6B | 0x08); | ||
209 | |||
210 | /* CR91[4] VDD On [3] Data On [2] VEE On [1] Back Light Off | ||
211 | [0] Software Control Power Sequence */ | ||
212 | RegCR91 = viafb_read_reg(VIACR, CR91); | ||
213 | viafb_write_reg(CR91, VIACR, 0x1D); | ||
214 | |||
215 | /* CR93[7] DI1 Data Source Selection: 1 = DSP2. | ||
216 | CR93[5] DI1 Clock Source: 1 = internal. | ||
217 | CR93[4] DI1 Clock Polarity. | ||
218 | CR93[3:1] DI1 Clock Adjust. CR93[0] DI1 enable */ | ||
219 | RegCR93 = viafb_read_reg(VIACR, CR93); | ||
220 | viafb_write_reg(CR93, VIACR, 0x01); | ||
221 | } else { | ||
222 | /* DVP0/DVP1 Pad on */ | ||
223 | RegSR1E = viafb_read_reg(VIASR, SR1E); | ||
224 | viafb_write_reg(SR1E, VIASR, RegSR1E | 0xF0); | ||
225 | |||
226 | /* SR3E[1]Multi-function selection: | ||
227 | 0 = Emulate I2C and DDC bus by GPIO2/3/4. */ | ||
228 | RegSR3E = viafb_read_reg(VIASR, SR3E); | ||
229 | viafb_write_reg(SR3E, VIASR, RegSR3E & (~0x20)); | ||
230 | |||
231 | /* CR91[4] VDD On [3] Data On [2] VEE On [1] Back Light Off | ||
232 | [0] Software Control Power Sequence */ | ||
233 | RegCR91 = viafb_read_reg(VIACR, CR91); | ||
234 | viafb_write_reg(CR91, VIACR, 0x1D); | ||
235 | |||
236 | /*CR9B[4] DVP1 Data Source Selection: 1 = From secondary | ||
237 | display.CR9B[2:0] DVP1 Clock Adjust */ | ||
238 | RegCR9B = viafb_read_reg(VIACR, CR9B); | ||
239 | viafb_write_reg(CR9B, VIACR, 0x01); | ||
240 | } | ||
241 | |||
242 | data = (u8) tmds_register_read(0x09); | ||
243 | if (data & 0x04) | ||
244 | ret = true; | ||
245 | |||
246 | if (ret == false) { | ||
247 | if (viafb_dvi_query_EDID()) | ||
248 | ret = true; | ||
249 | } | ||
250 | |||
251 | /* Restore status */ | ||
252 | viafb_write_reg(SR1E, VIASR, RegSR1E); | ||
253 | viafb_write_reg(CR91, VIACR, RegCR91); | ||
254 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { | ||
255 | viafb_write_reg(CR6B, VIACR, RegCR6B); | ||
256 | viafb_write_reg(CR93, VIACR, RegCR93); | ||
257 | } else { | ||
258 | viafb_write_reg(SR3E, VIASR, RegSR3E); | ||
259 | viafb_write_reg(CR9B, VIACR, RegCR9B); | ||
260 | } | ||
261 | |||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | /* Query Flat Panel's EDID Table Version Through DVI Connector */ | ||
266 | static int viafb_dvi_query_EDID(void) | ||
267 | { | ||
268 | u8 data0, data1; | ||
269 | int restore; | ||
270 | |||
271 | DEBUG_MSG(KERN_INFO "viafb_dvi_query_EDID!!\n"); | ||
272 | |||
273 | restore = viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr; | ||
274 | viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = 0xA0; | ||
275 | |||
276 | data0 = (u8) tmds_register_read(0x00); | ||
277 | data1 = (u8) tmds_register_read(0x01); | ||
278 | if ((data0 == 0) && (data1 == 0xFF)) { | ||
279 | viaparinfo->chip_info-> | ||
280 | tmds_chip_info.tmds_chip_slave_addr = restore; | ||
281 | return EDID_VERSION_1; /* Found EDID1 Table */ | ||
282 | } | ||
283 | |||
284 | return false; | ||
285 | } | ||
286 | |||
287 | /* Get Panel Size Using EDID1 Table */ | ||
288 | static void dvi_get_panel_size_from_DDCv1( | ||
289 | struct tmds_chip_information *tmds_chip, | ||
290 | struct tmds_setting_information *tmds_setting) | ||
291 | { | ||
292 | int i, restore; | ||
293 | unsigned char EDID_DATA[18]; | ||
294 | |||
295 | DEBUG_MSG(KERN_INFO "\n dvi_get_panel_size_from_DDCv1 \n"); | ||
296 | |||
297 | restore = tmds_chip->tmds_chip_slave_addr; | ||
298 | tmds_chip->tmds_chip_slave_addr = 0xA0; | ||
299 | for (i = 0x25; i < 0x6D; i++) { | ||
300 | switch (i) { | ||
301 | case 0x36: | ||
302 | case 0x48: | ||
303 | case 0x5A: | ||
304 | case 0x6C: | ||
305 | tmds_register_read_bytes(i, EDID_DATA, 10); | ||
306 | if (!(EDID_DATA[0] || EDID_DATA[1])) { | ||
307 | /* The first two byte must be zero. */ | ||
308 | if (EDID_DATA[3] == 0xFD) { | ||
309 | /* To get max pixel clock. */ | ||
310 | tmds_setting->max_pixel_clock = | ||
311 | EDID_DATA[9] * 10; | ||
312 | } | ||
313 | } | ||
314 | break; | ||
315 | |||
316 | default: | ||
317 | break; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | DEBUG_MSG(KERN_INFO "DVI max pixelclock = %d\n", | ||
322 | tmds_setting->max_pixel_clock); | ||
323 | tmds_chip->tmds_chip_slave_addr = restore; | ||
324 | } | ||
325 | |||
326 | /* If Disable DVI, turn off pad */ | ||
327 | void viafb_dvi_disable(void) | ||
328 | { | ||
329 | if (viaparinfo->chip_info-> | ||
330 | tmds_chip_info.output_interface == INTERFACE_TMDS) | ||
331 | /* Turn off TMDS power. */ | ||
332 | viafb_write_reg(CRD2, VIACR, | ||
333 | viafb_read_reg(VIACR, CRD2) | 0x08); | ||
334 | } | ||
335 | |||
336 | static void dvi_patch_skew_dvp0(void) | ||
337 | { | ||
338 | /* Reset data driving first: */ | ||
339 | viafb_write_reg_mask(SR1B, VIASR, 0, BIT1); | ||
340 | viafb_write_reg_mask(SR2A, VIASR, 0, BIT4); | ||
341 | |||
342 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
343 | case UNICHROME_P4M890: | ||
344 | { | ||
345 | if ((viaparinfo->tmds_setting_info->h_active == 1600) && | ||
346 | (viaparinfo->tmds_setting_info->v_active == | ||
347 | 1200)) | ||
348 | viafb_write_reg_mask(CR96, VIACR, 0x03, | ||
349 | BIT0 + BIT1 + BIT2); | ||
350 | else | ||
351 | viafb_write_reg_mask(CR96, VIACR, 0x07, | ||
352 | BIT0 + BIT1 + BIT2); | ||
353 | break; | ||
354 | } | ||
355 | |||
356 | case UNICHROME_P4M900: | ||
357 | { | ||
358 | viafb_write_reg_mask(CR96, VIACR, 0x07, | ||
359 | BIT0 + BIT1 + BIT2 + BIT3); | ||
360 | viafb_write_reg_mask(SR1B, VIASR, 0x02, BIT1); | ||
361 | viafb_write_reg_mask(SR2A, VIASR, 0x10, BIT4); | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | default: | ||
366 | { | ||
367 | break; | ||
368 | } | ||
369 | } | ||
370 | } | ||
371 | |||
372 | static void dvi_patch_skew_dvp_low(void) | ||
373 | { | ||
374 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
375 | case UNICHROME_K8M890: | ||
376 | { | ||
377 | viafb_write_reg_mask(CR99, VIACR, 0x03, BIT0 + BIT1); | ||
378 | break; | ||
379 | } | ||
380 | |||
381 | case UNICHROME_P4M900: | ||
382 | { | ||
383 | viafb_write_reg_mask(CR99, VIACR, 0x08, | ||
384 | BIT0 + BIT1 + BIT2 + BIT3); | ||
385 | break; | ||
386 | } | ||
387 | |||
388 | case UNICHROME_P4M890: | ||
389 | { | ||
390 | viafb_write_reg_mask(CR99, VIACR, 0x0F, | ||
391 | BIT0 + BIT1 + BIT2 + BIT3); | ||
392 | break; | ||
393 | } | ||
394 | |||
395 | default: | ||
396 | { | ||
397 | break; | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | |||
402 | /* If Enable DVI, turn off pad */ | ||
403 | void viafb_dvi_enable(void) | ||
404 | { | ||
405 | u8 data; | ||
406 | |||
407 | switch (viaparinfo->chip_info->tmds_chip_info.output_interface) { | ||
408 | case INTERFACE_DVP0: | ||
409 | viafb_write_reg_mask(CR6B, VIACR, 0x01, BIT0); | ||
410 | viafb_write_reg_mask(CR6C, VIACR, 0x21, BIT0 + BIT5); | ||
411 | dvi_patch_skew_dvp0(); | ||
412 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) | ||
413 | tmds_register_write(0x88, 0x3b); | ||
414 | else | ||
415 | /*clear CR91[5] to direct on display period | ||
416 | in the secondary diplay path */ | ||
417 | via_write_reg_mask(VIACR, 0x91, 0x00, 0x20); | ||
418 | break; | ||
419 | |||
420 | case INTERFACE_DVP1: | ||
421 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) | ||
422 | viafb_write_reg_mask(CR93, VIACR, 0x21, BIT0 + BIT5); | ||
423 | |||
424 | /*fix dvi cann't be enabled with MB VT5718C4 - Al Zhang */ | ||
425 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) | ||
426 | tmds_register_write(0x88, 0x3b); | ||
427 | else | ||
428 | /*clear CR91[5] to direct on display period | ||
429 | in the secondary diplay path */ | ||
430 | via_write_reg_mask(VIACR, 0x91, 0x00, 0x20); | ||
431 | |||
432 | /*fix DVI cannot enable on EPIA-M board */ | ||
433 | if (viafb_platform_epia_dvi == 1) { | ||
434 | viafb_write_reg_mask(CR91, VIACR, 0x1f, 0x1f); | ||
435 | viafb_write_reg_mask(CR88, VIACR, 0x00, BIT6 + BIT0); | ||
436 | if (viafb_bus_width == 24) { | ||
437 | if (viafb_device_lcd_dualedge == 1) | ||
438 | data = 0x3F; | ||
439 | else | ||
440 | data = 0x37; | ||
441 | viafb_i2c_writebyte(viaparinfo->chip_info-> | ||
442 | tmds_chip_info.i2c_port, | ||
443 | viaparinfo->chip_info-> | ||
444 | tmds_chip_info.tmds_chip_slave_addr, | ||
445 | 0x08, data); | ||
446 | } | ||
447 | } | ||
448 | break; | ||
449 | |||
450 | case INTERFACE_DFP_HIGH: | ||
451 | if (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266) | ||
452 | via_write_reg_mask(VIACR, CR97, 0x03, 0x03); | ||
453 | |||
454 | via_write_reg_mask(VIACR, 0x91, 0x00, 0x20); | ||
455 | break; | ||
456 | |||
457 | case INTERFACE_DFP_LOW: | ||
458 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) | ||
459 | break; | ||
460 | |||
461 | dvi_patch_skew_dvp_low(); | ||
462 | via_write_reg_mask(VIACR, 0x91, 0x00, 0x20); | ||
463 | break; | ||
464 | |||
465 | case INTERFACE_TMDS: | ||
466 | /* Turn on Display period in the panel path. */ | ||
467 | viafb_write_reg_mask(CR91, VIACR, 0, BIT7); | ||
468 | |||
469 | /* Turn on TMDS power. */ | ||
470 | viafb_write_reg_mask(CRD2, VIACR, 0, BIT3); | ||
471 | break; | ||
472 | } | ||
473 | |||
474 | if (viaparinfo->tmds_setting_info->iga_path == IGA2) { | ||
475 | /* Disable LCD Scaling */ | ||
476 | viafb_write_reg_mask(CR79, VIACR, 0x00, BIT0); | ||
477 | } | ||
478 | } | ||
diff --git a/drivers/video/fbdev/via/dvi.h b/drivers/video/fbdev/via/dvi.h new file mode 100644 index 000000000000..4c6bfba57d11 --- /dev/null +++ b/drivers/video/fbdev/via/dvi.h | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef __DVI_H__ | ||
23 | #define __DVI_H__ | ||
24 | |||
25 | /*Definition TMDS Device ID register*/ | ||
26 | #define VT1632_DEVICE_ID_REG 0x02 | ||
27 | #define VT1632_DEVICE_ID 0x92 | ||
28 | |||
29 | #define GET_DVI_SIZE_BY_SYSTEM_BIOS 0x01 | ||
30 | #define GET_DVI_SIZE_BY_VGA_BIOS 0x02 | ||
31 | #define GET_DVI_SZIE_BY_HW_STRAPPING 0x03 | ||
32 | |||
33 | /* Definition DVI Panel ID*/ | ||
34 | /* Resolution: 640x480, Channel: single, Dithering: Enable */ | ||
35 | #define DVI_PANEL_ID0_640X480 0x00 | ||
36 | /* Resolution: 800x600, Channel: single, Dithering: Enable */ | ||
37 | #define DVI_PANEL_ID1_800x600 0x01 | ||
38 | /* Resolution: 1024x768, Channel: single, Dithering: Enable */ | ||
39 | #define DVI_PANEL_ID1_1024x768 0x02 | ||
40 | /* Resolution: 1280x768, Channel: single, Dithering: Enable */ | ||
41 | #define DVI_PANEL_ID1_1280x768 0x03 | ||
42 | /* Resolution: 1280x1024, Channel: dual, Dithering: Enable */ | ||
43 | #define DVI_PANEL_ID1_1280x1024 0x04 | ||
44 | /* Resolution: 1400x1050, Channel: dual, Dithering: Enable */ | ||
45 | #define DVI_PANEL_ID1_1400x1050 0x05 | ||
46 | /* Resolution: 1600x1200, Channel: dual, Dithering: Enable */ | ||
47 | #define DVI_PANEL_ID1_1600x1200 0x06 | ||
48 | |||
49 | /* Define the version of EDID*/ | ||
50 | #define EDID_VERSION_1 1 | ||
51 | #define EDID_VERSION_2 2 | ||
52 | |||
53 | #define DEV_CONNECT_DVI 0x01 | ||
54 | #define DEV_CONNECT_HDMI 0x02 | ||
55 | |||
56 | int viafb_dvi_sense(void); | ||
57 | void viafb_dvi_disable(void); | ||
58 | void viafb_dvi_enable(void); | ||
59 | bool viafb_tmds_trasmitter_identify(void); | ||
60 | void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, | ||
61 | struct tmds_setting_information *tmds_setting); | ||
62 | void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, | ||
63 | u16 cxres, u16 cyres, int iga); | ||
64 | |||
65 | #endif /* __DVI_H__ */ | ||
diff --git a/drivers/video/fbdev/via/global.c b/drivers/video/fbdev/via/global.c new file mode 100644 index 000000000000..3102171c1674 --- /dev/null +++ b/drivers/video/fbdev/via/global.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #include "global.h" | ||
22 | int viafb_platform_epia_dvi = STATE_OFF; | ||
23 | int viafb_device_lcd_dualedge = STATE_OFF; | ||
24 | int viafb_bus_width = 12; | ||
25 | int viafb_display_hardware_layout = HW_LAYOUT_LCD_DVI; | ||
26 | int viafb_DeviceStatus = CRT_Device; | ||
27 | int viafb_hotplug; | ||
28 | int viafb_refresh = 60; | ||
29 | int viafb_refresh1 = 60; | ||
30 | int viafb_lcd_dsp_method = LCD_EXPANDSION; | ||
31 | int viafb_lcd_mode = LCD_OPENLDI; | ||
32 | int viafb_CRT_ON = 1; | ||
33 | int viafb_DVI_ON; | ||
34 | int viafb_LCD_ON ; | ||
35 | int viafb_LCD2_ON; | ||
36 | int viafb_SAMM_ON; | ||
37 | int viafb_dual_fb; | ||
38 | unsigned int viafb_second_xres = 640; | ||
39 | unsigned int viafb_second_yres = 480; | ||
40 | int viafb_hotplug_Xres = 640; | ||
41 | int viafb_hotplug_Yres = 480; | ||
42 | int viafb_hotplug_bpp = 32; | ||
43 | int viafb_hotplug_refresh = 60; | ||
44 | int viafb_primary_dev = None_Device; | ||
45 | int viafb_lcd_panel_id = LCD_PANEL_ID_MAXIMUM + 1; | ||
46 | struct fb_info *viafbinfo; | ||
47 | struct fb_info *viafbinfo1; | ||
48 | struct viafb_par *viaparinfo; | ||
49 | struct viafb_par *viaparinfo1; | ||
50 | |||
diff --git a/drivers/video/fbdev/via/global.h b/drivers/video/fbdev/via/global.h new file mode 100644 index 000000000000..275dbbbd6b81 --- /dev/null +++ b/drivers/video/fbdev/via/global.h | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef __GLOBAL_H__ | ||
23 | #define __GLOBAL_H__ | ||
24 | |||
25 | #include <linux/fb.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/ioport.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/io.h> | ||
30 | #include <linux/uaccess.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/proc_fs.h> | ||
33 | #include <linux/console.h> | ||
34 | #include <linux/timer.h> | ||
35 | |||
36 | #include "debug.h" | ||
37 | |||
38 | #include "viafbdev.h" | ||
39 | #include "chip.h" | ||
40 | #include "accel.h" | ||
41 | #include "share.h" | ||
42 | #include "dvi.h" | ||
43 | #include "viamode.h" | ||
44 | #include "hw.h" | ||
45 | |||
46 | #include "lcd.h" | ||
47 | #include "ioctl.h" | ||
48 | #include "via_utility.h" | ||
49 | #include "vt1636.h" | ||
50 | #include "tblDPASetting.h" | ||
51 | |||
52 | /* External struct*/ | ||
53 | |||
54 | extern int viafb_platform_epia_dvi; | ||
55 | extern int viafb_device_lcd_dualedge; | ||
56 | extern int viafb_bus_width; | ||
57 | extern int viafb_display_hardware_layout; | ||
58 | extern struct offset offset_reg; | ||
59 | extern struct viafb_par *viaparinfo; | ||
60 | extern struct viafb_par *viaparinfo1; | ||
61 | extern struct fb_info *viafbinfo; | ||
62 | extern struct fb_info *viafbinfo1; | ||
63 | extern int viafb_DeviceStatus; | ||
64 | extern int viafb_refresh; | ||
65 | extern int viafb_refresh1; | ||
66 | extern int viafb_lcd_dsp_method; | ||
67 | extern int viafb_lcd_mode; | ||
68 | |||
69 | extern int viafb_CRT_ON; | ||
70 | extern unsigned int viafb_second_xres; | ||
71 | extern unsigned int viafb_second_yres; | ||
72 | extern int viafb_hotplug_Xres; | ||
73 | extern int viafb_hotplug_Yres; | ||
74 | extern int viafb_hotplug_bpp; | ||
75 | extern int viafb_hotplug_refresh; | ||
76 | extern int viafb_primary_dev; | ||
77 | |||
78 | extern int viafb_lcd_panel_id; | ||
79 | |||
80 | #endif /* __GLOBAL_H__ */ | ||
diff --git a/drivers/video/fbdev/via/hw.c b/drivers/video/fbdev/via/hw.c new file mode 100644 index 000000000000..22450908306c --- /dev/null +++ b/drivers/video/fbdev/via/hw.c | |||
@@ -0,0 +1,2134 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/via-core.h> | ||
23 | #include <asm/olpc.h> | ||
24 | #include "global.h" | ||
25 | #include "via_clock.h" | ||
26 | |||
27 | static struct pll_limit cle266_pll_limits[] = { | ||
28 | {19, 19, 4, 0}, | ||
29 | {26, 102, 5, 0}, | ||
30 | {53, 112, 6, 0}, | ||
31 | {41, 100, 7, 0}, | ||
32 | {83, 108, 8, 0}, | ||
33 | {87, 118, 9, 0}, | ||
34 | {95, 115, 12, 0}, | ||
35 | {108, 108, 13, 0}, | ||
36 | {83, 83, 17, 0}, | ||
37 | {67, 98, 20, 0}, | ||
38 | {121, 121, 24, 0}, | ||
39 | {99, 99, 29, 0}, | ||
40 | {33, 33, 3, 1}, | ||
41 | {15, 23, 4, 1}, | ||
42 | {37, 121, 5, 1}, | ||
43 | {82, 82, 6, 1}, | ||
44 | {31, 84, 7, 1}, | ||
45 | {83, 83, 8, 1}, | ||
46 | {76, 127, 9, 1}, | ||
47 | {33, 121, 4, 2}, | ||
48 | {91, 118, 5, 2}, | ||
49 | {83, 109, 6, 2}, | ||
50 | {90, 90, 7, 2}, | ||
51 | {93, 93, 2, 3}, | ||
52 | {53, 53, 3, 3}, | ||
53 | {73, 117, 4, 3}, | ||
54 | {101, 127, 5, 3}, | ||
55 | {99, 99, 7, 3} | ||
56 | }; | ||
57 | |||
58 | static struct pll_limit k800_pll_limits[] = { | ||
59 | {22, 22, 2, 0}, | ||
60 | {28, 28, 3, 0}, | ||
61 | {81, 112, 3, 1}, | ||
62 | {86, 166, 4, 1}, | ||
63 | {109, 153, 5, 1}, | ||
64 | {66, 116, 3, 2}, | ||
65 | {93, 137, 4, 2}, | ||
66 | {117, 208, 5, 2}, | ||
67 | {30, 30, 2, 3}, | ||
68 | {69, 125, 3, 3}, | ||
69 | {89, 161, 4, 3}, | ||
70 | {121, 208, 5, 3}, | ||
71 | {66, 66, 2, 4}, | ||
72 | {85, 85, 3, 4}, | ||
73 | {141, 161, 4, 4}, | ||
74 | {177, 177, 5, 4} | ||
75 | }; | ||
76 | |||
77 | static struct pll_limit cx700_pll_limits[] = { | ||
78 | {98, 98, 3, 1}, | ||
79 | {86, 86, 4, 1}, | ||
80 | {109, 208, 5, 1}, | ||
81 | {68, 68, 2, 2}, | ||
82 | {95, 116, 3, 2}, | ||
83 | {93, 166, 4, 2}, | ||
84 | {110, 206, 5, 2}, | ||
85 | {174, 174, 7, 2}, | ||
86 | {82, 109, 3, 3}, | ||
87 | {117, 161, 4, 3}, | ||
88 | {112, 208, 5, 3}, | ||
89 | {141, 202, 5, 4} | ||
90 | }; | ||
91 | |||
92 | static struct pll_limit vx855_pll_limits[] = { | ||
93 | {86, 86, 4, 1}, | ||
94 | {108, 208, 5, 1}, | ||
95 | {110, 208, 5, 2}, | ||
96 | {83, 112, 3, 3}, | ||
97 | {103, 161, 4, 3}, | ||
98 | {112, 209, 5, 3}, | ||
99 | {142, 161, 4, 4}, | ||
100 | {141, 176, 5, 4} | ||
101 | }; | ||
102 | |||
103 | /* according to VIA Technologies these values are based on experiment */ | ||
104 | static struct io_reg scaling_parameters[] = { | ||
105 | {VIACR, CR7A, 0xFF, 0x01}, /* LCD Scaling Parameter 1 */ | ||
106 | {VIACR, CR7B, 0xFF, 0x02}, /* LCD Scaling Parameter 2 */ | ||
107 | {VIACR, CR7C, 0xFF, 0x03}, /* LCD Scaling Parameter 3 */ | ||
108 | {VIACR, CR7D, 0xFF, 0x04}, /* LCD Scaling Parameter 4 */ | ||
109 | {VIACR, CR7E, 0xFF, 0x07}, /* LCD Scaling Parameter 5 */ | ||
110 | {VIACR, CR7F, 0xFF, 0x0A}, /* LCD Scaling Parameter 6 */ | ||
111 | {VIACR, CR80, 0xFF, 0x0D}, /* LCD Scaling Parameter 7 */ | ||
112 | {VIACR, CR81, 0xFF, 0x13}, /* LCD Scaling Parameter 8 */ | ||
113 | {VIACR, CR82, 0xFF, 0x16}, /* LCD Scaling Parameter 9 */ | ||
114 | {VIACR, CR83, 0xFF, 0x19}, /* LCD Scaling Parameter 10 */ | ||
115 | {VIACR, CR84, 0xFF, 0x1C}, /* LCD Scaling Parameter 11 */ | ||
116 | {VIACR, CR85, 0xFF, 0x1D}, /* LCD Scaling Parameter 12 */ | ||
117 | {VIACR, CR86, 0xFF, 0x1E}, /* LCD Scaling Parameter 13 */ | ||
118 | {VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */ | ||
119 | }; | ||
120 | |||
121 | static struct io_reg common_vga[] = { | ||
122 | {VIACR, CR07, 0x10, 0x10}, /* [0] vertical total (bit 8) | ||
123 | [1] vertical display end (bit 8) | ||
124 | [2] vertical retrace start (bit 8) | ||
125 | [3] start vertical blanking (bit 8) | ||
126 | [4] line compare (bit 8) | ||
127 | [5] vertical total (bit 9) | ||
128 | [6] vertical display end (bit 9) | ||
129 | [7] vertical retrace start (bit 9) */ | ||
130 | {VIACR, CR08, 0xFF, 0x00}, /* [0-4] preset row scan | ||
131 | [5-6] byte panning */ | ||
132 | {VIACR, CR09, 0xDF, 0x40}, /* [0-4] max scan line | ||
133 | [5] start vertical blanking (bit 9) | ||
134 | [6] line compare (bit 9) | ||
135 | [7] scan doubling */ | ||
136 | {VIACR, CR0A, 0xFF, 0x1E}, /* [0-4] cursor start | ||
137 | [5] cursor disable */ | ||
138 | {VIACR, CR0B, 0xFF, 0x00}, /* [0-4] cursor end | ||
139 | [5-6] cursor skew */ | ||
140 | {VIACR, CR0E, 0xFF, 0x00}, /* [0-7] cursor location (high) */ | ||
141 | {VIACR, CR0F, 0xFF, 0x00}, /* [0-7] cursor location (low) */ | ||
142 | {VIACR, CR11, 0xF0, 0x80}, /* [0-3] vertical retrace end | ||
143 | [6] memory refresh bandwidth | ||
144 | [7] CRTC register protect enable */ | ||
145 | {VIACR, CR14, 0xFF, 0x00}, /* [0-4] underline location | ||
146 | [5] divide memory address clock by 4 | ||
147 | [6] double word addressing */ | ||
148 | {VIACR, CR17, 0xFF, 0x63}, /* [0-1] mapping of display address 13-14 | ||
149 | [2] divide scan line clock by 2 | ||
150 | [3] divide memory address clock by 2 | ||
151 | [5] address wrap | ||
152 | [6] byte mode select | ||
153 | [7] sync enable */ | ||
154 | {VIACR, CR18, 0xFF, 0xFF}, /* [0-7] line compare */ | ||
155 | }; | ||
156 | |||
157 | static struct fifo_depth_select display_fifo_depth_reg = { | ||
158 | /* IGA1 FIFO Depth_Select */ | ||
159 | {IGA1_FIFO_DEPTH_SELECT_REG_NUM, {{SR17, 0, 7} } }, | ||
160 | /* IGA2 FIFO Depth_Select */ | ||
161 | {IGA2_FIFO_DEPTH_SELECT_REG_NUM, | ||
162 | {{CR68, 4, 7}, {CR94, 7, 7}, {CR95, 7, 7} } } | ||
163 | }; | ||
164 | |||
165 | static struct fifo_threshold_select fifo_threshold_select_reg = { | ||
166 | /* IGA1 FIFO Threshold Select */ | ||
167 | {IGA1_FIFO_THRESHOLD_REG_NUM, {{SR16, 0, 5}, {SR16, 7, 7} } }, | ||
168 | /* IGA2 FIFO Threshold Select */ | ||
169 | {IGA2_FIFO_THRESHOLD_REG_NUM, {{CR68, 0, 3}, {CR95, 4, 6} } } | ||
170 | }; | ||
171 | |||
172 | static struct fifo_high_threshold_select fifo_high_threshold_select_reg = { | ||
173 | /* IGA1 FIFO High Threshold Select */ | ||
174 | {IGA1_FIFO_HIGH_THRESHOLD_REG_NUM, {{SR18, 0, 5}, {SR18, 7, 7} } }, | ||
175 | /* IGA2 FIFO High Threshold Select */ | ||
176 | {IGA2_FIFO_HIGH_THRESHOLD_REG_NUM, {{CR92, 0, 3}, {CR95, 0, 2} } } | ||
177 | }; | ||
178 | |||
179 | static struct display_queue_expire_num display_queue_expire_num_reg = { | ||
180 | /* IGA1 Display Queue Expire Num */ | ||
181 | {IGA1_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM, {{SR22, 0, 4} } }, | ||
182 | /* IGA2 Display Queue Expire Num */ | ||
183 | {IGA2_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM, {{CR94, 0, 6} } } | ||
184 | }; | ||
185 | |||
186 | /* Definition Fetch Count Registers*/ | ||
187 | static struct fetch_count fetch_count_reg = { | ||
188 | /* IGA1 Fetch Count Register */ | ||
189 | {IGA1_FETCH_COUNT_REG_NUM, {{SR1C, 0, 7}, {SR1D, 0, 1} } }, | ||
190 | /* IGA2 Fetch Count Register */ | ||
191 | {IGA2_FETCH_COUNT_REG_NUM, {{CR65, 0, 7}, {CR67, 2, 3} } } | ||
192 | }; | ||
193 | |||
194 | static struct rgbLUT palLUT_table[] = { | ||
195 | /* {R,G,B} */ | ||
196 | /* Index 0x00~0x03 */ | ||
197 | {0x00, 0x00, 0x00}, {0x00, 0x00, 0x2A}, {0x00, 0x2A, 0x00}, {0x00, | ||
198 | 0x2A, | ||
199 | 0x2A}, | ||
200 | /* Index 0x04~0x07 */ | ||
201 | {0x2A, 0x00, 0x00}, {0x2A, 0x00, 0x2A}, {0x2A, 0x15, 0x00}, {0x2A, | ||
202 | 0x2A, | ||
203 | 0x2A}, | ||
204 | /* Index 0x08~0x0B */ | ||
205 | {0x15, 0x15, 0x15}, {0x15, 0x15, 0x3F}, {0x15, 0x3F, 0x15}, {0x15, | ||
206 | 0x3F, | ||
207 | 0x3F}, | ||
208 | /* Index 0x0C~0x0F */ | ||
209 | {0x3F, 0x15, 0x15}, {0x3F, 0x15, 0x3F}, {0x3F, 0x3F, 0x15}, {0x3F, | ||
210 | 0x3F, | ||
211 | 0x3F}, | ||
212 | /* Index 0x10~0x13 */ | ||
213 | {0x00, 0x00, 0x00}, {0x05, 0x05, 0x05}, {0x08, 0x08, 0x08}, {0x0B, | ||
214 | 0x0B, | ||
215 | 0x0B}, | ||
216 | /* Index 0x14~0x17 */ | ||
217 | {0x0E, 0x0E, 0x0E}, {0x11, 0x11, 0x11}, {0x14, 0x14, 0x14}, {0x18, | ||
218 | 0x18, | ||
219 | 0x18}, | ||
220 | /* Index 0x18~0x1B */ | ||
221 | {0x1C, 0x1C, 0x1C}, {0x20, 0x20, 0x20}, {0x24, 0x24, 0x24}, {0x28, | ||
222 | 0x28, | ||
223 | 0x28}, | ||
224 | /* Index 0x1C~0x1F */ | ||
225 | {0x2D, 0x2D, 0x2D}, {0x32, 0x32, 0x32}, {0x38, 0x38, 0x38}, {0x3F, | ||
226 | 0x3F, | ||
227 | 0x3F}, | ||
228 | /* Index 0x20~0x23 */ | ||
229 | {0x00, 0x00, 0x3F}, {0x10, 0x00, 0x3F}, {0x1F, 0x00, 0x3F}, {0x2F, | ||
230 | 0x00, | ||
231 | 0x3F}, | ||
232 | /* Index 0x24~0x27 */ | ||
233 | {0x3F, 0x00, 0x3F}, {0x3F, 0x00, 0x2F}, {0x3F, 0x00, 0x1F}, {0x3F, | ||
234 | 0x00, | ||
235 | 0x10}, | ||
236 | /* Index 0x28~0x2B */ | ||
237 | {0x3F, 0x00, 0x00}, {0x3F, 0x10, 0x00}, {0x3F, 0x1F, 0x00}, {0x3F, | ||
238 | 0x2F, | ||
239 | 0x00}, | ||
240 | /* Index 0x2C~0x2F */ | ||
241 | {0x3F, 0x3F, 0x00}, {0x2F, 0x3F, 0x00}, {0x1F, 0x3F, 0x00}, {0x10, | ||
242 | 0x3F, | ||
243 | 0x00}, | ||
244 | /* Index 0x30~0x33 */ | ||
245 | {0x00, 0x3F, 0x00}, {0x00, 0x3F, 0x10}, {0x00, 0x3F, 0x1F}, {0x00, | ||
246 | 0x3F, | ||
247 | 0x2F}, | ||
248 | /* Index 0x34~0x37 */ | ||
249 | {0x00, 0x3F, 0x3F}, {0x00, 0x2F, 0x3F}, {0x00, 0x1F, 0x3F}, {0x00, | ||
250 | 0x10, | ||
251 | 0x3F}, | ||
252 | /* Index 0x38~0x3B */ | ||
253 | {0x1F, 0x1F, 0x3F}, {0x27, 0x1F, 0x3F}, {0x2F, 0x1F, 0x3F}, {0x37, | ||
254 | 0x1F, | ||
255 | 0x3F}, | ||
256 | /* Index 0x3C~0x3F */ | ||
257 | {0x3F, 0x1F, 0x3F}, {0x3F, 0x1F, 0x37}, {0x3F, 0x1F, 0x2F}, {0x3F, | ||
258 | 0x1F, | ||
259 | 0x27}, | ||
260 | /* Index 0x40~0x43 */ | ||
261 | {0x3F, 0x1F, 0x1F}, {0x3F, 0x27, 0x1F}, {0x3F, 0x2F, 0x1F}, {0x3F, | ||
262 | 0x3F, | ||
263 | 0x1F}, | ||
264 | /* Index 0x44~0x47 */ | ||
265 | {0x3F, 0x3F, 0x1F}, {0x37, 0x3F, 0x1F}, {0x2F, 0x3F, 0x1F}, {0x27, | ||
266 | 0x3F, | ||
267 | 0x1F}, | ||
268 | /* Index 0x48~0x4B */ | ||
269 | {0x1F, 0x3F, 0x1F}, {0x1F, 0x3F, 0x27}, {0x1F, 0x3F, 0x2F}, {0x1F, | ||
270 | 0x3F, | ||
271 | 0x37}, | ||
272 | /* Index 0x4C~0x4F */ | ||
273 | {0x1F, 0x3F, 0x3F}, {0x1F, 0x37, 0x3F}, {0x1F, 0x2F, 0x3F}, {0x1F, | ||
274 | 0x27, | ||
275 | 0x3F}, | ||
276 | /* Index 0x50~0x53 */ | ||
277 | {0x2D, 0x2D, 0x3F}, {0x31, 0x2D, 0x3F}, {0x36, 0x2D, 0x3F}, {0x3A, | ||
278 | 0x2D, | ||
279 | 0x3F}, | ||
280 | /* Index 0x54~0x57 */ | ||
281 | {0x3F, 0x2D, 0x3F}, {0x3F, 0x2D, 0x3A}, {0x3F, 0x2D, 0x36}, {0x3F, | ||
282 | 0x2D, | ||
283 | 0x31}, | ||
284 | /* Index 0x58~0x5B */ | ||
285 | {0x3F, 0x2D, 0x2D}, {0x3F, 0x31, 0x2D}, {0x3F, 0x36, 0x2D}, {0x3F, | ||
286 | 0x3A, | ||
287 | 0x2D}, | ||
288 | /* Index 0x5C~0x5F */ | ||
289 | {0x3F, 0x3F, 0x2D}, {0x3A, 0x3F, 0x2D}, {0x36, 0x3F, 0x2D}, {0x31, | ||
290 | 0x3F, | ||
291 | 0x2D}, | ||
292 | /* Index 0x60~0x63 */ | ||
293 | {0x2D, 0x3F, 0x2D}, {0x2D, 0x3F, 0x31}, {0x2D, 0x3F, 0x36}, {0x2D, | ||
294 | 0x3F, | ||
295 | 0x3A}, | ||
296 | /* Index 0x64~0x67 */ | ||
297 | {0x2D, 0x3F, 0x3F}, {0x2D, 0x3A, 0x3F}, {0x2D, 0x36, 0x3F}, {0x2D, | ||
298 | 0x31, | ||
299 | 0x3F}, | ||
300 | /* Index 0x68~0x6B */ | ||
301 | {0x00, 0x00, 0x1C}, {0x07, 0x00, 0x1C}, {0x0E, 0x00, 0x1C}, {0x15, | ||
302 | 0x00, | ||
303 | 0x1C}, | ||
304 | /* Index 0x6C~0x6F */ | ||
305 | {0x1C, 0x00, 0x1C}, {0x1C, 0x00, 0x15}, {0x1C, 0x00, 0x0E}, {0x1C, | ||
306 | 0x00, | ||
307 | 0x07}, | ||
308 | /* Index 0x70~0x73 */ | ||
309 | {0x1C, 0x00, 0x00}, {0x1C, 0x07, 0x00}, {0x1C, 0x0E, 0x00}, {0x1C, | ||
310 | 0x15, | ||
311 | 0x00}, | ||
312 | /* Index 0x74~0x77 */ | ||
313 | {0x1C, 0x1C, 0x00}, {0x15, 0x1C, 0x00}, {0x0E, 0x1C, 0x00}, {0x07, | ||
314 | 0x1C, | ||
315 | 0x00}, | ||
316 | /* Index 0x78~0x7B */ | ||
317 | {0x00, 0x1C, 0x00}, {0x00, 0x1C, 0x07}, {0x00, 0x1C, 0x0E}, {0x00, | ||
318 | 0x1C, | ||
319 | 0x15}, | ||
320 | /* Index 0x7C~0x7F */ | ||
321 | {0x00, 0x1C, 0x1C}, {0x00, 0x15, 0x1C}, {0x00, 0x0E, 0x1C}, {0x00, | ||
322 | 0x07, | ||
323 | 0x1C}, | ||
324 | /* Index 0x80~0x83 */ | ||
325 | {0x0E, 0x0E, 0x1C}, {0x11, 0x0E, 0x1C}, {0x15, 0x0E, 0x1C}, {0x18, | ||
326 | 0x0E, | ||
327 | 0x1C}, | ||
328 | /* Index 0x84~0x87 */ | ||
329 | {0x1C, 0x0E, 0x1C}, {0x1C, 0x0E, 0x18}, {0x1C, 0x0E, 0x15}, {0x1C, | ||
330 | 0x0E, | ||
331 | 0x11}, | ||
332 | /* Index 0x88~0x8B */ | ||
333 | {0x1C, 0x0E, 0x0E}, {0x1C, 0x11, 0x0E}, {0x1C, 0x15, 0x0E}, {0x1C, | ||
334 | 0x18, | ||
335 | 0x0E}, | ||
336 | /* Index 0x8C~0x8F */ | ||
337 | {0x1C, 0x1C, 0x0E}, {0x18, 0x1C, 0x0E}, {0x15, 0x1C, 0x0E}, {0x11, | ||
338 | 0x1C, | ||
339 | 0x0E}, | ||
340 | /* Index 0x90~0x93 */ | ||
341 | {0x0E, 0x1C, 0x0E}, {0x0E, 0x1C, 0x11}, {0x0E, 0x1C, 0x15}, {0x0E, | ||
342 | 0x1C, | ||
343 | 0x18}, | ||
344 | /* Index 0x94~0x97 */ | ||
345 | {0x0E, 0x1C, 0x1C}, {0x0E, 0x18, 0x1C}, {0x0E, 0x15, 0x1C}, {0x0E, | ||
346 | 0x11, | ||
347 | 0x1C}, | ||
348 | /* Index 0x98~0x9B */ | ||
349 | {0x14, 0x14, 0x1C}, {0x16, 0x14, 0x1C}, {0x18, 0x14, 0x1C}, {0x1A, | ||
350 | 0x14, | ||
351 | 0x1C}, | ||
352 | /* Index 0x9C~0x9F */ | ||
353 | {0x1C, 0x14, 0x1C}, {0x1C, 0x14, 0x1A}, {0x1C, 0x14, 0x18}, {0x1C, | ||
354 | 0x14, | ||
355 | 0x16}, | ||
356 | /* Index 0xA0~0xA3 */ | ||
357 | {0x1C, 0x14, 0x14}, {0x1C, 0x16, 0x14}, {0x1C, 0x18, 0x14}, {0x1C, | ||
358 | 0x1A, | ||
359 | 0x14}, | ||
360 | /* Index 0xA4~0xA7 */ | ||
361 | {0x1C, 0x1C, 0x14}, {0x1A, 0x1C, 0x14}, {0x18, 0x1C, 0x14}, {0x16, | ||
362 | 0x1C, | ||
363 | 0x14}, | ||
364 | /* Index 0xA8~0xAB */ | ||
365 | {0x14, 0x1C, 0x14}, {0x14, 0x1C, 0x16}, {0x14, 0x1C, 0x18}, {0x14, | ||
366 | 0x1C, | ||
367 | 0x1A}, | ||
368 | /* Index 0xAC~0xAF */ | ||
369 | {0x14, 0x1C, 0x1C}, {0x14, 0x1A, 0x1C}, {0x14, 0x18, 0x1C}, {0x14, | ||
370 | 0x16, | ||
371 | 0x1C}, | ||
372 | /* Index 0xB0~0xB3 */ | ||
373 | {0x00, 0x00, 0x10}, {0x04, 0x00, 0x10}, {0x08, 0x00, 0x10}, {0x0C, | ||
374 | 0x00, | ||
375 | 0x10}, | ||
376 | /* Index 0xB4~0xB7 */ | ||
377 | {0x10, 0x00, 0x10}, {0x10, 0x00, 0x0C}, {0x10, 0x00, 0x08}, {0x10, | ||
378 | 0x00, | ||
379 | 0x04}, | ||
380 | /* Index 0xB8~0xBB */ | ||
381 | {0x10, 0x00, 0x00}, {0x10, 0x04, 0x00}, {0x10, 0x08, 0x00}, {0x10, | ||
382 | 0x0C, | ||
383 | 0x00}, | ||
384 | /* Index 0xBC~0xBF */ | ||
385 | {0x10, 0x10, 0x00}, {0x0C, 0x10, 0x00}, {0x08, 0x10, 0x00}, {0x04, | ||
386 | 0x10, | ||
387 | 0x00}, | ||
388 | /* Index 0xC0~0xC3 */ | ||
389 | {0x00, 0x10, 0x00}, {0x00, 0x10, 0x04}, {0x00, 0x10, 0x08}, {0x00, | ||
390 | 0x10, | ||
391 | 0x0C}, | ||
392 | /* Index 0xC4~0xC7 */ | ||
393 | {0x00, 0x10, 0x10}, {0x00, 0x0C, 0x10}, {0x00, 0x08, 0x10}, {0x00, | ||
394 | 0x04, | ||
395 | 0x10}, | ||
396 | /* Index 0xC8~0xCB */ | ||
397 | {0x08, 0x08, 0x10}, {0x0A, 0x08, 0x10}, {0x0C, 0x08, 0x10}, {0x0E, | ||
398 | 0x08, | ||
399 | 0x10}, | ||
400 | /* Index 0xCC~0xCF */ | ||
401 | {0x10, 0x08, 0x10}, {0x10, 0x08, 0x0E}, {0x10, 0x08, 0x0C}, {0x10, | ||
402 | 0x08, | ||
403 | 0x0A}, | ||
404 | /* Index 0xD0~0xD3 */ | ||
405 | {0x10, 0x08, 0x08}, {0x10, 0x0A, 0x08}, {0x10, 0x0C, 0x08}, {0x10, | ||
406 | 0x0E, | ||
407 | 0x08}, | ||
408 | /* Index 0xD4~0xD7 */ | ||
409 | {0x10, 0x10, 0x08}, {0x0E, 0x10, 0x08}, {0x0C, 0x10, 0x08}, {0x0A, | ||
410 | 0x10, | ||
411 | 0x08}, | ||
412 | /* Index 0xD8~0xDB */ | ||
413 | {0x08, 0x10, 0x08}, {0x08, 0x10, 0x0A}, {0x08, 0x10, 0x0C}, {0x08, | ||
414 | 0x10, | ||
415 | 0x0E}, | ||
416 | /* Index 0xDC~0xDF */ | ||
417 | {0x08, 0x10, 0x10}, {0x08, 0x0E, 0x10}, {0x08, 0x0C, 0x10}, {0x08, | ||
418 | 0x0A, | ||
419 | 0x10}, | ||
420 | /* Index 0xE0~0xE3 */ | ||
421 | {0x0B, 0x0B, 0x10}, {0x0C, 0x0B, 0x10}, {0x0D, 0x0B, 0x10}, {0x0F, | ||
422 | 0x0B, | ||
423 | 0x10}, | ||
424 | /* Index 0xE4~0xE7 */ | ||
425 | {0x10, 0x0B, 0x10}, {0x10, 0x0B, 0x0F}, {0x10, 0x0B, 0x0D}, {0x10, | ||
426 | 0x0B, | ||
427 | 0x0C}, | ||
428 | /* Index 0xE8~0xEB */ | ||
429 | {0x10, 0x0B, 0x0B}, {0x10, 0x0C, 0x0B}, {0x10, 0x0D, 0x0B}, {0x10, | ||
430 | 0x0F, | ||
431 | 0x0B}, | ||
432 | /* Index 0xEC~0xEF */ | ||
433 | {0x10, 0x10, 0x0B}, {0x0F, 0x10, 0x0B}, {0x0D, 0x10, 0x0B}, {0x0C, | ||
434 | 0x10, | ||
435 | 0x0B}, | ||
436 | /* Index 0xF0~0xF3 */ | ||
437 | {0x0B, 0x10, 0x0B}, {0x0B, 0x10, 0x0C}, {0x0B, 0x10, 0x0D}, {0x0B, | ||
438 | 0x10, | ||
439 | 0x0F}, | ||
440 | /* Index 0xF4~0xF7 */ | ||
441 | {0x0B, 0x10, 0x10}, {0x0B, 0x0F, 0x10}, {0x0B, 0x0D, 0x10}, {0x0B, | ||
442 | 0x0C, | ||
443 | 0x10}, | ||
444 | /* Index 0xF8~0xFB */ | ||
445 | {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, | ||
446 | 0x00, | ||
447 | 0x00}, | ||
448 | /* Index 0xFC~0xFF */ | ||
449 | {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, | ||
450 | 0x00, | ||
451 | 0x00} | ||
452 | }; | ||
453 | |||
454 | static struct via_device_mapping device_mapping[] = { | ||
455 | {VIA_LDVP0, "LDVP0"}, | ||
456 | {VIA_LDVP1, "LDVP1"}, | ||
457 | {VIA_DVP0, "DVP0"}, | ||
458 | {VIA_CRT, "CRT"}, | ||
459 | {VIA_DVP1, "DVP1"}, | ||
460 | {VIA_LVDS1, "LVDS1"}, | ||
461 | {VIA_LVDS2, "LVDS2"} | ||
462 | }; | ||
463 | |||
464 | /* structure with function pointers to support clock control */ | ||
465 | static struct via_clock clock; | ||
466 | |||
467 | static void load_fix_bit_crtc_reg(void); | ||
468 | static void init_gfx_chip_info(int chip_type); | ||
469 | static void init_tmds_chip_info(void); | ||
470 | static void init_lvds_chip_info(void); | ||
471 | static void device_screen_off(void); | ||
472 | static void device_screen_on(void); | ||
473 | static void set_display_channel(void); | ||
474 | static void device_off(void); | ||
475 | static void device_on(void); | ||
476 | static void enable_second_display_channel(void); | ||
477 | static void disable_second_display_channel(void); | ||
478 | |||
479 | void viafb_lock_crt(void) | ||
480 | { | ||
481 | viafb_write_reg_mask(CR11, VIACR, BIT7, BIT7); | ||
482 | } | ||
483 | |||
484 | void viafb_unlock_crt(void) | ||
485 | { | ||
486 | viafb_write_reg_mask(CR11, VIACR, 0, BIT7); | ||
487 | viafb_write_reg_mask(CR47, VIACR, 0, BIT0); | ||
488 | } | ||
489 | |||
490 | static void write_dac_reg(u8 index, u8 r, u8 g, u8 b) | ||
491 | { | ||
492 | outb(index, LUT_INDEX_WRITE); | ||
493 | outb(r, LUT_DATA); | ||
494 | outb(g, LUT_DATA); | ||
495 | outb(b, LUT_DATA); | ||
496 | } | ||
497 | |||
498 | static u32 get_dvi_devices(int output_interface) | ||
499 | { | ||
500 | switch (output_interface) { | ||
501 | case INTERFACE_DVP0: | ||
502 | return VIA_DVP0 | VIA_LDVP0; | ||
503 | |||
504 | case INTERFACE_DVP1: | ||
505 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) | ||
506 | return VIA_LDVP1; | ||
507 | else | ||
508 | return VIA_DVP1; | ||
509 | |||
510 | case INTERFACE_DFP_HIGH: | ||
511 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) | ||
512 | return 0; | ||
513 | else | ||
514 | return VIA_LVDS2 | VIA_DVP0; | ||
515 | |||
516 | case INTERFACE_DFP_LOW: | ||
517 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) | ||
518 | return 0; | ||
519 | else | ||
520 | return VIA_DVP1 | VIA_LVDS1; | ||
521 | |||
522 | case INTERFACE_TMDS: | ||
523 | return VIA_LVDS1; | ||
524 | } | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | static u32 get_lcd_devices(int output_interface) | ||
530 | { | ||
531 | switch (output_interface) { | ||
532 | case INTERFACE_DVP0: | ||
533 | return VIA_DVP0; | ||
534 | |||
535 | case INTERFACE_DVP1: | ||
536 | return VIA_DVP1; | ||
537 | |||
538 | case INTERFACE_DFP_HIGH: | ||
539 | return VIA_LVDS2 | VIA_DVP0; | ||
540 | |||
541 | case INTERFACE_DFP_LOW: | ||
542 | return VIA_LVDS1 | VIA_DVP1; | ||
543 | |||
544 | case INTERFACE_DFP: | ||
545 | return VIA_LVDS1 | VIA_LVDS2; | ||
546 | |||
547 | case INTERFACE_LVDS0: | ||
548 | case INTERFACE_LVDS0LVDS1: | ||
549 | return VIA_LVDS1; | ||
550 | |||
551 | case INTERFACE_LVDS1: | ||
552 | return VIA_LVDS2; | ||
553 | } | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | /*Set IGA path for each device*/ | ||
559 | void viafb_set_iga_path(void) | ||
560 | { | ||
561 | int crt_iga_path = 0; | ||
562 | |||
563 | if (viafb_SAMM_ON == 1) { | ||
564 | if (viafb_CRT_ON) { | ||
565 | if (viafb_primary_dev == CRT_Device) | ||
566 | crt_iga_path = IGA1; | ||
567 | else | ||
568 | crt_iga_path = IGA2; | ||
569 | } | ||
570 | |||
571 | if (viafb_DVI_ON) { | ||
572 | if (viafb_primary_dev == DVI_Device) | ||
573 | viaparinfo->tmds_setting_info->iga_path = IGA1; | ||
574 | else | ||
575 | viaparinfo->tmds_setting_info->iga_path = IGA2; | ||
576 | } | ||
577 | |||
578 | if (viafb_LCD_ON) { | ||
579 | if (viafb_primary_dev == LCD_Device) { | ||
580 | if (viafb_dual_fb && | ||
581 | (viaparinfo->chip_info->gfx_chip_name == | ||
582 | UNICHROME_CLE266)) { | ||
583 | viaparinfo-> | ||
584 | lvds_setting_info->iga_path = IGA2; | ||
585 | crt_iga_path = IGA1; | ||
586 | viaparinfo-> | ||
587 | tmds_setting_info->iga_path = IGA1; | ||
588 | } else | ||
589 | viaparinfo-> | ||
590 | lvds_setting_info->iga_path = IGA1; | ||
591 | } else { | ||
592 | viaparinfo->lvds_setting_info->iga_path = IGA2; | ||
593 | } | ||
594 | } | ||
595 | if (viafb_LCD2_ON) { | ||
596 | if (LCD2_Device == viafb_primary_dev) | ||
597 | viaparinfo->lvds_setting_info2->iga_path = IGA1; | ||
598 | else | ||
599 | viaparinfo->lvds_setting_info2->iga_path = IGA2; | ||
600 | } | ||
601 | } else { | ||
602 | viafb_SAMM_ON = 0; | ||
603 | |||
604 | if (viafb_CRT_ON && viafb_LCD_ON) { | ||
605 | crt_iga_path = IGA1; | ||
606 | viaparinfo->lvds_setting_info->iga_path = IGA2; | ||
607 | } else if (viafb_CRT_ON && viafb_DVI_ON) { | ||
608 | crt_iga_path = IGA1; | ||
609 | viaparinfo->tmds_setting_info->iga_path = IGA2; | ||
610 | } else if (viafb_LCD_ON && viafb_DVI_ON) { | ||
611 | viaparinfo->tmds_setting_info->iga_path = IGA1; | ||
612 | viaparinfo->lvds_setting_info->iga_path = IGA2; | ||
613 | } else if (viafb_LCD_ON && viafb_LCD2_ON) { | ||
614 | viaparinfo->lvds_setting_info->iga_path = IGA2; | ||
615 | viaparinfo->lvds_setting_info2->iga_path = IGA2; | ||
616 | } else if (viafb_CRT_ON) { | ||
617 | crt_iga_path = IGA1; | ||
618 | } else if (viafb_LCD_ON) { | ||
619 | viaparinfo->lvds_setting_info->iga_path = IGA2; | ||
620 | } else if (viafb_DVI_ON) { | ||
621 | viaparinfo->tmds_setting_info->iga_path = IGA1; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | viaparinfo->shared->iga1_devices = 0; | ||
626 | viaparinfo->shared->iga2_devices = 0; | ||
627 | if (viafb_CRT_ON) { | ||
628 | if (crt_iga_path == IGA1) | ||
629 | viaparinfo->shared->iga1_devices |= VIA_CRT; | ||
630 | else | ||
631 | viaparinfo->shared->iga2_devices |= VIA_CRT; | ||
632 | } | ||
633 | |||
634 | if (viafb_DVI_ON) { | ||
635 | if (viaparinfo->tmds_setting_info->iga_path == IGA1) | ||
636 | viaparinfo->shared->iga1_devices |= get_dvi_devices( | ||
637 | viaparinfo->chip_info-> | ||
638 | tmds_chip_info.output_interface); | ||
639 | else | ||
640 | viaparinfo->shared->iga2_devices |= get_dvi_devices( | ||
641 | viaparinfo->chip_info-> | ||
642 | tmds_chip_info.output_interface); | ||
643 | } | ||
644 | |||
645 | if (viafb_LCD_ON) { | ||
646 | if (viaparinfo->lvds_setting_info->iga_path == IGA1) | ||
647 | viaparinfo->shared->iga1_devices |= get_lcd_devices( | ||
648 | viaparinfo->chip_info-> | ||
649 | lvds_chip_info.output_interface); | ||
650 | else | ||
651 | viaparinfo->shared->iga2_devices |= get_lcd_devices( | ||
652 | viaparinfo->chip_info-> | ||
653 | lvds_chip_info.output_interface); | ||
654 | } | ||
655 | |||
656 | if (viafb_LCD2_ON) { | ||
657 | if (viaparinfo->lvds_setting_info2->iga_path == IGA1) | ||
658 | viaparinfo->shared->iga1_devices |= get_lcd_devices( | ||
659 | viaparinfo->chip_info-> | ||
660 | lvds_chip_info2.output_interface); | ||
661 | else | ||
662 | viaparinfo->shared->iga2_devices |= get_lcd_devices( | ||
663 | viaparinfo->chip_info-> | ||
664 | lvds_chip_info2.output_interface); | ||
665 | } | ||
666 | |||
667 | /* looks like the OLPC has its display wired to DVP1 and LVDS2 */ | ||
668 | if (machine_is_olpc()) | ||
669 | viaparinfo->shared->iga2_devices = VIA_DVP1 | VIA_LVDS2; | ||
670 | } | ||
671 | |||
672 | static void set_color_register(u8 index, u8 red, u8 green, u8 blue) | ||
673 | { | ||
674 | outb(0xFF, 0x3C6); /* bit mask of palette */ | ||
675 | outb(index, 0x3C8); | ||
676 | outb(red, 0x3C9); | ||
677 | outb(green, 0x3C9); | ||
678 | outb(blue, 0x3C9); | ||
679 | } | ||
680 | |||
681 | void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue) | ||
682 | { | ||
683 | viafb_write_reg_mask(0x1A, VIASR, 0x00, 0x01); | ||
684 | set_color_register(index, red, green, blue); | ||
685 | } | ||
686 | |||
687 | void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue) | ||
688 | { | ||
689 | viafb_write_reg_mask(0x1A, VIASR, 0x01, 0x01); | ||
690 | set_color_register(index, red, green, blue); | ||
691 | } | ||
692 | |||
693 | static void set_source_common(u8 index, u8 offset, u8 iga) | ||
694 | { | ||
695 | u8 value, mask = 1 << offset; | ||
696 | |||
697 | switch (iga) { | ||
698 | case IGA1: | ||
699 | value = 0x00; | ||
700 | break; | ||
701 | case IGA2: | ||
702 | value = mask; | ||
703 | break; | ||
704 | default: | ||
705 | printk(KERN_WARNING "viafb: Unsupported source: %d\n", iga); | ||
706 | return; | ||
707 | } | ||
708 | |||
709 | via_write_reg_mask(VIACR, index, value, mask); | ||
710 | } | ||
711 | |||
712 | static void set_crt_source(u8 iga) | ||
713 | { | ||
714 | u8 value; | ||
715 | |||
716 | switch (iga) { | ||
717 | case IGA1: | ||
718 | value = 0x00; | ||
719 | break; | ||
720 | case IGA2: | ||
721 | value = 0x40; | ||
722 | break; | ||
723 | default: | ||
724 | printk(KERN_WARNING "viafb: Unsupported source: %d\n", iga); | ||
725 | return; | ||
726 | } | ||
727 | |||
728 | via_write_reg_mask(VIASR, 0x16, value, 0x40); | ||
729 | } | ||
730 | |||
731 | static inline void set_ldvp0_source(u8 iga) | ||
732 | { | ||
733 | set_source_common(0x6C, 7, iga); | ||
734 | } | ||
735 | |||
736 | static inline void set_ldvp1_source(u8 iga) | ||
737 | { | ||
738 | set_source_common(0x93, 7, iga); | ||
739 | } | ||
740 | |||
741 | static inline void set_dvp0_source(u8 iga) | ||
742 | { | ||
743 | set_source_common(0x96, 4, iga); | ||
744 | } | ||
745 | |||
746 | static inline void set_dvp1_source(u8 iga) | ||
747 | { | ||
748 | set_source_common(0x9B, 4, iga); | ||
749 | } | ||
750 | |||
751 | static inline void set_lvds1_source(u8 iga) | ||
752 | { | ||
753 | set_source_common(0x99, 4, iga); | ||
754 | } | ||
755 | |||
756 | static inline void set_lvds2_source(u8 iga) | ||
757 | { | ||
758 | set_source_common(0x97, 4, iga); | ||
759 | } | ||
760 | |||
761 | void via_set_source(u32 devices, u8 iga) | ||
762 | { | ||
763 | if (devices & VIA_LDVP0) | ||
764 | set_ldvp0_source(iga); | ||
765 | if (devices & VIA_LDVP1) | ||
766 | set_ldvp1_source(iga); | ||
767 | if (devices & VIA_DVP0) | ||
768 | set_dvp0_source(iga); | ||
769 | if (devices & VIA_CRT) | ||
770 | set_crt_source(iga); | ||
771 | if (devices & VIA_DVP1) | ||
772 | set_dvp1_source(iga); | ||
773 | if (devices & VIA_LVDS1) | ||
774 | set_lvds1_source(iga); | ||
775 | if (devices & VIA_LVDS2) | ||
776 | set_lvds2_source(iga); | ||
777 | } | ||
778 | |||
779 | static void set_crt_state(u8 state) | ||
780 | { | ||
781 | u8 value; | ||
782 | |||
783 | switch (state) { | ||
784 | case VIA_STATE_ON: | ||
785 | value = 0x00; | ||
786 | break; | ||
787 | case VIA_STATE_STANDBY: | ||
788 | value = 0x10; | ||
789 | break; | ||
790 | case VIA_STATE_SUSPEND: | ||
791 | value = 0x20; | ||
792 | break; | ||
793 | case VIA_STATE_OFF: | ||
794 | value = 0x30; | ||
795 | break; | ||
796 | default: | ||
797 | return; | ||
798 | } | ||
799 | |||
800 | via_write_reg_mask(VIACR, 0x36, value, 0x30); | ||
801 | } | ||
802 | |||
803 | static void set_dvp0_state(u8 state) | ||
804 | { | ||
805 | u8 value; | ||
806 | |||
807 | switch (state) { | ||
808 | case VIA_STATE_ON: | ||
809 | value = 0xC0; | ||
810 | break; | ||
811 | case VIA_STATE_OFF: | ||
812 | value = 0x00; | ||
813 | break; | ||
814 | default: | ||
815 | return; | ||
816 | } | ||
817 | |||
818 | via_write_reg_mask(VIASR, 0x1E, value, 0xC0); | ||
819 | } | ||
820 | |||
821 | static void set_dvp1_state(u8 state) | ||
822 | { | ||
823 | u8 value; | ||
824 | |||
825 | switch (state) { | ||
826 | case VIA_STATE_ON: | ||
827 | value = 0x30; | ||
828 | break; | ||
829 | case VIA_STATE_OFF: | ||
830 | value = 0x00; | ||
831 | break; | ||
832 | default: | ||
833 | return; | ||
834 | } | ||
835 | |||
836 | via_write_reg_mask(VIASR, 0x1E, value, 0x30); | ||
837 | } | ||
838 | |||
839 | static void set_lvds1_state(u8 state) | ||
840 | { | ||
841 | u8 value; | ||
842 | |||
843 | switch (state) { | ||
844 | case VIA_STATE_ON: | ||
845 | value = 0x03; | ||
846 | break; | ||
847 | case VIA_STATE_OFF: | ||
848 | value = 0x00; | ||
849 | break; | ||
850 | default: | ||
851 | return; | ||
852 | } | ||
853 | |||
854 | via_write_reg_mask(VIASR, 0x2A, value, 0x03); | ||
855 | } | ||
856 | |||
857 | static void set_lvds2_state(u8 state) | ||
858 | { | ||
859 | u8 value; | ||
860 | |||
861 | switch (state) { | ||
862 | case VIA_STATE_ON: | ||
863 | value = 0x0C; | ||
864 | break; | ||
865 | case VIA_STATE_OFF: | ||
866 | value = 0x00; | ||
867 | break; | ||
868 | default: | ||
869 | return; | ||
870 | } | ||
871 | |||
872 | via_write_reg_mask(VIASR, 0x2A, value, 0x0C); | ||
873 | } | ||
874 | |||
875 | void via_set_state(u32 devices, u8 state) | ||
876 | { | ||
877 | /* | ||
878 | TODO: Can we enable/disable these devices? How? | ||
879 | if (devices & VIA_LDVP0) | ||
880 | if (devices & VIA_LDVP1) | ||
881 | */ | ||
882 | if (devices & VIA_DVP0) | ||
883 | set_dvp0_state(state); | ||
884 | if (devices & VIA_CRT) | ||
885 | set_crt_state(state); | ||
886 | if (devices & VIA_DVP1) | ||
887 | set_dvp1_state(state); | ||
888 | if (devices & VIA_LVDS1) | ||
889 | set_lvds1_state(state); | ||
890 | if (devices & VIA_LVDS2) | ||
891 | set_lvds2_state(state); | ||
892 | } | ||
893 | |||
894 | void via_set_sync_polarity(u32 devices, u8 polarity) | ||
895 | { | ||
896 | if (polarity & ~(VIA_HSYNC_NEGATIVE | VIA_VSYNC_NEGATIVE)) { | ||
897 | printk(KERN_WARNING "viafb: Unsupported polarity: %d\n", | ||
898 | polarity); | ||
899 | return; | ||
900 | } | ||
901 | |||
902 | if (devices & VIA_CRT) | ||
903 | via_write_misc_reg_mask(polarity << 6, 0xC0); | ||
904 | if (devices & VIA_DVP1) | ||
905 | via_write_reg_mask(VIACR, 0x9B, polarity << 5, 0x60); | ||
906 | if (devices & VIA_LVDS1) | ||
907 | via_write_reg_mask(VIACR, 0x99, polarity << 5, 0x60); | ||
908 | if (devices & VIA_LVDS2) | ||
909 | via_write_reg_mask(VIACR, 0x97, polarity << 5, 0x60); | ||
910 | } | ||
911 | |||
912 | u32 via_parse_odev(char *input, char **end) | ||
913 | { | ||
914 | char *ptr = input; | ||
915 | u32 odev = 0; | ||
916 | bool next = true; | ||
917 | int i, len; | ||
918 | |||
919 | while (next) { | ||
920 | next = false; | ||
921 | for (i = 0; i < ARRAY_SIZE(device_mapping); i++) { | ||
922 | len = strlen(device_mapping[i].name); | ||
923 | if (!strncmp(ptr, device_mapping[i].name, len)) { | ||
924 | odev |= device_mapping[i].device; | ||
925 | ptr += len; | ||
926 | if (*ptr == ',') { | ||
927 | ptr++; | ||
928 | next = true; | ||
929 | } | ||
930 | } | ||
931 | } | ||
932 | } | ||
933 | |||
934 | *end = ptr; | ||
935 | return odev; | ||
936 | } | ||
937 | |||
938 | void via_odev_to_seq(struct seq_file *m, u32 odev) | ||
939 | { | ||
940 | int i, count = 0; | ||
941 | |||
942 | for (i = 0; i < ARRAY_SIZE(device_mapping); i++) { | ||
943 | if (odev & device_mapping[i].device) { | ||
944 | if (count > 0) | ||
945 | seq_putc(m, ','); | ||
946 | |||
947 | seq_puts(m, device_mapping[i].name); | ||
948 | count++; | ||
949 | } | ||
950 | } | ||
951 | |||
952 | seq_putc(m, '\n'); | ||
953 | } | ||
954 | |||
955 | static void load_fix_bit_crtc_reg(void) | ||
956 | { | ||
957 | viafb_unlock_crt(); | ||
958 | |||
959 | /* always set to 1 */ | ||
960 | viafb_write_reg_mask(CR03, VIACR, 0x80, BIT7); | ||
961 | /* line compare should set all bits = 1 (extend modes) */ | ||
962 | viafb_write_reg_mask(CR35, VIACR, 0x10, BIT4); | ||
963 | /* line compare should set all bits = 1 (extend modes) */ | ||
964 | viafb_write_reg_mask(CR33, VIACR, 0x06, BIT0 + BIT1 + BIT2); | ||
965 | /*viafb_write_reg_mask(CR32, VIACR, 0x01, BIT0); */ | ||
966 | |||
967 | viafb_lock_crt(); | ||
968 | |||
969 | /* If K8M800, enable Prefetch Mode. */ | ||
970 | if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) | ||
971 | || (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K8M890)) | ||
972 | viafb_write_reg_mask(CR33, VIACR, 0x08, BIT3); | ||
973 | if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) | ||
974 | && (viaparinfo->chip_info->gfx_chip_revision == CLE266_REVISION_AX)) | ||
975 | viafb_write_reg_mask(SR1A, VIASR, 0x02, BIT1); | ||
976 | |||
977 | } | ||
978 | |||
979 | void viafb_load_reg(int timing_value, int viafb_load_reg_num, | ||
980 | struct io_register *reg, | ||
981 | int io_type) | ||
982 | { | ||
983 | int reg_mask; | ||
984 | int bit_num = 0; | ||
985 | int data; | ||
986 | int i, j; | ||
987 | int shift_next_reg; | ||
988 | int start_index, end_index, cr_index; | ||
989 | u16 get_bit; | ||
990 | |||
991 | for (i = 0; i < viafb_load_reg_num; i++) { | ||
992 | reg_mask = 0; | ||
993 | data = 0; | ||
994 | start_index = reg[i].start_bit; | ||
995 | end_index = reg[i].end_bit; | ||
996 | cr_index = reg[i].io_addr; | ||
997 | |||
998 | shift_next_reg = bit_num; | ||
999 | for (j = start_index; j <= end_index; j++) { | ||
1000 | /*if (bit_num==8) timing_value = timing_value >>8; */ | ||
1001 | reg_mask = reg_mask | (BIT0 << j); | ||
1002 | get_bit = (timing_value & (BIT0 << bit_num)); | ||
1003 | data = | ||
1004 | data | ((get_bit >> shift_next_reg) << start_index); | ||
1005 | bit_num++; | ||
1006 | } | ||
1007 | if (io_type == VIACR) | ||
1008 | viafb_write_reg_mask(cr_index, VIACR, data, reg_mask); | ||
1009 | else | ||
1010 | viafb_write_reg_mask(cr_index, VIASR, data, reg_mask); | ||
1011 | } | ||
1012 | |||
1013 | } | ||
1014 | |||
1015 | /* Write Registers */ | ||
1016 | void viafb_write_regx(struct io_reg RegTable[], int ItemNum) | ||
1017 | { | ||
1018 | int i; | ||
1019 | |||
1020 | /*DEBUG_MSG(KERN_INFO "Table Size : %x!!\n",ItemNum ); */ | ||
1021 | |||
1022 | for (i = 0; i < ItemNum; i++) | ||
1023 | via_write_reg_mask(RegTable[i].port, RegTable[i].index, | ||
1024 | RegTable[i].value, RegTable[i].mask); | ||
1025 | } | ||
1026 | |||
1027 | void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga) | ||
1028 | { | ||
1029 | int reg_value; | ||
1030 | int viafb_load_reg_num; | ||
1031 | struct io_register *reg = NULL; | ||
1032 | |||
1033 | switch (set_iga) { | ||
1034 | case IGA1: | ||
1035 | reg_value = IGA1_FETCH_COUNT_FORMULA(h_addr, bpp_byte); | ||
1036 | viafb_load_reg_num = fetch_count_reg. | ||
1037 | iga1_fetch_count_reg.reg_num; | ||
1038 | reg = fetch_count_reg.iga1_fetch_count_reg.reg; | ||
1039 | viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR); | ||
1040 | break; | ||
1041 | case IGA2: | ||
1042 | reg_value = IGA2_FETCH_COUNT_FORMULA(h_addr, bpp_byte); | ||
1043 | viafb_load_reg_num = fetch_count_reg. | ||
1044 | iga2_fetch_count_reg.reg_num; | ||
1045 | reg = fetch_count_reg.iga2_fetch_count_reg.reg; | ||
1046 | viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR); | ||
1047 | break; | ||
1048 | } | ||
1049 | |||
1050 | } | ||
1051 | |||
1052 | void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active) | ||
1053 | { | ||
1054 | int reg_value; | ||
1055 | int viafb_load_reg_num; | ||
1056 | struct io_register *reg = NULL; | ||
1057 | int iga1_fifo_max_depth = 0, iga1_fifo_threshold = | ||
1058 | 0, iga1_fifo_high_threshold = 0, iga1_display_queue_expire_num = 0; | ||
1059 | int iga2_fifo_max_depth = 0, iga2_fifo_threshold = | ||
1060 | 0, iga2_fifo_high_threshold = 0, iga2_display_queue_expire_num = 0; | ||
1061 | |||
1062 | if (set_iga == IGA1) { | ||
1063 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) { | ||
1064 | iga1_fifo_max_depth = K800_IGA1_FIFO_MAX_DEPTH; | ||
1065 | iga1_fifo_threshold = K800_IGA1_FIFO_THRESHOLD; | ||
1066 | iga1_fifo_high_threshold = | ||
1067 | K800_IGA1_FIFO_HIGH_THRESHOLD; | ||
1068 | /* If resolution > 1280x1024, expire length = 64, else | ||
1069 | expire length = 128 */ | ||
1070 | if ((hor_active > 1280) && (ver_active > 1024)) | ||
1071 | iga1_display_queue_expire_num = 16; | ||
1072 | else | ||
1073 | iga1_display_queue_expire_num = | ||
1074 | K800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1075 | |||
1076 | } | ||
1077 | |||
1078 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_PM800) { | ||
1079 | iga1_fifo_max_depth = P880_IGA1_FIFO_MAX_DEPTH; | ||
1080 | iga1_fifo_threshold = P880_IGA1_FIFO_THRESHOLD; | ||
1081 | iga1_fifo_high_threshold = | ||
1082 | P880_IGA1_FIFO_HIGH_THRESHOLD; | ||
1083 | iga1_display_queue_expire_num = | ||
1084 | P880_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1085 | |||
1086 | /* If resolution > 1280x1024, expire length = 64, else | ||
1087 | expire length = 128 */ | ||
1088 | if ((hor_active > 1280) && (ver_active > 1024)) | ||
1089 | iga1_display_queue_expire_num = 16; | ||
1090 | else | ||
1091 | iga1_display_queue_expire_num = | ||
1092 | P880_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1093 | } | ||
1094 | |||
1095 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CN700) { | ||
1096 | iga1_fifo_max_depth = CN700_IGA1_FIFO_MAX_DEPTH; | ||
1097 | iga1_fifo_threshold = CN700_IGA1_FIFO_THRESHOLD; | ||
1098 | iga1_fifo_high_threshold = | ||
1099 | CN700_IGA1_FIFO_HIGH_THRESHOLD; | ||
1100 | |||
1101 | /* If resolution > 1280x1024, expire length = 64, | ||
1102 | else expire length = 128 */ | ||
1103 | if ((hor_active > 1280) && (ver_active > 1024)) | ||
1104 | iga1_display_queue_expire_num = 16; | ||
1105 | else | ||
1106 | iga1_display_queue_expire_num = | ||
1107 | CN700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1108 | } | ||
1109 | |||
1110 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) { | ||
1111 | iga1_fifo_max_depth = CX700_IGA1_FIFO_MAX_DEPTH; | ||
1112 | iga1_fifo_threshold = CX700_IGA1_FIFO_THRESHOLD; | ||
1113 | iga1_fifo_high_threshold = | ||
1114 | CX700_IGA1_FIFO_HIGH_THRESHOLD; | ||
1115 | iga1_display_queue_expire_num = | ||
1116 | CX700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1117 | } | ||
1118 | |||
1119 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K8M890) { | ||
1120 | iga1_fifo_max_depth = K8M890_IGA1_FIFO_MAX_DEPTH; | ||
1121 | iga1_fifo_threshold = K8M890_IGA1_FIFO_THRESHOLD; | ||
1122 | iga1_fifo_high_threshold = | ||
1123 | K8M890_IGA1_FIFO_HIGH_THRESHOLD; | ||
1124 | iga1_display_queue_expire_num = | ||
1125 | K8M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1126 | } | ||
1127 | |||
1128 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M890) { | ||
1129 | iga1_fifo_max_depth = P4M890_IGA1_FIFO_MAX_DEPTH; | ||
1130 | iga1_fifo_threshold = P4M890_IGA1_FIFO_THRESHOLD; | ||
1131 | iga1_fifo_high_threshold = | ||
1132 | P4M890_IGA1_FIFO_HIGH_THRESHOLD; | ||
1133 | iga1_display_queue_expire_num = | ||
1134 | P4M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1135 | } | ||
1136 | |||
1137 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M900) { | ||
1138 | iga1_fifo_max_depth = P4M900_IGA1_FIFO_MAX_DEPTH; | ||
1139 | iga1_fifo_threshold = P4M900_IGA1_FIFO_THRESHOLD; | ||
1140 | iga1_fifo_high_threshold = | ||
1141 | P4M900_IGA1_FIFO_HIGH_THRESHOLD; | ||
1142 | iga1_display_queue_expire_num = | ||
1143 | P4M900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1144 | } | ||
1145 | |||
1146 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX800) { | ||
1147 | iga1_fifo_max_depth = VX800_IGA1_FIFO_MAX_DEPTH; | ||
1148 | iga1_fifo_threshold = VX800_IGA1_FIFO_THRESHOLD; | ||
1149 | iga1_fifo_high_threshold = | ||
1150 | VX800_IGA1_FIFO_HIGH_THRESHOLD; | ||
1151 | iga1_display_queue_expire_num = | ||
1152 | VX800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1153 | } | ||
1154 | |||
1155 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX855) { | ||
1156 | iga1_fifo_max_depth = VX855_IGA1_FIFO_MAX_DEPTH; | ||
1157 | iga1_fifo_threshold = VX855_IGA1_FIFO_THRESHOLD; | ||
1158 | iga1_fifo_high_threshold = | ||
1159 | VX855_IGA1_FIFO_HIGH_THRESHOLD; | ||
1160 | iga1_display_queue_expire_num = | ||
1161 | VX855_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1162 | } | ||
1163 | |||
1164 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX900) { | ||
1165 | iga1_fifo_max_depth = VX900_IGA1_FIFO_MAX_DEPTH; | ||
1166 | iga1_fifo_threshold = VX900_IGA1_FIFO_THRESHOLD; | ||
1167 | iga1_fifo_high_threshold = | ||
1168 | VX900_IGA1_FIFO_HIGH_THRESHOLD; | ||
1169 | iga1_display_queue_expire_num = | ||
1170 | VX900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1171 | } | ||
1172 | |||
1173 | /* Set Display FIFO Depath Select */ | ||
1174 | reg_value = IGA1_FIFO_DEPTH_SELECT_FORMULA(iga1_fifo_max_depth); | ||
1175 | viafb_load_reg_num = | ||
1176 | display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg_num; | ||
1177 | reg = display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg; | ||
1178 | viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR); | ||
1179 | |||
1180 | /* Set Display FIFO Threshold Select */ | ||
1181 | reg_value = IGA1_FIFO_THRESHOLD_FORMULA(iga1_fifo_threshold); | ||
1182 | viafb_load_reg_num = | ||
1183 | fifo_threshold_select_reg. | ||
1184 | iga1_fifo_threshold_select_reg.reg_num; | ||
1185 | reg = | ||
1186 | fifo_threshold_select_reg. | ||
1187 | iga1_fifo_threshold_select_reg.reg; | ||
1188 | viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR); | ||
1189 | |||
1190 | /* Set FIFO High Threshold Select */ | ||
1191 | reg_value = | ||
1192 | IGA1_FIFO_HIGH_THRESHOLD_FORMULA(iga1_fifo_high_threshold); | ||
1193 | viafb_load_reg_num = | ||
1194 | fifo_high_threshold_select_reg. | ||
1195 | iga1_fifo_high_threshold_select_reg.reg_num; | ||
1196 | reg = | ||
1197 | fifo_high_threshold_select_reg. | ||
1198 | iga1_fifo_high_threshold_select_reg.reg; | ||
1199 | viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR); | ||
1200 | |||
1201 | /* Set Display Queue Expire Num */ | ||
1202 | reg_value = | ||
1203 | IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA | ||
1204 | (iga1_display_queue_expire_num); | ||
1205 | viafb_load_reg_num = | ||
1206 | display_queue_expire_num_reg. | ||
1207 | iga1_display_queue_expire_num_reg.reg_num; | ||
1208 | reg = | ||
1209 | display_queue_expire_num_reg. | ||
1210 | iga1_display_queue_expire_num_reg.reg; | ||
1211 | viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR); | ||
1212 | |||
1213 | } else { | ||
1214 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) { | ||
1215 | iga2_fifo_max_depth = K800_IGA2_FIFO_MAX_DEPTH; | ||
1216 | iga2_fifo_threshold = K800_IGA2_FIFO_THRESHOLD; | ||
1217 | iga2_fifo_high_threshold = | ||
1218 | K800_IGA2_FIFO_HIGH_THRESHOLD; | ||
1219 | |||
1220 | /* If resolution > 1280x1024, expire length = 64, | ||
1221 | else expire length = 128 */ | ||
1222 | if ((hor_active > 1280) && (ver_active > 1024)) | ||
1223 | iga2_display_queue_expire_num = 16; | ||
1224 | else | ||
1225 | iga2_display_queue_expire_num = | ||
1226 | K800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1227 | } | ||
1228 | |||
1229 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_PM800) { | ||
1230 | iga2_fifo_max_depth = P880_IGA2_FIFO_MAX_DEPTH; | ||
1231 | iga2_fifo_threshold = P880_IGA2_FIFO_THRESHOLD; | ||
1232 | iga2_fifo_high_threshold = | ||
1233 | P880_IGA2_FIFO_HIGH_THRESHOLD; | ||
1234 | |||
1235 | /* If resolution > 1280x1024, expire length = 64, | ||
1236 | else expire length = 128 */ | ||
1237 | if ((hor_active > 1280) && (ver_active > 1024)) | ||
1238 | iga2_display_queue_expire_num = 16; | ||
1239 | else | ||
1240 | iga2_display_queue_expire_num = | ||
1241 | P880_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1242 | } | ||
1243 | |||
1244 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CN700) { | ||
1245 | iga2_fifo_max_depth = CN700_IGA2_FIFO_MAX_DEPTH; | ||
1246 | iga2_fifo_threshold = CN700_IGA2_FIFO_THRESHOLD; | ||
1247 | iga2_fifo_high_threshold = | ||
1248 | CN700_IGA2_FIFO_HIGH_THRESHOLD; | ||
1249 | |||
1250 | /* If resolution > 1280x1024, expire length = 64, | ||
1251 | else expire length = 128 */ | ||
1252 | if ((hor_active > 1280) && (ver_active > 1024)) | ||
1253 | iga2_display_queue_expire_num = 16; | ||
1254 | else | ||
1255 | iga2_display_queue_expire_num = | ||
1256 | CN700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1257 | } | ||
1258 | |||
1259 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) { | ||
1260 | iga2_fifo_max_depth = CX700_IGA2_FIFO_MAX_DEPTH; | ||
1261 | iga2_fifo_threshold = CX700_IGA2_FIFO_THRESHOLD; | ||
1262 | iga2_fifo_high_threshold = | ||
1263 | CX700_IGA2_FIFO_HIGH_THRESHOLD; | ||
1264 | iga2_display_queue_expire_num = | ||
1265 | CX700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1266 | } | ||
1267 | |||
1268 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K8M890) { | ||
1269 | iga2_fifo_max_depth = K8M890_IGA2_FIFO_MAX_DEPTH; | ||
1270 | iga2_fifo_threshold = K8M890_IGA2_FIFO_THRESHOLD; | ||
1271 | iga2_fifo_high_threshold = | ||
1272 | K8M890_IGA2_FIFO_HIGH_THRESHOLD; | ||
1273 | iga2_display_queue_expire_num = | ||
1274 | K8M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1275 | } | ||
1276 | |||
1277 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M890) { | ||
1278 | iga2_fifo_max_depth = P4M890_IGA2_FIFO_MAX_DEPTH; | ||
1279 | iga2_fifo_threshold = P4M890_IGA2_FIFO_THRESHOLD; | ||
1280 | iga2_fifo_high_threshold = | ||
1281 | P4M890_IGA2_FIFO_HIGH_THRESHOLD; | ||
1282 | iga2_display_queue_expire_num = | ||
1283 | P4M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1284 | } | ||
1285 | |||
1286 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M900) { | ||
1287 | iga2_fifo_max_depth = P4M900_IGA2_FIFO_MAX_DEPTH; | ||
1288 | iga2_fifo_threshold = P4M900_IGA2_FIFO_THRESHOLD; | ||
1289 | iga2_fifo_high_threshold = | ||
1290 | P4M900_IGA2_FIFO_HIGH_THRESHOLD; | ||
1291 | iga2_display_queue_expire_num = | ||
1292 | P4M900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1293 | } | ||
1294 | |||
1295 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX800) { | ||
1296 | iga2_fifo_max_depth = VX800_IGA2_FIFO_MAX_DEPTH; | ||
1297 | iga2_fifo_threshold = VX800_IGA2_FIFO_THRESHOLD; | ||
1298 | iga2_fifo_high_threshold = | ||
1299 | VX800_IGA2_FIFO_HIGH_THRESHOLD; | ||
1300 | iga2_display_queue_expire_num = | ||
1301 | VX800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1302 | } | ||
1303 | |||
1304 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX855) { | ||
1305 | iga2_fifo_max_depth = VX855_IGA2_FIFO_MAX_DEPTH; | ||
1306 | iga2_fifo_threshold = VX855_IGA2_FIFO_THRESHOLD; | ||
1307 | iga2_fifo_high_threshold = | ||
1308 | VX855_IGA2_FIFO_HIGH_THRESHOLD; | ||
1309 | iga2_display_queue_expire_num = | ||
1310 | VX855_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1311 | } | ||
1312 | |||
1313 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX900) { | ||
1314 | iga2_fifo_max_depth = VX900_IGA2_FIFO_MAX_DEPTH; | ||
1315 | iga2_fifo_threshold = VX900_IGA2_FIFO_THRESHOLD; | ||
1316 | iga2_fifo_high_threshold = | ||
1317 | VX900_IGA2_FIFO_HIGH_THRESHOLD; | ||
1318 | iga2_display_queue_expire_num = | ||
1319 | VX900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; | ||
1320 | } | ||
1321 | |||
1322 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) { | ||
1323 | /* Set Display FIFO Depath Select */ | ||
1324 | reg_value = | ||
1325 | IGA2_FIFO_DEPTH_SELECT_FORMULA(iga2_fifo_max_depth) | ||
1326 | - 1; | ||
1327 | /* Patch LCD in IGA2 case */ | ||
1328 | viafb_load_reg_num = | ||
1329 | display_fifo_depth_reg. | ||
1330 | iga2_fifo_depth_select_reg.reg_num; | ||
1331 | reg = | ||
1332 | display_fifo_depth_reg. | ||
1333 | iga2_fifo_depth_select_reg.reg; | ||
1334 | viafb_load_reg(reg_value, | ||
1335 | viafb_load_reg_num, reg, VIACR); | ||
1336 | } else { | ||
1337 | |||
1338 | /* Set Display FIFO Depath Select */ | ||
1339 | reg_value = | ||
1340 | IGA2_FIFO_DEPTH_SELECT_FORMULA(iga2_fifo_max_depth); | ||
1341 | viafb_load_reg_num = | ||
1342 | display_fifo_depth_reg. | ||
1343 | iga2_fifo_depth_select_reg.reg_num; | ||
1344 | reg = | ||
1345 | display_fifo_depth_reg. | ||
1346 | iga2_fifo_depth_select_reg.reg; | ||
1347 | viafb_load_reg(reg_value, | ||
1348 | viafb_load_reg_num, reg, VIACR); | ||
1349 | } | ||
1350 | |||
1351 | /* Set Display FIFO Threshold Select */ | ||
1352 | reg_value = IGA2_FIFO_THRESHOLD_FORMULA(iga2_fifo_threshold); | ||
1353 | viafb_load_reg_num = | ||
1354 | fifo_threshold_select_reg. | ||
1355 | iga2_fifo_threshold_select_reg.reg_num; | ||
1356 | reg = | ||
1357 | fifo_threshold_select_reg. | ||
1358 | iga2_fifo_threshold_select_reg.reg; | ||
1359 | viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR); | ||
1360 | |||
1361 | /* Set FIFO High Threshold Select */ | ||
1362 | reg_value = | ||
1363 | IGA2_FIFO_HIGH_THRESHOLD_FORMULA(iga2_fifo_high_threshold); | ||
1364 | viafb_load_reg_num = | ||
1365 | fifo_high_threshold_select_reg. | ||
1366 | iga2_fifo_high_threshold_select_reg.reg_num; | ||
1367 | reg = | ||
1368 | fifo_high_threshold_select_reg. | ||
1369 | iga2_fifo_high_threshold_select_reg.reg; | ||
1370 | viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR); | ||
1371 | |||
1372 | /* Set Display Queue Expire Num */ | ||
1373 | reg_value = | ||
1374 | IGA2_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA | ||
1375 | (iga2_display_queue_expire_num); | ||
1376 | viafb_load_reg_num = | ||
1377 | display_queue_expire_num_reg. | ||
1378 | iga2_display_queue_expire_num_reg.reg_num; | ||
1379 | reg = | ||
1380 | display_queue_expire_num_reg. | ||
1381 | iga2_display_queue_expire_num_reg.reg; | ||
1382 | viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR); | ||
1383 | |||
1384 | } | ||
1385 | |||
1386 | } | ||
1387 | |||
1388 | static struct via_pll_config get_pll_config(struct pll_limit *limits, int size, | ||
1389 | int clk) | ||
1390 | { | ||
1391 | struct via_pll_config cur, up, down, best = {0, 1, 0}; | ||
1392 | const u32 f0 = 14318180; /* X1 frequency */ | ||
1393 | int i, f; | ||
1394 | |||
1395 | for (i = 0; i < size; i++) { | ||
1396 | cur.rshift = limits[i].rshift; | ||
1397 | cur.divisor = limits[i].divisor; | ||
1398 | cur.multiplier = clk / ((f0 / cur.divisor)>>cur.rshift); | ||
1399 | f = abs(get_pll_output_frequency(f0, cur) - clk); | ||
1400 | up = down = cur; | ||
1401 | up.multiplier++; | ||
1402 | down.multiplier--; | ||
1403 | if (abs(get_pll_output_frequency(f0, up) - clk) < f) | ||
1404 | cur = up; | ||
1405 | else if (abs(get_pll_output_frequency(f0, down) - clk) < f) | ||
1406 | cur = down; | ||
1407 | |||
1408 | if (cur.multiplier < limits[i].multiplier_min) | ||
1409 | cur.multiplier = limits[i].multiplier_min; | ||
1410 | else if (cur.multiplier > limits[i].multiplier_max) | ||
1411 | cur.multiplier = limits[i].multiplier_max; | ||
1412 | |||
1413 | f = abs(get_pll_output_frequency(f0, cur) - clk); | ||
1414 | if (f < abs(get_pll_output_frequency(f0, best) - clk)) | ||
1415 | best = cur; | ||
1416 | } | ||
1417 | |||
1418 | return best; | ||
1419 | } | ||
1420 | |||
1421 | static struct via_pll_config get_best_pll_config(int clk) | ||
1422 | { | ||
1423 | struct via_pll_config config; | ||
1424 | |||
1425 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
1426 | case UNICHROME_CLE266: | ||
1427 | case UNICHROME_K400: | ||
1428 | config = get_pll_config(cle266_pll_limits, | ||
1429 | ARRAY_SIZE(cle266_pll_limits), clk); | ||
1430 | break; | ||
1431 | case UNICHROME_K800: | ||
1432 | case UNICHROME_PM800: | ||
1433 | case UNICHROME_CN700: | ||
1434 | config = get_pll_config(k800_pll_limits, | ||
1435 | ARRAY_SIZE(k800_pll_limits), clk); | ||
1436 | break; | ||
1437 | case UNICHROME_CX700: | ||
1438 | case UNICHROME_CN750: | ||
1439 | case UNICHROME_K8M890: | ||
1440 | case UNICHROME_P4M890: | ||
1441 | case UNICHROME_P4M900: | ||
1442 | case UNICHROME_VX800: | ||
1443 | config = get_pll_config(cx700_pll_limits, | ||
1444 | ARRAY_SIZE(cx700_pll_limits), clk); | ||
1445 | break; | ||
1446 | case UNICHROME_VX855: | ||
1447 | case UNICHROME_VX900: | ||
1448 | config = get_pll_config(vx855_pll_limits, | ||
1449 | ARRAY_SIZE(vx855_pll_limits), clk); | ||
1450 | break; | ||
1451 | } | ||
1452 | |||
1453 | return config; | ||
1454 | } | ||
1455 | |||
1456 | /* Set VCLK*/ | ||
1457 | void viafb_set_vclock(u32 clk, int set_iga) | ||
1458 | { | ||
1459 | struct via_pll_config config = get_best_pll_config(clk); | ||
1460 | |||
1461 | if (set_iga == IGA1) | ||
1462 | clock.set_primary_pll(config); | ||
1463 | if (set_iga == IGA2) | ||
1464 | clock.set_secondary_pll(config); | ||
1465 | |||
1466 | /* Fire! */ | ||
1467 | via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */ | ||
1468 | } | ||
1469 | |||
1470 | struct via_display_timing var_to_timing(const struct fb_var_screeninfo *var, | ||
1471 | u16 cxres, u16 cyres) | ||
1472 | { | ||
1473 | struct via_display_timing timing; | ||
1474 | u16 dx = (var->xres - cxres) / 2, dy = (var->yres - cyres) / 2; | ||
1475 | |||
1476 | timing.hor_addr = cxres; | ||
1477 | timing.hor_sync_start = timing.hor_addr + var->right_margin + dx; | ||
1478 | timing.hor_sync_end = timing.hor_sync_start + var->hsync_len; | ||
1479 | timing.hor_total = timing.hor_sync_end + var->left_margin + dx; | ||
1480 | timing.hor_blank_start = timing.hor_addr + dx; | ||
1481 | timing.hor_blank_end = timing.hor_total - dx; | ||
1482 | timing.ver_addr = cyres; | ||
1483 | timing.ver_sync_start = timing.ver_addr + var->lower_margin + dy; | ||
1484 | timing.ver_sync_end = timing.ver_sync_start + var->vsync_len; | ||
1485 | timing.ver_total = timing.ver_sync_end + var->upper_margin + dy; | ||
1486 | timing.ver_blank_start = timing.ver_addr + dy; | ||
1487 | timing.ver_blank_end = timing.ver_total - dy; | ||
1488 | return timing; | ||
1489 | } | ||
1490 | |||
1491 | void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, | ||
1492 | u16 cxres, u16 cyres, int iga) | ||
1493 | { | ||
1494 | struct via_display_timing crt_reg = var_to_timing(var, | ||
1495 | cxres ? cxres : var->xres, cyres ? cyres : var->yres); | ||
1496 | |||
1497 | if (iga == IGA1) | ||
1498 | via_set_primary_timing(&crt_reg); | ||
1499 | else if (iga == IGA2) | ||
1500 | via_set_secondary_timing(&crt_reg); | ||
1501 | |||
1502 | viafb_load_fetch_count_reg(var->xres, var->bits_per_pixel / 8, iga); | ||
1503 | if (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266 | ||
1504 | && viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400) | ||
1505 | viafb_load_FIFO_reg(iga, var->xres, var->yres); | ||
1506 | |||
1507 | viafb_set_vclock(PICOS2KHZ(var->pixclock) * 1000, iga); | ||
1508 | } | ||
1509 | |||
1510 | void viafb_init_chip_info(int chip_type) | ||
1511 | { | ||
1512 | via_clock_init(&clock, chip_type); | ||
1513 | init_gfx_chip_info(chip_type); | ||
1514 | init_tmds_chip_info(); | ||
1515 | init_lvds_chip_info(); | ||
1516 | |||
1517 | /*Set IGA path for each device */ | ||
1518 | viafb_set_iga_path(); | ||
1519 | |||
1520 | viaparinfo->lvds_setting_info->display_method = viafb_lcd_dsp_method; | ||
1521 | viaparinfo->lvds_setting_info->lcd_mode = viafb_lcd_mode; | ||
1522 | viaparinfo->lvds_setting_info2->display_method = | ||
1523 | viaparinfo->lvds_setting_info->display_method; | ||
1524 | viaparinfo->lvds_setting_info2->lcd_mode = | ||
1525 | viaparinfo->lvds_setting_info->lcd_mode; | ||
1526 | } | ||
1527 | |||
1528 | void viafb_update_device_setting(int hres, int vres, int bpp, int flag) | ||
1529 | { | ||
1530 | if (flag == 0) { | ||
1531 | viaparinfo->tmds_setting_info->h_active = hres; | ||
1532 | viaparinfo->tmds_setting_info->v_active = vres; | ||
1533 | } else { | ||
1534 | |||
1535 | if (viaparinfo->tmds_setting_info->iga_path == IGA2) { | ||
1536 | viaparinfo->tmds_setting_info->h_active = hres; | ||
1537 | viaparinfo->tmds_setting_info->v_active = vres; | ||
1538 | } | ||
1539 | |||
1540 | } | ||
1541 | } | ||
1542 | |||
1543 | static void init_gfx_chip_info(int chip_type) | ||
1544 | { | ||
1545 | u8 tmp; | ||
1546 | |||
1547 | viaparinfo->chip_info->gfx_chip_name = chip_type; | ||
1548 | |||
1549 | /* Check revision of CLE266 Chip */ | ||
1550 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { | ||
1551 | /* CR4F only define in CLE266.CX chip */ | ||
1552 | tmp = viafb_read_reg(VIACR, CR4F); | ||
1553 | viafb_write_reg(CR4F, VIACR, 0x55); | ||
1554 | if (viafb_read_reg(VIACR, CR4F) != 0x55) | ||
1555 | viaparinfo->chip_info->gfx_chip_revision = | ||
1556 | CLE266_REVISION_AX; | ||
1557 | else | ||
1558 | viaparinfo->chip_info->gfx_chip_revision = | ||
1559 | CLE266_REVISION_CX; | ||
1560 | /* restore orignal CR4F value */ | ||
1561 | viafb_write_reg(CR4F, VIACR, tmp); | ||
1562 | } | ||
1563 | |||
1564 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) { | ||
1565 | tmp = viafb_read_reg(VIASR, SR43); | ||
1566 | DEBUG_MSG(KERN_INFO "SR43:%X\n", tmp); | ||
1567 | if (tmp & 0x02) { | ||
1568 | viaparinfo->chip_info->gfx_chip_revision = | ||
1569 | CX700_REVISION_700M2; | ||
1570 | } else if (tmp & 0x40) { | ||
1571 | viaparinfo->chip_info->gfx_chip_revision = | ||
1572 | CX700_REVISION_700M; | ||
1573 | } else { | ||
1574 | viaparinfo->chip_info->gfx_chip_revision = | ||
1575 | CX700_REVISION_700; | ||
1576 | } | ||
1577 | } | ||
1578 | |||
1579 | /* Determine which 2D engine we have */ | ||
1580 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
1581 | case UNICHROME_VX800: | ||
1582 | case UNICHROME_VX855: | ||
1583 | case UNICHROME_VX900: | ||
1584 | viaparinfo->chip_info->twod_engine = VIA_2D_ENG_M1; | ||
1585 | break; | ||
1586 | case UNICHROME_K8M890: | ||
1587 | case UNICHROME_P4M900: | ||
1588 | viaparinfo->chip_info->twod_engine = VIA_2D_ENG_H5; | ||
1589 | break; | ||
1590 | default: | ||
1591 | viaparinfo->chip_info->twod_engine = VIA_2D_ENG_H2; | ||
1592 | break; | ||
1593 | } | ||
1594 | } | ||
1595 | |||
1596 | static void init_tmds_chip_info(void) | ||
1597 | { | ||
1598 | viafb_tmds_trasmitter_identify(); | ||
1599 | |||
1600 | if (INTERFACE_NONE == viaparinfo->chip_info->tmds_chip_info. | ||
1601 | output_interface) { | ||
1602 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
1603 | case UNICHROME_CX700: | ||
1604 | { | ||
1605 | /* we should check support by hardware layout.*/ | ||
1606 | if ((viafb_display_hardware_layout == | ||
1607 | HW_LAYOUT_DVI_ONLY) | ||
1608 | || (viafb_display_hardware_layout == | ||
1609 | HW_LAYOUT_LCD_DVI)) { | ||
1610 | viaparinfo->chip_info->tmds_chip_info. | ||
1611 | output_interface = INTERFACE_TMDS; | ||
1612 | } else { | ||
1613 | viaparinfo->chip_info->tmds_chip_info. | ||
1614 | output_interface = | ||
1615 | INTERFACE_NONE; | ||
1616 | } | ||
1617 | break; | ||
1618 | } | ||
1619 | case UNICHROME_K8M890: | ||
1620 | case UNICHROME_P4M900: | ||
1621 | case UNICHROME_P4M890: | ||
1622 | /* TMDS on PCIE, we set DFPLOW as default. */ | ||
1623 | viaparinfo->chip_info->tmds_chip_info.output_interface = | ||
1624 | INTERFACE_DFP_LOW; | ||
1625 | break; | ||
1626 | default: | ||
1627 | { | ||
1628 | /* set DVP1 default for DVI */ | ||
1629 | viaparinfo->chip_info->tmds_chip_info | ||
1630 | .output_interface = INTERFACE_DVP1; | ||
1631 | } | ||
1632 | } | ||
1633 | } | ||
1634 | |||
1635 | DEBUG_MSG(KERN_INFO "TMDS Chip = %d\n", | ||
1636 | viaparinfo->chip_info->tmds_chip_info.tmds_chip_name); | ||
1637 | viafb_init_dvi_size(&viaparinfo->shared->chip_info.tmds_chip_info, | ||
1638 | &viaparinfo->shared->tmds_setting_info); | ||
1639 | } | ||
1640 | |||
1641 | static void init_lvds_chip_info(void) | ||
1642 | { | ||
1643 | viafb_lvds_trasmitter_identify(); | ||
1644 | viafb_init_lcd_size(); | ||
1645 | viafb_init_lvds_output_interface(&viaparinfo->chip_info->lvds_chip_info, | ||
1646 | viaparinfo->lvds_setting_info); | ||
1647 | if (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) { | ||
1648 | viafb_init_lvds_output_interface(&viaparinfo->chip_info-> | ||
1649 | lvds_chip_info2, viaparinfo->lvds_setting_info2); | ||
1650 | } | ||
1651 | /*If CX700,two singel LCD, we need to reassign | ||
1652 | LCD interface to different LVDS port */ | ||
1653 | if ((UNICHROME_CX700 == viaparinfo->chip_info->gfx_chip_name) | ||
1654 | && (HW_LAYOUT_LCD1_LCD2 == viafb_display_hardware_layout)) { | ||
1655 | if ((INTEGRATED_LVDS == viaparinfo->chip_info->lvds_chip_info. | ||
1656 | lvds_chip_name) && (INTEGRATED_LVDS == | ||
1657 | viaparinfo->chip_info-> | ||
1658 | lvds_chip_info2.lvds_chip_name)) { | ||
1659 | viaparinfo->chip_info->lvds_chip_info.output_interface = | ||
1660 | INTERFACE_LVDS0; | ||
1661 | viaparinfo->chip_info->lvds_chip_info2. | ||
1662 | output_interface = | ||
1663 | INTERFACE_LVDS1; | ||
1664 | } | ||
1665 | } | ||
1666 | |||
1667 | DEBUG_MSG(KERN_INFO "LVDS Chip = %d\n", | ||
1668 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name); | ||
1669 | DEBUG_MSG(KERN_INFO "LVDS1 output_interface = %d\n", | ||
1670 | viaparinfo->chip_info->lvds_chip_info.output_interface); | ||
1671 | DEBUG_MSG(KERN_INFO "LVDS2 output_interface = %d\n", | ||
1672 | viaparinfo->chip_info->lvds_chip_info.output_interface); | ||
1673 | } | ||
1674 | |||
1675 | void viafb_init_dac(int set_iga) | ||
1676 | { | ||
1677 | int i; | ||
1678 | u8 tmp; | ||
1679 | |||
1680 | if (set_iga == IGA1) { | ||
1681 | /* access Primary Display's LUT */ | ||
1682 | viafb_write_reg_mask(SR1A, VIASR, 0x00, BIT0); | ||
1683 | /* turn off LCK */ | ||
1684 | viafb_write_reg_mask(SR1B, VIASR, 0x00, BIT7 + BIT6); | ||
1685 | for (i = 0; i < 256; i++) { | ||
1686 | write_dac_reg(i, palLUT_table[i].red, | ||
1687 | palLUT_table[i].green, | ||
1688 | palLUT_table[i].blue); | ||
1689 | } | ||
1690 | /* turn on LCK */ | ||
1691 | viafb_write_reg_mask(SR1B, VIASR, 0xC0, BIT7 + BIT6); | ||
1692 | } else { | ||
1693 | tmp = viafb_read_reg(VIACR, CR6A); | ||
1694 | /* access Secondary Display's LUT */ | ||
1695 | viafb_write_reg_mask(CR6A, VIACR, 0x40, BIT6); | ||
1696 | viafb_write_reg_mask(SR1A, VIASR, 0x01, BIT0); | ||
1697 | for (i = 0; i < 256; i++) { | ||
1698 | write_dac_reg(i, palLUT_table[i].red, | ||
1699 | palLUT_table[i].green, | ||
1700 | palLUT_table[i].blue); | ||
1701 | } | ||
1702 | /* set IGA1 DAC for default */ | ||
1703 | viafb_write_reg_mask(SR1A, VIASR, 0x00, BIT0); | ||
1704 | viafb_write_reg(CR6A, VIACR, tmp); | ||
1705 | } | ||
1706 | } | ||
1707 | |||
1708 | static void device_screen_off(void) | ||
1709 | { | ||
1710 | /* turn off CRT screen (IGA1) */ | ||
1711 | viafb_write_reg_mask(SR01, VIASR, 0x20, BIT5); | ||
1712 | } | ||
1713 | |||
1714 | static void device_screen_on(void) | ||
1715 | { | ||
1716 | /* turn on CRT screen (IGA1) */ | ||
1717 | viafb_write_reg_mask(SR01, VIASR, 0x00, BIT5); | ||
1718 | } | ||
1719 | |||
1720 | static void set_display_channel(void) | ||
1721 | { | ||
1722 | /*If viafb_LCD2_ON, on cx700, internal lvds's information | ||
1723 | is keeped on lvds_setting_info2 */ | ||
1724 | if (viafb_LCD2_ON && | ||
1725 | viaparinfo->lvds_setting_info2->device_lcd_dualedge) { | ||
1726 | /* For dual channel LCD: */ | ||
1727 | /* Set to Dual LVDS channel. */ | ||
1728 | viafb_write_reg_mask(CRD2, VIACR, 0x20, BIT4 + BIT5); | ||
1729 | } else if (viafb_LCD_ON && viafb_DVI_ON) { | ||
1730 | /* For LCD+DFP: */ | ||
1731 | /* Set to LVDS1 + TMDS channel. */ | ||
1732 | viafb_write_reg_mask(CRD2, VIACR, 0x10, BIT4 + BIT5); | ||
1733 | } else if (viafb_DVI_ON) { | ||
1734 | /* Set to single TMDS channel. */ | ||
1735 | viafb_write_reg_mask(CRD2, VIACR, 0x30, BIT4 + BIT5); | ||
1736 | } else if (viafb_LCD_ON) { | ||
1737 | if (viaparinfo->lvds_setting_info->device_lcd_dualedge) { | ||
1738 | /* For dual channel LCD: */ | ||
1739 | /* Set to Dual LVDS channel. */ | ||
1740 | viafb_write_reg_mask(CRD2, VIACR, 0x20, BIT4 + BIT5); | ||
1741 | } else { | ||
1742 | /* Set to LVDS0 + LVDS1 channel. */ | ||
1743 | viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT4 + BIT5); | ||
1744 | } | ||
1745 | } | ||
1746 | } | ||
1747 | |||
1748 | static u8 get_sync(struct fb_var_screeninfo *var) | ||
1749 | { | ||
1750 | u8 polarity = 0; | ||
1751 | |||
1752 | if (!(var->sync & FB_SYNC_HOR_HIGH_ACT)) | ||
1753 | polarity |= VIA_HSYNC_NEGATIVE; | ||
1754 | if (!(var->sync & FB_SYNC_VERT_HIGH_ACT)) | ||
1755 | polarity |= VIA_VSYNC_NEGATIVE; | ||
1756 | return polarity; | ||
1757 | } | ||
1758 | |||
1759 | static void hw_init(void) | ||
1760 | { | ||
1761 | int i; | ||
1762 | |||
1763 | inb(VIAStatus); | ||
1764 | outb(0x00, VIAAR); | ||
1765 | |||
1766 | /* Write Common Setting for Video Mode */ | ||
1767 | viafb_write_regx(common_vga, ARRAY_SIZE(common_vga)); | ||
1768 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
1769 | case UNICHROME_CLE266: | ||
1770 | viafb_write_regx(CLE266_ModeXregs, NUM_TOTAL_CLE266_ModeXregs); | ||
1771 | break; | ||
1772 | |||
1773 | case UNICHROME_K400: | ||
1774 | viafb_write_regx(KM400_ModeXregs, NUM_TOTAL_KM400_ModeXregs); | ||
1775 | break; | ||
1776 | |||
1777 | case UNICHROME_K800: | ||
1778 | case UNICHROME_PM800: | ||
1779 | viafb_write_regx(CN400_ModeXregs, NUM_TOTAL_CN400_ModeXregs); | ||
1780 | break; | ||
1781 | |||
1782 | case UNICHROME_CN700: | ||
1783 | case UNICHROME_K8M890: | ||
1784 | case UNICHROME_P4M890: | ||
1785 | case UNICHROME_P4M900: | ||
1786 | viafb_write_regx(CN700_ModeXregs, NUM_TOTAL_CN700_ModeXregs); | ||
1787 | break; | ||
1788 | |||
1789 | case UNICHROME_CX700: | ||
1790 | case UNICHROME_VX800: | ||
1791 | viafb_write_regx(CX700_ModeXregs, NUM_TOTAL_CX700_ModeXregs); | ||
1792 | break; | ||
1793 | |||
1794 | case UNICHROME_VX855: | ||
1795 | case UNICHROME_VX900: | ||
1796 | viafb_write_regx(VX855_ModeXregs, NUM_TOTAL_VX855_ModeXregs); | ||
1797 | break; | ||
1798 | } | ||
1799 | |||
1800 | /* magic required on VX900 for correct modesetting on IGA1 */ | ||
1801 | via_write_reg_mask(VIACR, 0x45, 0x00, 0x01); | ||
1802 | |||
1803 | /* probably this should go to the scaling code one day */ | ||
1804 | via_write_reg_mask(VIACR, 0xFD, 0, 0x80); /* VX900 hw scale on IGA2 */ | ||
1805 | viafb_write_regx(scaling_parameters, ARRAY_SIZE(scaling_parameters)); | ||
1806 | |||
1807 | /* Fill VPIT Parameters */ | ||
1808 | /* Write Misc Register */ | ||
1809 | outb(VPIT.Misc, VIA_MISC_REG_WRITE); | ||
1810 | |||
1811 | /* Write Sequencer */ | ||
1812 | for (i = 1; i <= StdSR; i++) | ||
1813 | via_write_reg(VIASR, i, VPIT.SR[i - 1]); | ||
1814 | |||
1815 | viafb_write_reg_mask(0x15, VIASR, 0xA2, 0xA2); | ||
1816 | |||
1817 | /* Write Graphic Controller */ | ||
1818 | for (i = 0; i < StdGR; i++) | ||
1819 | via_write_reg(VIAGR, i, VPIT.GR[i]); | ||
1820 | |||
1821 | /* Write Attribute Controller */ | ||
1822 | for (i = 0; i < StdAR; i++) { | ||
1823 | inb(VIAStatus); | ||
1824 | outb(i, VIAAR); | ||
1825 | outb(VPIT.AR[i], VIAAR); | ||
1826 | } | ||
1827 | |||
1828 | inb(VIAStatus); | ||
1829 | outb(0x20, VIAAR); | ||
1830 | |||
1831 | load_fix_bit_crtc_reg(); | ||
1832 | } | ||
1833 | |||
1834 | int viafb_setmode(void) | ||
1835 | { | ||
1836 | int j, cxres = 0, cyres = 0; | ||
1837 | int port; | ||
1838 | u32 devices = viaparinfo->shared->iga1_devices | ||
1839 | | viaparinfo->shared->iga2_devices; | ||
1840 | u8 value, index, mask; | ||
1841 | struct fb_var_screeninfo var2; | ||
1842 | |||
1843 | device_screen_off(); | ||
1844 | device_off(); | ||
1845 | via_set_state(devices, VIA_STATE_OFF); | ||
1846 | |||
1847 | hw_init(); | ||
1848 | |||
1849 | /* Update Patch Register */ | ||
1850 | |||
1851 | if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266 | ||
1852 | || viaparinfo->chip_info->gfx_chip_name == UNICHROME_K400) | ||
1853 | && viafbinfo->var.xres == 1024 && viafbinfo->var.yres == 768) { | ||
1854 | for (j = 0; j < res_patch_table[0].table_length; j++) { | ||
1855 | index = res_patch_table[0].io_reg_table[j].index; | ||
1856 | port = res_patch_table[0].io_reg_table[j].port; | ||
1857 | value = res_patch_table[0].io_reg_table[j].value; | ||
1858 | mask = res_patch_table[0].io_reg_table[j].mask; | ||
1859 | viafb_write_reg_mask(index, port, value, mask); | ||
1860 | } | ||
1861 | } | ||
1862 | |||
1863 | via_set_primary_pitch(viafbinfo->fix.line_length); | ||
1864 | via_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length | ||
1865 | : viafbinfo->fix.line_length); | ||
1866 | via_set_primary_color_depth(viaparinfo->depth); | ||
1867 | via_set_secondary_color_depth(viafb_dual_fb ? viaparinfo1->depth | ||
1868 | : viaparinfo->depth); | ||
1869 | via_set_source(viaparinfo->shared->iga1_devices, IGA1); | ||
1870 | via_set_source(viaparinfo->shared->iga2_devices, IGA2); | ||
1871 | if (viaparinfo->shared->iga2_devices) | ||
1872 | enable_second_display_channel(); | ||
1873 | else | ||
1874 | disable_second_display_channel(); | ||
1875 | |||
1876 | /* Update Refresh Rate Setting */ | ||
1877 | |||
1878 | /* Clear On Screen */ | ||
1879 | |||
1880 | if (viafb_dual_fb) { | ||
1881 | var2 = viafbinfo1->var; | ||
1882 | } else if (viafb_SAMM_ON) { | ||
1883 | viafb_fill_var_timing_info(&var2, viafb_get_best_mode( | ||
1884 | viafb_second_xres, viafb_second_yres, viafb_refresh1)); | ||
1885 | cxres = viafbinfo->var.xres; | ||
1886 | cyres = viafbinfo->var.yres; | ||
1887 | var2.bits_per_pixel = viafbinfo->var.bits_per_pixel; | ||
1888 | } | ||
1889 | |||
1890 | /* CRT set mode */ | ||
1891 | if (viafb_CRT_ON) { | ||
1892 | if (viaparinfo->shared->iga2_devices & VIA_CRT | ||
1893 | && viafb_SAMM_ON) | ||
1894 | viafb_fill_crtc_timing(&var2, cxres, cyres, IGA2); | ||
1895 | else | ||
1896 | viafb_fill_crtc_timing(&viafbinfo->var, 0, 0, | ||
1897 | (viaparinfo->shared->iga1_devices & VIA_CRT) | ||
1898 | ? IGA1 : IGA2); | ||
1899 | |||
1900 | /* Patch if set_hres is not 8 alignment (1366) to viafb_setmode | ||
1901 | to 8 alignment (1368),there is several pixels (2 pixels) | ||
1902 | on right side of screen. */ | ||
1903 | if (viafbinfo->var.xres % 8) { | ||
1904 | viafb_unlock_crt(); | ||
1905 | viafb_write_reg(CR02, VIACR, | ||
1906 | viafb_read_reg(VIACR, CR02) - 1); | ||
1907 | viafb_lock_crt(); | ||
1908 | } | ||
1909 | } | ||
1910 | |||
1911 | if (viafb_DVI_ON) { | ||
1912 | if (viaparinfo->shared->tmds_setting_info.iga_path == IGA2 | ||
1913 | && viafb_SAMM_ON) | ||
1914 | viafb_dvi_set_mode(&var2, cxres, cyres, IGA2); | ||
1915 | else | ||
1916 | viafb_dvi_set_mode(&viafbinfo->var, 0, 0, | ||
1917 | viaparinfo->tmds_setting_info->iga_path); | ||
1918 | } | ||
1919 | |||
1920 | if (viafb_LCD_ON) { | ||
1921 | if (viafb_SAMM_ON && | ||
1922 | (viaparinfo->lvds_setting_info->iga_path == IGA2)) { | ||
1923 | viafb_lcd_set_mode(&var2, cxres, cyres, | ||
1924 | viaparinfo->lvds_setting_info, | ||
1925 | &viaparinfo->chip_info->lvds_chip_info); | ||
1926 | } else { | ||
1927 | /* IGA1 doesn't have LCD scaling, so set it center. */ | ||
1928 | if (viaparinfo->lvds_setting_info->iga_path == IGA1) { | ||
1929 | viaparinfo->lvds_setting_info->display_method = | ||
1930 | LCD_CENTERING; | ||
1931 | } | ||
1932 | viafb_lcd_set_mode(&viafbinfo->var, 0, 0, | ||
1933 | viaparinfo->lvds_setting_info, | ||
1934 | &viaparinfo->chip_info->lvds_chip_info); | ||
1935 | } | ||
1936 | } | ||
1937 | if (viafb_LCD2_ON) { | ||
1938 | if (viafb_SAMM_ON && | ||
1939 | (viaparinfo->lvds_setting_info2->iga_path == IGA2)) { | ||
1940 | viafb_lcd_set_mode(&var2, cxres, cyres, | ||
1941 | viaparinfo->lvds_setting_info2, | ||
1942 | &viaparinfo->chip_info->lvds_chip_info2); | ||
1943 | } else { | ||
1944 | /* IGA1 doesn't have LCD scaling, so set it center. */ | ||
1945 | if (viaparinfo->lvds_setting_info2->iga_path == IGA1) { | ||
1946 | viaparinfo->lvds_setting_info2->display_method = | ||
1947 | LCD_CENTERING; | ||
1948 | } | ||
1949 | viafb_lcd_set_mode(&viafbinfo->var, 0, 0, | ||
1950 | viaparinfo->lvds_setting_info2, | ||
1951 | &viaparinfo->chip_info->lvds_chip_info2); | ||
1952 | } | ||
1953 | } | ||
1954 | |||
1955 | if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) | ||
1956 | && (viafb_LCD_ON || viafb_DVI_ON)) | ||
1957 | set_display_channel(); | ||
1958 | |||
1959 | /* If set mode normally, save resolution information for hot-plug . */ | ||
1960 | if (!viafb_hotplug) { | ||
1961 | viafb_hotplug_Xres = viafbinfo->var.xres; | ||
1962 | viafb_hotplug_Yres = viafbinfo->var.yres; | ||
1963 | viafb_hotplug_bpp = viafbinfo->var.bits_per_pixel; | ||
1964 | viafb_hotplug_refresh = viafb_refresh; | ||
1965 | |||
1966 | if (viafb_DVI_ON) | ||
1967 | viafb_DeviceStatus = DVI_Device; | ||
1968 | else | ||
1969 | viafb_DeviceStatus = CRT_Device; | ||
1970 | } | ||
1971 | device_on(); | ||
1972 | if (!viafb_SAMM_ON) | ||
1973 | via_set_sync_polarity(devices, get_sync(&viafbinfo->var)); | ||
1974 | else { | ||
1975 | via_set_sync_polarity(viaparinfo->shared->iga1_devices, | ||
1976 | get_sync(&viafbinfo->var)); | ||
1977 | via_set_sync_polarity(viaparinfo->shared->iga2_devices, | ||
1978 | get_sync(&var2)); | ||
1979 | } | ||
1980 | |||
1981 | clock.set_engine_pll_state(VIA_STATE_ON); | ||
1982 | clock.set_primary_clock_source(VIA_CLKSRC_X1, true); | ||
1983 | clock.set_secondary_clock_source(VIA_CLKSRC_X1, true); | ||
1984 | |||
1985 | #ifdef CONFIG_FB_VIA_X_COMPATIBILITY | ||
1986 | clock.set_primary_pll_state(VIA_STATE_ON); | ||
1987 | clock.set_primary_clock_state(VIA_STATE_ON); | ||
1988 | clock.set_secondary_pll_state(VIA_STATE_ON); | ||
1989 | clock.set_secondary_clock_state(VIA_STATE_ON); | ||
1990 | #else | ||
1991 | if (viaparinfo->shared->iga1_devices) { | ||
1992 | clock.set_primary_pll_state(VIA_STATE_ON); | ||
1993 | clock.set_primary_clock_state(VIA_STATE_ON); | ||
1994 | } else { | ||
1995 | clock.set_primary_pll_state(VIA_STATE_OFF); | ||
1996 | clock.set_primary_clock_state(VIA_STATE_OFF); | ||
1997 | } | ||
1998 | |||
1999 | if (viaparinfo->shared->iga2_devices) { | ||
2000 | clock.set_secondary_pll_state(VIA_STATE_ON); | ||
2001 | clock.set_secondary_clock_state(VIA_STATE_ON); | ||
2002 | } else { | ||
2003 | clock.set_secondary_pll_state(VIA_STATE_OFF); | ||
2004 | clock.set_secondary_clock_state(VIA_STATE_OFF); | ||
2005 | } | ||
2006 | #endif /*CONFIG_FB_VIA_X_COMPATIBILITY*/ | ||
2007 | |||
2008 | via_set_state(devices, VIA_STATE_ON); | ||
2009 | device_screen_on(); | ||
2010 | return 1; | ||
2011 | } | ||
2012 | |||
2013 | int viafb_get_refresh(int hres, int vres, u32 long_refresh) | ||
2014 | { | ||
2015 | const struct fb_videomode *best; | ||
2016 | |||
2017 | best = viafb_get_best_mode(hres, vres, long_refresh); | ||
2018 | if (!best) | ||
2019 | return 60; | ||
2020 | |||
2021 | if (abs(best->refresh - long_refresh) > 3) { | ||
2022 | if (hres == 1200 && vres == 900) | ||
2023 | return 49; /* OLPC DCON only supports 50 Hz */ | ||
2024 | else | ||
2025 | return 60; | ||
2026 | } | ||
2027 | |||
2028 | return best->refresh; | ||
2029 | } | ||
2030 | |||
2031 | static void device_off(void) | ||
2032 | { | ||
2033 | viafb_dvi_disable(); | ||
2034 | viafb_lcd_disable(); | ||
2035 | } | ||
2036 | |||
2037 | static void device_on(void) | ||
2038 | { | ||
2039 | if (viafb_DVI_ON == 1) | ||
2040 | viafb_dvi_enable(); | ||
2041 | if (viafb_LCD_ON == 1) | ||
2042 | viafb_lcd_enable(); | ||
2043 | } | ||
2044 | |||
2045 | static void enable_second_display_channel(void) | ||
2046 | { | ||
2047 | /* to enable second display channel. */ | ||
2048 | viafb_write_reg_mask(CR6A, VIACR, 0x00, BIT6); | ||
2049 | viafb_write_reg_mask(CR6A, VIACR, BIT7, BIT7); | ||
2050 | viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6); | ||
2051 | } | ||
2052 | |||
2053 | static void disable_second_display_channel(void) | ||
2054 | { | ||
2055 | /* to disable second display channel. */ | ||
2056 | viafb_write_reg_mask(CR6A, VIACR, 0x00, BIT6); | ||
2057 | viafb_write_reg_mask(CR6A, VIACR, 0x00, BIT7); | ||
2058 | viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6); | ||
2059 | } | ||
2060 | |||
2061 | void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\ | ||
2062 | *p_gfx_dpa_setting) | ||
2063 | { | ||
2064 | switch (output_interface) { | ||
2065 | case INTERFACE_DVP0: | ||
2066 | { | ||
2067 | /* DVP0 Clock Polarity and Adjust: */ | ||
2068 | viafb_write_reg_mask(CR96, VIACR, | ||
2069 | p_gfx_dpa_setting->DVP0, 0x0F); | ||
2070 | |||
2071 | /* DVP0 Clock and Data Pads Driving: */ | ||
2072 | viafb_write_reg_mask(SR1E, VIASR, | ||
2073 | p_gfx_dpa_setting->DVP0ClockDri_S, BIT2); | ||
2074 | viafb_write_reg_mask(SR2A, VIASR, | ||
2075 | p_gfx_dpa_setting->DVP0ClockDri_S1, | ||
2076 | BIT4); | ||
2077 | viafb_write_reg_mask(SR1B, VIASR, | ||
2078 | p_gfx_dpa_setting->DVP0DataDri_S, BIT1); | ||
2079 | viafb_write_reg_mask(SR2A, VIASR, | ||
2080 | p_gfx_dpa_setting->DVP0DataDri_S1, BIT5); | ||
2081 | break; | ||
2082 | } | ||
2083 | |||
2084 | case INTERFACE_DVP1: | ||
2085 | { | ||
2086 | /* DVP1 Clock Polarity and Adjust: */ | ||
2087 | viafb_write_reg_mask(CR9B, VIACR, | ||
2088 | p_gfx_dpa_setting->DVP1, 0x0F); | ||
2089 | |||
2090 | /* DVP1 Clock and Data Pads Driving: */ | ||
2091 | viafb_write_reg_mask(SR65, VIASR, | ||
2092 | p_gfx_dpa_setting->DVP1Driving, 0x0F); | ||
2093 | break; | ||
2094 | } | ||
2095 | |||
2096 | case INTERFACE_DFP_HIGH: | ||
2097 | { | ||
2098 | viafb_write_reg_mask(CR97, VIACR, | ||
2099 | p_gfx_dpa_setting->DFPHigh, 0x0F); | ||
2100 | break; | ||
2101 | } | ||
2102 | |||
2103 | case INTERFACE_DFP_LOW: | ||
2104 | { | ||
2105 | viafb_write_reg_mask(CR99, VIACR, | ||
2106 | p_gfx_dpa_setting->DFPLow, 0x0F); | ||
2107 | break; | ||
2108 | } | ||
2109 | |||
2110 | case INTERFACE_DFP: | ||
2111 | { | ||
2112 | viafb_write_reg_mask(CR97, VIACR, | ||
2113 | p_gfx_dpa_setting->DFPHigh, 0x0F); | ||
2114 | viafb_write_reg_mask(CR99, VIACR, | ||
2115 | p_gfx_dpa_setting->DFPLow, 0x0F); | ||
2116 | break; | ||
2117 | } | ||
2118 | } | ||
2119 | } | ||
2120 | |||
2121 | void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, | ||
2122 | const struct fb_videomode *mode) | ||
2123 | { | ||
2124 | var->pixclock = mode->pixclock; | ||
2125 | var->xres = mode->xres; | ||
2126 | var->yres = mode->yres; | ||
2127 | var->left_margin = mode->left_margin; | ||
2128 | var->right_margin = mode->right_margin; | ||
2129 | var->hsync_len = mode->hsync_len; | ||
2130 | var->upper_margin = mode->upper_margin; | ||
2131 | var->lower_margin = mode->lower_margin; | ||
2132 | var->vsync_len = mode->vsync_len; | ||
2133 | var->sync = mode->sync; | ||
2134 | } | ||
diff --git a/drivers/video/fbdev/via/hw.h b/drivers/video/fbdev/via/hw.h new file mode 100644 index 000000000000..3be073c58b03 --- /dev/null +++ b/drivers/video/fbdev/via/hw.h | |||
@@ -0,0 +1,676 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef __HW_H__ | ||
23 | #define __HW_H__ | ||
24 | |||
25 | #include <linux/seq_file.h> | ||
26 | |||
27 | #include "viamode.h" | ||
28 | #include "global.h" | ||
29 | #include "via_modesetting.h" | ||
30 | |||
31 | #define viafb_read_reg(p, i) via_read_reg(p, i) | ||
32 | #define viafb_write_reg(i, p, d) via_write_reg(p, i, d) | ||
33 | #define viafb_write_reg_mask(i, p, d, m) via_write_reg_mask(p, i, d, m) | ||
34 | |||
35 | /* VIA output devices */ | ||
36 | #define VIA_LDVP0 0x00000001 | ||
37 | #define VIA_LDVP1 0x00000002 | ||
38 | #define VIA_DVP0 0x00000004 | ||
39 | #define VIA_CRT 0x00000010 | ||
40 | #define VIA_DVP1 0x00000020 | ||
41 | #define VIA_LVDS1 0x00000040 | ||
42 | #define VIA_LVDS2 0x00000080 | ||
43 | |||
44 | /* VIA output device power states */ | ||
45 | #define VIA_STATE_ON 0 | ||
46 | #define VIA_STATE_STANDBY 1 | ||
47 | #define VIA_STATE_SUSPEND 2 | ||
48 | #define VIA_STATE_OFF 3 | ||
49 | |||
50 | /* VIA output device sync polarity */ | ||
51 | #define VIA_HSYNC_NEGATIVE 0x01 | ||
52 | #define VIA_VSYNC_NEGATIVE 0x02 | ||
53 | |||
54 | /**********************************************************/ | ||
55 | /* Definition IGA2 Design Method of CRTC Shadow Registers */ | ||
56 | /**********************************************************/ | ||
57 | #define IGA2_HOR_TOTAL_SHADOW_FORMULA(x) ((x/8)-5) | ||
58 | #define IGA2_HOR_BLANK_END_SHADOW_FORMULA(x, y) (((x+y)/8)-1) | ||
59 | #define IGA2_VER_TOTAL_SHADOW_FORMULA(x) ((x)-2) | ||
60 | #define IGA2_VER_ADDR_SHADOW_FORMULA(x) ((x)-1) | ||
61 | #define IGA2_VER_BLANK_START_SHADOW_FORMULA(x) ((x)-1) | ||
62 | #define IGA2_VER_BLANK_END_SHADOW_FORMULA(x, y) ((x+y)-1) | ||
63 | #define IGA2_VER_SYNC_START_SHADOW_FORMULA(x) (x) | ||
64 | #define IGA2_VER_SYNC_END_SHADOW_FORMULA(x, y) (x+y) | ||
65 | |||
66 | /* Define Register Number for IGA2 Shadow CRTC Timing */ | ||
67 | |||
68 | /* location: {CR6D,0,7},{CR71,3,3} */ | ||
69 | #define IGA2_SHADOW_HOR_TOTAL_REG_NUM 2 | ||
70 | /* location: {CR6E,0,7} */ | ||
71 | #define IGA2_SHADOW_HOR_BLANK_END_REG_NUM 1 | ||
72 | /* location: {CR6F,0,7},{CR71,0,2} */ | ||
73 | #define IGA2_SHADOW_VER_TOTAL_REG_NUM 2 | ||
74 | /* location: {CR70,0,7},{CR71,4,6} */ | ||
75 | #define IGA2_SHADOW_VER_ADDR_REG_NUM 2 | ||
76 | /* location: {CR72,0,7},{CR74,4,6} */ | ||
77 | #define IGA2_SHADOW_VER_BLANK_START_REG_NUM 2 | ||
78 | /* location: {CR73,0,7},{CR74,0,2} */ | ||
79 | #define IGA2_SHADOW_VER_BLANK_END_REG_NUM 2 | ||
80 | /* location: {CR75,0,7},{CR76,4,6} */ | ||
81 | #define IGA2_SHADOW_VER_SYNC_START_REG_NUM 2 | ||
82 | /* location: {CR76,0,3} */ | ||
83 | #define IGA2_SHADOW_VER_SYNC_END_REG_NUM 1 | ||
84 | |||
85 | /* Define Fetch Count Register*/ | ||
86 | |||
87 | /* location: {SR1C,0,7},{SR1D,0,1} */ | ||
88 | #define IGA1_FETCH_COUNT_REG_NUM 2 | ||
89 | /* 16 bytes alignment. */ | ||
90 | #define IGA1_FETCH_COUNT_ALIGN_BYTE 16 | ||
91 | /* x: H resolution, y: color depth */ | ||
92 | #define IGA1_FETCH_COUNT_PATCH_VALUE 4 | ||
93 | #define IGA1_FETCH_COUNT_FORMULA(x, y) \ | ||
94 | (((x*y)/IGA1_FETCH_COUNT_ALIGN_BYTE) + IGA1_FETCH_COUNT_PATCH_VALUE) | ||
95 | |||
96 | /* location: {CR65,0,7},{CR67,2,3} */ | ||
97 | #define IGA2_FETCH_COUNT_REG_NUM 2 | ||
98 | #define IGA2_FETCH_COUNT_ALIGN_BYTE 16 | ||
99 | #define IGA2_FETCH_COUNT_PATCH_VALUE 0 | ||
100 | #define IGA2_FETCH_COUNT_FORMULA(x, y) \ | ||
101 | (((x*y)/IGA2_FETCH_COUNT_ALIGN_BYTE) + IGA2_FETCH_COUNT_PATCH_VALUE) | ||
102 | |||
103 | /* Staring Address*/ | ||
104 | |||
105 | /* location: {CR0C,0,7},{CR0D,0,7},{CR34,0,7},{CR48,0,1} */ | ||
106 | #define IGA1_STARTING_ADDR_REG_NUM 4 | ||
107 | /* location: {CR62,1,7},{CR63,0,7},{CR64,0,7} */ | ||
108 | #define IGA2_STARTING_ADDR_REG_NUM 3 | ||
109 | |||
110 | /* Define Display OFFSET*/ | ||
111 | /* These value are by HW suggested value*/ | ||
112 | /* location: {SR17,0,7} */ | ||
113 | #define K800_IGA1_FIFO_MAX_DEPTH 384 | ||
114 | /* location: {SR16,0,5},{SR16,7,7} */ | ||
115 | #define K800_IGA1_FIFO_THRESHOLD 328 | ||
116 | /* location: {SR18,0,5},{SR18,7,7} */ | ||
117 | #define K800_IGA1_FIFO_HIGH_THRESHOLD 296 | ||
118 | /* location: {SR22,0,4}. (128/4) =64, K800 must be set zero, */ | ||
119 | /* because HW only 5 bits */ | ||
120 | #define K800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 0 | ||
121 | |||
122 | /* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ | ||
123 | #define K800_IGA2_FIFO_MAX_DEPTH 384 | ||
124 | /* location: {CR68,0,3},{CR95,4,6} */ | ||
125 | #define K800_IGA2_FIFO_THRESHOLD 328 | ||
126 | /* location: {CR92,0,3},{CR95,0,2} */ | ||
127 | #define K800_IGA2_FIFO_HIGH_THRESHOLD 296 | ||
128 | /* location: {CR94,0,6} */ | ||
129 | #define K800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128 | ||
130 | |||
131 | /* location: {SR17,0,7} */ | ||
132 | #define P880_IGA1_FIFO_MAX_DEPTH 192 | ||
133 | /* location: {SR16,0,5},{SR16,7,7} */ | ||
134 | #define P880_IGA1_FIFO_THRESHOLD 128 | ||
135 | /* location: {SR18,0,5},{SR18,7,7} */ | ||
136 | #define P880_IGA1_FIFO_HIGH_THRESHOLD 64 | ||
137 | /* location: {SR22,0,4}. (128/4) =64, K800 must be set zero, */ | ||
138 | /* because HW only 5 bits */ | ||
139 | #define P880_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 0 | ||
140 | |||
141 | /* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ | ||
142 | #define P880_IGA2_FIFO_MAX_DEPTH 96 | ||
143 | /* location: {CR68,0,3},{CR95,4,6} */ | ||
144 | #define P880_IGA2_FIFO_THRESHOLD 64 | ||
145 | /* location: {CR92,0,3},{CR95,0,2} */ | ||
146 | #define P880_IGA2_FIFO_HIGH_THRESHOLD 32 | ||
147 | /* location: {CR94,0,6} */ | ||
148 | #define P880_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128 | ||
149 | |||
150 | /* VT3314 chipset*/ | ||
151 | |||
152 | /* location: {SR17,0,7} */ | ||
153 | #define CN700_IGA1_FIFO_MAX_DEPTH 96 | ||
154 | /* location: {SR16,0,5},{SR16,7,7} */ | ||
155 | #define CN700_IGA1_FIFO_THRESHOLD 80 | ||
156 | /* location: {SR18,0,5},{SR18,7,7} */ | ||
157 | #define CN700_IGA1_FIFO_HIGH_THRESHOLD 64 | ||
158 | /* location: {SR22,0,4}. (128/4) =64, P800 must be set zero, | ||
159 | because HW only 5 bits */ | ||
160 | #define CN700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 0 | ||
161 | /* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ | ||
162 | #define CN700_IGA2_FIFO_MAX_DEPTH 96 | ||
163 | /* location: {CR68,0,3},{CR95,4,6} */ | ||
164 | #define CN700_IGA2_FIFO_THRESHOLD 80 | ||
165 | /* location: {CR92,0,3},{CR95,0,2} */ | ||
166 | #define CN700_IGA2_FIFO_HIGH_THRESHOLD 32 | ||
167 | /* location: {CR94,0,6} */ | ||
168 | #define CN700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128 | ||
169 | |||
170 | /* For VT3324, these values are suggested by HW */ | ||
171 | /* location: {SR17,0,7} */ | ||
172 | #define CX700_IGA1_FIFO_MAX_DEPTH 192 | ||
173 | /* location: {SR16,0,5},{SR16,7,7} */ | ||
174 | #define CX700_IGA1_FIFO_THRESHOLD 128 | ||
175 | /* location: {SR18,0,5},{SR18,7,7} */ | ||
176 | #define CX700_IGA1_FIFO_HIGH_THRESHOLD 128 | ||
177 | /* location: {SR22,0,4} */ | ||
178 | #define CX700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 124 | ||
179 | |||
180 | /* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ | ||
181 | #define CX700_IGA2_FIFO_MAX_DEPTH 96 | ||
182 | /* location: {CR68,0,3},{CR95,4,6} */ | ||
183 | #define CX700_IGA2_FIFO_THRESHOLD 64 | ||
184 | /* location: {CR92,0,3},{CR95,0,2} */ | ||
185 | #define CX700_IGA2_FIFO_HIGH_THRESHOLD 32 | ||
186 | /* location: {CR94,0,6} */ | ||
187 | #define CX700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128 | ||
188 | |||
189 | /* VT3336 chipset*/ | ||
190 | /* location: {SR17,0,7} */ | ||
191 | #define K8M890_IGA1_FIFO_MAX_DEPTH 360 | ||
192 | /* location: {SR16,0,5},{SR16,7,7} */ | ||
193 | #define K8M890_IGA1_FIFO_THRESHOLD 328 | ||
194 | /* location: {SR18,0,5},{SR18,7,7} */ | ||
195 | #define K8M890_IGA1_FIFO_HIGH_THRESHOLD 296 | ||
196 | /* location: {SR22,0,4}. */ | ||
197 | #define K8M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 124 | ||
198 | |||
199 | /* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ | ||
200 | #define K8M890_IGA2_FIFO_MAX_DEPTH 360 | ||
201 | /* location: {CR68,0,3},{CR95,4,6} */ | ||
202 | #define K8M890_IGA2_FIFO_THRESHOLD 328 | ||
203 | /* location: {CR92,0,3},{CR95,0,2} */ | ||
204 | #define K8M890_IGA2_FIFO_HIGH_THRESHOLD 296 | ||
205 | /* location: {CR94,0,6} */ | ||
206 | #define K8M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 124 | ||
207 | |||
208 | /* VT3327 chipset*/ | ||
209 | /* location: {SR17,0,7} */ | ||
210 | #define P4M890_IGA1_FIFO_MAX_DEPTH 96 | ||
211 | /* location: {SR16,0,5},{SR16,7,7} */ | ||
212 | #define P4M890_IGA1_FIFO_THRESHOLD 76 | ||
213 | /* location: {SR18,0,5},{SR18,7,7} */ | ||
214 | #define P4M890_IGA1_FIFO_HIGH_THRESHOLD 64 | ||
215 | /* location: {SR22,0,4}. (32/4) =8 */ | ||
216 | #define P4M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 32 | ||
217 | /* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ | ||
218 | #define P4M890_IGA2_FIFO_MAX_DEPTH 96 | ||
219 | /* location: {CR68,0,3},{CR95,4,6} */ | ||
220 | #define P4M890_IGA2_FIFO_THRESHOLD 76 | ||
221 | /* location: {CR92,0,3},{CR95,0,2} */ | ||
222 | #define P4M890_IGA2_FIFO_HIGH_THRESHOLD 64 | ||
223 | /* location: {CR94,0,6} */ | ||
224 | #define P4M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 32 | ||
225 | |||
226 | /* VT3364 chipset*/ | ||
227 | /* location: {SR17,0,7} */ | ||
228 | #define P4M900_IGA1_FIFO_MAX_DEPTH 96 | ||
229 | /* location: {SR16,0,5},{SR16,7,7} */ | ||
230 | #define P4M900_IGA1_FIFO_THRESHOLD 76 | ||
231 | /* location: {SR18,0,5},{SR18,7,7} */ | ||
232 | #define P4M900_IGA1_FIFO_HIGH_THRESHOLD 76 | ||
233 | /* location: {SR22,0,4}. */ | ||
234 | #define P4M900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 32 | ||
235 | /* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ | ||
236 | #define P4M900_IGA2_FIFO_MAX_DEPTH 96 | ||
237 | /* location: {CR68,0,3},{CR95,4,6} */ | ||
238 | #define P4M900_IGA2_FIFO_THRESHOLD 76 | ||
239 | /* location: {CR92,0,3},{CR95,0,2} */ | ||
240 | #define P4M900_IGA2_FIFO_HIGH_THRESHOLD 76 | ||
241 | /* location: {CR94,0,6} */ | ||
242 | #define P4M900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 32 | ||
243 | |||
244 | /* For VT3353, these values are suggested by HW */ | ||
245 | /* location: {SR17,0,7} */ | ||
246 | #define VX800_IGA1_FIFO_MAX_DEPTH 192 | ||
247 | /* location: {SR16,0,5},{SR16,7,7} */ | ||
248 | #define VX800_IGA1_FIFO_THRESHOLD 152 | ||
249 | /* location: {SR18,0,5},{SR18,7,7} */ | ||
250 | #define VX800_IGA1_FIFO_HIGH_THRESHOLD 152 | ||
251 | /* location: {SR22,0,4} */ | ||
252 | #define VX800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 64 | ||
253 | /* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ | ||
254 | #define VX800_IGA2_FIFO_MAX_DEPTH 96 | ||
255 | /* location: {CR68,0,3},{CR95,4,6} */ | ||
256 | #define VX800_IGA2_FIFO_THRESHOLD 64 | ||
257 | /* location: {CR92,0,3},{CR95,0,2} */ | ||
258 | #define VX800_IGA2_FIFO_HIGH_THRESHOLD 32 | ||
259 | /* location: {CR94,0,6} */ | ||
260 | #define VX800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128 | ||
261 | |||
262 | /* For VT3409 */ | ||
263 | #define VX855_IGA1_FIFO_MAX_DEPTH 400 | ||
264 | #define VX855_IGA1_FIFO_THRESHOLD 320 | ||
265 | #define VX855_IGA1_FIFO_HIGH_THRESHOLD 320 | ||
266 | #define VX855_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 160 | ||
267 | |||
268 | #define VX855_IGA2_FIFO_MAX_DEPTH 200 | ||
269 | #define VX855_IGA2_FIFO_THRESHOLD 160 | ||
270 | #define VX855_IGA2_FIFO_HIGH_THRESHOLD 160 | ||
271 | #define VX855_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 320 | ||
272 | |||
273 | /* For VT3410 */ | ||
274 | #define VX900_IGA1_FIFO_MAX_DEPTH 400 | ||
275 | #define VX900_IGA1_FIFO_THRESHOLD 320 | ||
276 | #define VX900_IGA1_FIFO_HIGH_THRESHOLD 320 | ||
277 | #define VX900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 160 | ||
278 | |||
279 | #define VX900_IGA2_FIFO_MAX_DEPTH 192 | ||
280 | #define VX900_IGA2_FIFO_THRESHOLD 160 | ||
281 | #define VX900_IGA2_FIFO_HIGH_THRESHOLD 160 | ||
282 | #define VX900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 320 | ||
283 | |||
284 | #define IGA1_FIFO_DEPTH_SELECT_REG_NUM 1 | ||
285 | #define IGA1_FIFO_THRESHOLD_REG_NUM 2 | ||
286 | #define IGA1_FIFO_HIGH_THRESHOLD_REG_NUM 2 | ||
287 | #define IGA1_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM 1 | ||
288 | |||
289 | #define IGA2_FIFO_DEPTH_SELECT_REG_NUM 3 | ||
290 | #define IGA2_FIFO_THRESHOLD_REG_NUM 2 | ||
291 | #define IGA2_FIFO_HIGH_THRESHOLD_REG_NUM 2 | ||
292 | #define IGA2_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM 1 | ||
293 | |||
294 | #define IGA1_FIFO_DEPTH_SELECT_FORMULA(x) ((x/2)-1) | ||
295 | #define IGA1_FIFO_THRESHOLD_FORMULA(x) (x/4) | ||
296 | #define IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(x) (x/4) | ||
297 | #define IGA1_FIFO_HIGH_THRESHOLD_FORMULA(x) (x/4) | ||
298 | #define IGA2_FIFO_DEPTH_SELECT_FORMULA(x) (((x/2)/4)-1) | ||
299 | #define IGA2_FIFO_THRESHOLD_FORMULA(x) (x/4) | ||
300 | #define IGA2_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(x) (x/4) | ||
301 | #define IGA2_FIFO_HIGH_THRESHOLD_FORMULA(x) (x/4) | ||
302 | |||
303 | /************************************************************************/ | ||
304 | /* LCD Timing */ | ||
305 | /************************************************************************/ | ||
306 | |||
307 | /* 500 ms = 500000 us */ | ||
308 | #define LCD_POWER_SEQ_TD0 500000 | ||
309 | /* 50 ms = 50000 us */ | ||
310 | #define LCD_POWER_SEQ_TD1 50000 | ||
311 | /* 0 us */ | ||
312 | #define LCD_POWER_SEQ_TD2 0 | ||
313 | /* 210 ms = 210000 us */ | ||
314 | #define LCD_POWER_SEQ_TD3 210000 | ||
315 | /* 2^10 * (1/14.31818M) = 71.475 us (K400.revA) */ | ||
316 | #define CLE266_POWER_SEQ_UNIT 71 | ||
317 | /* 2^11 * (1/14.31818M) = 142.95 us (K400.revB) */ | ||
318 | #define K800_POWER_SEQ_UNIT 142 | ||
319 | /* 2^13 * (1/14.31818M) = 572.1 us */ | ||
320 | #define P880_POWER_SEQ_UNIT 572 | ||
321 | |||
322 | #define CLE266_POWER_SEQ_FORMULA(x) ((x)/CLE266_POWER_SEQ_UNIT) | ||
323 | #define K800_POWER_SEQ_FORMULA(x) ((x)/K800_POWER_SEQ_UNIT) | ||
324 | #define P880_POWER_SEQ_FORMULA(x) ((x)/P880_POWER_SEQ_UNIT) | ||
325 | |||
326 | /* location: {CR8B,0,7},{CR8F,0,3} */ | ||
327 | #define LCD_POWER_SEQ_TD0_REG_NUM 2 | ||
328 | /* location: {CR8C,0,7},{CR8F,4,7} */ | ||
329 | #define LCD_POWER_SEQ_TD1_REG_NUM 2 | ||
330 | /* location: {CR8D,0,7},{CR90,0,3} */ | ||
331 | #define LCD_POWER_SEQ_TD2_REG_NUM 2 | ||
332 | /* location: {CR8E,0,7},{CR90,4,7} */ | ||
333 | #define LCD_POWER_SEQ_TD3_REG_NUM 2 | ||
334 | |||
335 | /* LCD Scaling factor*/ | ||
336 | /* x: indicate setting horizontal size*/ | ||
337 | /* y: indicate panel horizontal size*/ | ||
338 | |||
339 | /* Horizontal scaling factor 10 bits (2^10) */ | ||
340 | #define CLE266_LCD_HOR_SCF_FORMULA(x, y) (((x-1)*1024)/(y-1)) | ||
341 | /* Vertical scaling factor 10 bits (2^10) */ | ||
342 | #define CLE266_LCD_VER_SCF_FORMULA(x, y) (((x-1)*1024)/(y-1)) | ||
343 | /* Horizontal scaling factor 10 bits (2^12) */ | ||
344 | #define K800_LCD_HOR_SCF_FORMULA(x, y) (((x-1)*4096)/(y-1)) | ||
345 | /* Vertical scaling factor 10 bits (2^11) */ | ||
346 | #define K800_LCD_VER_SCF_FORMULA(x, y) (((x-1)*2048)/(y-1)) | ||
347 | |||
348 | /* location: {CR9F,0,1},{CR77,0,7},{CR79,4,5} */ | ||
349 | #define LCD_HOR_SCALING_FACTOR_REG_NUM 3 | ||
350 | /* location: {CR79,3,3},{CR78,0,7},{CR79,6,7} */ | ||
351 | #define LCD_VER_SCALING_FACTOR_REG_NUM 3 | ||
352 | /* location: {CR77,0,7},{CR79,4,5} */ | ||
353 | #define LCD_HOR_SCALING_FACTOR_REG_NUM_CLE 2 | ||
354 | /* location: {CR78,0,7},{CR79,6,7} */ | ||
355 | #define LCD_VER_SCALING_FACTOR_REG_NUM_CLE 2 | ||
356 | |||
357 | struct io_register { | ||
358 | u8 io_addr; | ||
359 | u8 start_bit; | ||
360 | u8 end_bit; | ||
361 | }; | ||
362 | |||
363 | /***************************************************** | ||
364 | ** Define IGA2 Shadow Display Timing **** | ||
365 | *****************************************************/ | ||
366 | |||
367 | /* IGA2 Shadow Horizontal Total */ | ||
368 | struct iga2_shadow_hor_total { | ||
369 | int reg_num; | ||
370 | struct io_register reg[IGA2_SHADOW_HOR_TOTAL_REG_NUM]; | ||
371 | }; | ||
372 | |||
373 | /* IGA2 Shadow Horizontal Blank End */ | ||
374 | struct iga2_shadow_hor_blank_end { | ||
375 | int reg_num; | ||
376 | struct io_register reg[IGA2_SHADOW_HOR_BLANK_END_REG_NUM]; | ||
377 | }; | ||
378 | |||
379 | /* IGA2 Shadow Vertical Total */ | ||
380 | struct iga2_shadow_ver_total { | ||
381 | int reg_num; | ||
382 | struct io_register reg[IGA2_SHADOW_VER_TOTAL_REG_NUM]; | ||
383 | }; | ||
384 | |||
385 | /* IGA2 Shadow Vertical Addressable Video */ | ||
386 | struct iga2_shadow_ver_addr { | ||
387 | int reg_num; | ||
388 | struct io_register reg[IGA2_SHADOW_VER_ADDR_REG_NUM]; | ||
389 | }; | ||
390 | |||
391 | /* IGA2 Shadow Vertical Blank Start */ | ||
392 | struct iga2_shadow_ver_blank_start { | ||
393 | int reg_num; | ||
394 | struct io_register reg[IGA2_SHADOW_VER_BLANK_START_REG_NUM]; | ||
395 | }; | ||
396 | |||
397 | /* IGA2 Shadow Vertical Blank End */ | ||
398 | struct iga2_shadow_ver_blank_end { | ||
399 | int reg_num; | ||
400 | struct io_register reg[IGA2_SHADOW_VER_BLANK_END_REG_NUM]; | ||
401 | }; | ||
402 | |||
403 | /* IGA2 Shadow Vertical Sync Start */ | ||
404 | struct iga2_shadow_ver_sync_start { | ||
405 | int reg_num; | ||
406 | struct io_register reg[IGA2_SHADOW_VER_SYNC_START_REG_NUM]; | ||
407 | }; | ||
408 | |||
409 | /* IGA2 Shadow Vertical Sync End */ | ||
410 | struct iga2_shadow_ver_sync_end { | ||
411 | int reg_num; | ||
412 | struct io_register reg[IGA2_SHADOW_VER_SYNC_END_REG_NUM]; | ||
413 | }; | ||
414 | |||
415 | /* IGA1 Fetch Count Register */ | ||
416 | struct iga1_fetch_count { | ||
417 | int reg_num; | ||
418 | struct io_register reg[IGA1_FETCH_COUNT_REG_NUM]; | ||
419 | }; | ||
420 | |||
421 | /* IGA2 Fetch Count Register */ | ||
422 | struct iga2_fetch_count { | ||
423 | int reg_num; | ||
424 | struct io_register reg[IGA2_FETCH_COUNT_REG_NUM]; | ||
425 | }; | ||
426 | |||
427 | struct fetch_count { | ||
428 | struct iga1_fetch_count iga1_fetch_count_reg; | ||
429 | struct iga2_fetch_count iga2_fetch_count_reg; | ||
430 | }; | ||
431 | |||
432 | /* Starting Address Register */ | ||
433 | struct iga1_starting_addr { | ||
434 | int reg_num; | ||
435 | struct io_register reg[IGA1_STARTING_ADDR_REG_NUM]; | ||
436 | }; | ||
437 | |||
438 | struct iga2_starting_addr { | ||
439 | int reg_num; | ||
440 | struct io_register reg[IGA2_STARTING_ADDR_REG_NUM]; | ||
441 | }; | ||
442 | |||
443 | struct starting_addr { | ||
444 | struct iga1_starting_addr iga1_starting_addr_reg; | ||
445 | struct iga2_starting_addr iga2_starting_addr_reg; | ||
446 | }; | ||
447 | |||
448 | /* LCD Power Sequence Timer */ | ||
449 | struct lcd_pwd_seq_td0 { | ||
450 | int reg_num; | ||
451 | struct io_register reg[LCD_POWER_SEQ_TD0_REG_NUM]; | ||
452 | }; | ||
453 | |||
454 | struct lcd_pwd_seq_td1 { | ||
455 | int reg_num; | ||
456 | struct io_register reg[LCD_POWER_SEQ_TD1_REG_NUM]; | ||
457 | }; | ||
458 | |||
459 | struct lcd_pwd_seq_td2 { | ||
460 | int reg_num; | ||
461 | struct io_register reg[LCD_POWER_SEQ_TD2_REG_NUM]; | ||
462 | }; | ||
463 | |||
464 | struct lcd_pwd_seq_td3 { | ||
465 | int reg_num; | ||
466 | struct io_register reg[LCD_POWER_SEQ_TD3_REG_NUM]; | ||
467 | }; | ||
468 | |||
469 | struct _lcd_pwd_seq_timer { | ||
470 | struct lcd_pwd_seq_td0 td0; | ||
471 | struct lcd_pwd_seq_td1 td1; | ||
472 | struct lcd_pwd_seq_td2 td2; | ||
473 | struct lcd_pwd_seq_td3 td3; | ||
474 | }; | ||
475 | |||
476 | /* LCD Scaling Factor */ | ||
477 | struct _lcd_hor_scaling_factor { | ||
478 | int reg_num; | ||
479 | struct io_register reg[LCD_HOR_SCALING_FACTOR_REG_NUM]; | ||
480 | }; | ||
481 | |||
482 | struct _lcd_ver_scaling_factor { | ||
483 | int reg_num; | ||
484 | struct io_register reg[LCD_VER_SCALING_FACTOR_REG_NUM]; | ||
485 | }; | ||
486 | |||
487 | struct _lcd_scaling_factor { | ||
488 | struct _lcd_hor_scaling_factor lcd_hor_scaling_factor; | ||
489 | struct _lcd_ver_scaling_factor lcd_ver_scaling_factor; | ||
490 | }; | ||
491 | |||
492 | struct pll_limit { | ||
493 | u16 multiplier_min; | ||
494 | u16 multiplier_max; | ||
495 | u8 divisor; | ||
496 | u8 rshift; | ||
497 | }; | ||
498 | |||
499 | struct rgbLUT { | ||
500 | u8 red; | ||
501 | u8 green; | ||
502 | u8 blue; | ||
503 | }; | ||
504 | |||
505 | struct lcd_pwd_seq_timer { | ||
506 | u16 td0; | ||
507 | u16 td1; | ||
508 | u16 td2; | ||
509 | u16 td3; | ||
510 | }; | ||
511 | |||
512 | /* Display FIFO Relation Registers*/ | ||
513 | struct iga1_fifo_depth_select { | ||
514 | int reg_num; | ||
515 | struct io_register reg[IGA1_FIFO_DEPTH_SELECT_REG_NUM]; | ||
516 | }; | ||
517 | |||
518 | struct iga1_fifo_threshold_select { | ||
519 | int reg_num; | ||
520 | struct io_register reg[IGA1_FIFO_THRESHOLD_REG_NUM]; | ||
521 | }; | ||
522 | |||
523 | struct iga1_fifo_high_threshold_select { | ||
524 | int reg_num; | ||
525 | struct io_register reg[IGA1_FIFO_HIGH_THRESHOLD_REG_NUM]; | ||
526 | }; | ||
527 | |||
528 | struct iga1_display_queue_expire_num { | ||
529 | int reg_num; | ||
530 | struct io_register reg[IGA1_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM]; | ||
531 | }; | ||
532 | |||
533 | struct iga2_fifo_depth_select { | ||
534 | int reg_num; | ||
535 | struct io_register reg[IGA2_FIFO_DEPTH_SELECT_REG_NUM]; | ||
536 | }; | ||
537 | |||
538 | struct iga2_fifo_threshold_select { | ||
539 | int reg_num; | ||
540 | struct io_register reg[IGA2_FIFO_THRESHOLD_REG_NUM]; | ||
541 | }; | ||
542 | |||
543 | struct iga2_fifo_high_threshold_select { | ||
544 | int reg_num; | ||
545 | struct io_register reg[IGA2_FIFO_HIGH_THRESHOLD_REG_NUM]; | ||
546 | }; | ||
547 | |||
548 | struct iga2_display_queue_expire_num { | ||
549 | int reg_num; | ||
550 | struct io_register reg[IGA2_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM]; | ||
551 | }; | ||
552 | |||
553 | struct fifo_depth_select { | ||
554 | struct iga1_fifo_depth_select iga1_fifo_depth_select_reg; | ||
555 | struct iga2_fifo_depth_select iga2_fifo_depth_select_reg; | ||
556 | }; | ||
557 | |||
558 | struct fifo_threshold_select { | ||
559 | struct iga1_fifo_threshold_select iga1_fifo_threshold_select_reg; | ||
560 | struct iga2_fifo_threshold_select iga2_fifo_threshold_select_reg; | ||
561 | }; | ||
562 | |||
563 | struct fifo_high_threshold_select { | ||
564 | struct iga1_fifo_high_threshold_select | ||
565 | iga1_fifo_high_threshold_select_reg; | ||
566 | struct iga2_fifo_high_threshold_select | ||
567 | iga2_fifo_high_threshold_select_reg; | ||
568 | }; | ||
569 | |||
570 | struct display_queue_expire_num { | ||
571 | struct iga1_display_queue_expire_num | ||
572 | iga1_display_queue_expire_num_reg; | ||
573 | struct iga2_display_queue_expire_num | ||
574 | iga2_display_queue_expire_num_reg; | ||
575 | }; | ||
576 | |||
577 | struct iga2_shadow_crtc_timing { | ||
578 | struct iga2_shadow_hor_total hor_total_shadow; | ||
579 | struct iga2_shadow_hor_blank_end hor_blank_end_shadow; | ||
580 | struct iga2_shadow_ver_total ver_total_shadow; | ||
581 | struct iga2_shadow_ver_addr ver_addr_shadow; | ||
582 | struct iga2_shadow_ver_blank_start ver_blank_start_shadow; | ||
583 | struct iga2_shadow_ver_blank_end ver_blank_end_shadow; | ||
584 | struct iga2_shadow_ver_sync_start ver_sync_start_shadow; | ||
585 | struct iga2_shadow_ver_sync_end ver_sync_end_shadow; | ||
586 | }; | ||
587 | |||
588 | /* device ID */ | ||
589 | #define CLE266_FUNCTION3 0x3123 | ||
590 | #define KM400_FUNCTION3 0x3205 | ||
591 | #define CN400_FUNCTION2 0x2259 | ||
592 | #define CN400_FUNCTION3 0x3259 | ||
593 | /* support VT3314 chipset */ | ||
594 | #define CN700_FUNCTION2 0x2314 | ||
595 | #define CN700_FUNCTION3 0x3208 | ||
596 | /* VT3324 chipset */ | ||
597 | #define CX700_FUNCTION2 0x2324 | ||
598 | #define CX700_FUNCTION3 0x3324 | ||
599 | /* VT3204 chipset*/ | ||
600 | #define KM800_FUNCTION3 0x3204 | ||
601 | /* VT3336 chipset*/ | ||
602 | #define KM890_FUNCTION3 0x3336 | ||
603 | /* VT3327 chipset*/ | ||
604 | #define P4M890_FUNCTION3 0x3327 | ||
605 | /* VT3293 chipset*/ | ||
606 | #define CN750_FUNCTION3 0x3208 | ||
607 | /* VT3364 chipset*/ | ||
608 | #define P4M900_FUNCTION3 0x3364 | ||
609 | /* VT3353 chipset*/ | ||
610 | #define VX800_FUNCTION3 0x3353 | ||
611 | /* VT3409 chipset*/ | ||
612 | #define VX855_FUNCTION3 0x3409 | ||
613 | /* VT3410 chipset*/ | ||
614 | #define VX900_FUNCTION3 0x3410 | ||
615 | |||
616 | struct IODATA { | ||
617 | u8 Index; | ||
618 | u8 Mask; | ||
619 | u8 Data; | ||
620 | }; | ||
621 | |||
622 | struct pci_device_id_info { | ||
623 | u32 vendor; | ||
624 | u32 device; | ||
625 | u32 chip_index; | ||
626 | }; | ||
627 | |||
628 | struct via_device_mapping { | ||
629 | u32 device; | ||
630 | const char *name; | ||
631 | }; | ||
632 | |||
633 | extern int viafb_SAMM_ON; | ||
634 | extern int viafb_dual_fb; | ||
635 | extern int viafb_LCD2_ON; | ||
636 | extern int viafb_LCD_ON; | ||
637 | extern int viafb_DVI_ON; | ||
638 | extern int viafb_hotplug; | ||
639 | |||
640 | struct via_display_timing var_to_timing(const struct fb_var_screeninfo *var, | ||
641 | u16 cxres, u16 cyres); | ||
642 | void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, | ||
643 | u16 cxres, u16 cyres, int iga); | ||
644 | void viafb_set_vclock(u32 CLK, int set_iga); | ||
645 | void viafb_load_reg(int timing_value, int viafb_load_reg_num, | ||
646 | struct io_register *reg, | ||
647 | int io_type); | ||
648 | void via_set_source(u32 devices, u8 iga); | ||
649 | void via_set_state(u32 devices, u8 state); | ||
650 | void via_set_sync_polarity(u32 devices, u8 polarity); | ||
651 | u32 via_parse_odev(char *input, char **end); | ||
652 | void via_odev_to_seq(struct seq_file *m, u32 odev); | ||
653 | void init_ad9389(void); | ||
654 | /* Access I/O Function */ | ||
655 | void viafb_lock_crt(void); | ||
656 | void viafb_unlock_crt(void); | ||
657 | void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga); | ||
658 | void viafb_write_regx(struct io_reg RegTable[], int ItemNum); | ||
659 | void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active); | ||
660 | void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\ | ||
661 | *p_gfx_dpa_setting); | ||
662 | |||
663 | int viafb_setmode(void); | ||
664 | void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, | ||
665 | const struct fb_videomode *mode); | ||
666 | void viafb_init_chip_info(int chip_type); | ||
667 | void viafb_init_dac(int set_iga); | ||
668 | int viafb_get_refresh(int hres, int vres, u32 float_refresh); | ||
669 | void viafb_update_device_setting(int hres, int vres, int bpp, int flag); | ||
670 | |||
671 | void viafb_set_iga_path(void); | ||
672 | void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue); | ||
673 | void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue); | ||
674 | void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len); | ||
675 | |||
676 | #endif /* __HW_H__ */ | ||
diff --git a/drivers/video/fbdev/via/ioctl.c b/drivers/video/fbdev/via/ioctl.c new file mode 100644 index 000000000000..ea1c51428823 --- /dev/null +++ b/drivers/video/fbdev/via/ioctl.c | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include "global.h" | ||
23 | |||
24 | int viafb_ioctl_get_viafb_info(u_long arg) | ||
25 | { | ||
26 | struct viafb_ioctl_info viainfo; | ||
27 | |||
28 | memset(&viainfo, 0, sizeof(struct viafb_ioctl_info)); | ||
29 | |||
30 | viainfo.viafb_id = VIAID; | ||
31 | viainfo.vendor_id = PCI_VIA_VENDOR_ID; | ||
32 | |||
33 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
34 | case UNICHROME_CLE266: | ||
35 | viainfo.device_id = UNICHROME_CLE266_DID; | ||
36 | break; | ||
37 | |||
38 | case UNICHROME_K400: | ||
39 | viainfo.device_id = UNICHROME_K400_DID; | ||
40 | break; | ||
41 | |||
42 | case UNICHROME_K800: | ||
43 | viainfo.device_id = UNICHROME_K800_DID; | ||
44 | break; | ||
45 | |||
46 | case UNICHROME_PM800: | ||
47 | viainfo.device_id = UNICHROME_PM800_DID; | ||
48 | break; | ||
49 | |||
50 | case UNICHROME_CN700: | ||
51 | viainfo.device_id = UNICHROME_CN700_DID; | ||
52 | break; | ||
53 | |||
54 | case UNICHROME_CX700: | ||
55 | viainfo.device_id = UNICHROME_CX700_DID; | ||
56 | break; | ||
57 | |||
58 | case UNICHROME_K8M890: | ||
59 | viainfo.device_id = UNICHROME_K8M890_DID; | ||
60 | break; | ||
61 | |||
62 | case UNICHROME_P4M890: | ||
63 | viainfo.device_id = UNICHROME_P4M890_DID; | ||
64 | break; | ||
65 | |||
66 | case UNICHROME_P4M900: | ||
67 | viainfo.device_id = UNICHROME_P4M900_DID; | ||
68 | break; | ||
69 | } | ||
70 | |||
71 | viainfo.version = VERSION_MAJOR; | ||
72 | viainfo.revision = VERSION_MINOR; | ||
73 | |||
74 | if (copy_to_user((void __user *)arg, &viainfo, sizeof(viainfo))) | ||
75 | return -EFAULT; | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | /* Hot-Plug Priority: DVI > CRT*/ | ||
81 | int viafb_ioctl_hotplug(int hres, int vres, int bpp) | ||
82 | { | ||
83 | int DVIsense, status = 0; | ||
84 | DEBUG_MSG(KERN_INFO "viafb_ioctl_hotplug!!\n"); | ||
85 | |||
86 | if (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name != | ||
87 | NON_TMDS_TRANSMITTER) { | ||
88 | DVIsense = viafb_dvi_sense(); | ||
89 | |||
90 | if (DVIsense) { | ||
91 | DEBUG_MSG(KERN_INFO "DVI Attached...\n"); | ||
92 | if (viafb_DeviceStatus != DVI_Device) { | ||
93 | viafb_DVI_ON = 1; | ||
94 | viafb_CRT_ON = 0; | ||
95 | viafb_LCD_ON = 0; | ||
96 | viafb_DeviceStatus = DVI_Device; | ||
97 | viafb_set_iga_path(); | ||
98 | return viafb_DeviceStatus; | ||
99 | } | ||
100 | status = 1; | ||
101 | } else | ||
102 | DEBUG_MSG(KERN_INFO "DVI De-attached...\n"); | ||
103 | } | ||
104 | |||
105 | if ((viafb_DeviceStatus != CRT_Device) && (status == 0)) { | ||
106 | viafb_CRT_ON = 1; | ||
107 | viafb_DVI_ON = 0; | ||
108 | viafb_LCD_ON = 0; | ||
109 | |||
110 | viafb_DeviceStatus = CRT_Device; | ||
111 | viafb_set_iga_path(); | ||
112 | return viafb_DeviceStatus; | ||
113 | } | ||
114 | |||
115 | return 0; | ||
116 | } | ||
diff --git a/drivers/video/fbdev/via/ioctl.h b/drivers/video/fbdev/via/ioctl.h new file mode 100644 index 000000000000..6010d10b59e8 --- /dev/null +++ b/drivers/video/fbdev/via/ioctl.h | |||
@@ -0,0 +1,203 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef __IOCTL_H__ | ||
23 | #define __IOCTL_H__ | ||
24 | |||
25 | #ifndef __user | ||
26 | #define __user | ||
27 | #endif | ||
28 | |||
29 | /* VIAFB IOCTL definition */ | ||
30 | #define VIAFB_GET_INFO_SIZE 0x56494101 /* 'VIA\01' */ | ||
31 | #define VIAFB_GET_INFO 0x56494102 /* 'VIA\02' */ | ||
32 | #define VIAFB_HOTPLUG 0x56494103 /* 'VIA\03' */ | ||
33 | #define VIAFB_SET_HOTPLUG_FLAG 0x56494104 /* 'VIA\04' */ | ||
34 | #define VIAFB_GET_RESOLUTION 0x56494105 /* 'VIA\05' */ | ||
35 | #define VIAFB_GET_SAMM_INFO 0x56494107 /* 'VIA\07' */ | ||
36 | #define VIAFB_TURN_ON_OUTPUT_DEVICE 0x56494108 /* 'VIA\08' */ | ||
37 | #define VIAFB_TURN_OFF_OUTPUT_DEVICE 0x56494109 /* 'VIA\09' */ | ||
38 | #define VIAFB_GET_DEVICE 0x5649410B | ||
39 | #define VIAFB_GET_DRIVER_VERSION 0x56494112 /* 'VIA\12' */ | ||
40 | #define VIAFB_GET_CHIP_INFO 0x56494113 /* 'VIA\13' */ | ||
41 | #define VIAFB_GET_DEVICE_INFO 0x56494115 | ||
42 | |||
43 | #define VIAFB_GET_DEVICE_SUPPORT 0x56494118 | ||
44 | #define VIAFB_GET_DEVICE_CONNECT 0x56494119 | ||
45 | #define VIAFB_GET_PANEL_SUPPORT_EXPAND 0x5649411A | ||
46 | #define VIAFB_GET_DRIVER_NAME 0x56494122 | ||
47 | #define VIAFB_GET_DEVICE_SUPPORT_STATE 0x56494123 | ||
48 | #define VIAFB_GET_GAMMA_LUT 0x56494124 | ||
49 | #define VIAFB_SET_GAMMA_LUT 0x56494125 | ||
50 | #define VIAFB_GET_GAMMA_SUPPORT_STATE 0x56494126 | ||
51 | #define VIAFB_SYNC_SURFACE 0x56494130 | ||
52 | #define VIAFB_GET_DRIVER_CAPS 0x56494131 | ||
53 | #define VIAFB_GET_IGA_SCALING_INFO 0x56494132 | ||
54 | #define VIAFB_GET_PANEL_MAX_SIZE 0x56494133 | ||
55 | #define VIAFB_GET_PANEL_MAX_POSITION 0x56494134 | ||
56 | #define VIAFB_SET_PANEL_SIZE 0x56494135 | ||
57 | #define VIAFB_SET_PANEL_POSITION 0x56494136 | ||
58 | #define VIAFB_GET_PANEL_POSITION 0x56494137 | ||
59 | #define VIAFB_GET_PANEL_SIZE 0x56494138 | ||
60 | |||
61 | #define None_Device 0x00 | ||
62 | #define CRT_Device 0x01 | ||
63 | #define LCD_Device 0x02 | ||
64 | #define DVI_Device 0x08 | ||
65 | #define CRT2_Device 0x10 | ||
66 | #define LCD2_Device 0x40 | ||
67 | |||
68 | #define OP_LCD_CENTERING 0x01 | ||
69 | #define OP_LCD_PANEL_ID 0x02 | ||
70 | #define OP_LCD_MODE 0x03 | ||
71 | |||
72 | /*SAMM operation flag*/ | ||
73 | #define OP_SAMM 0x80 | ||
74 | |||
75 | #define LCD_PANEL_ID_MAXIMUM 23 | ||
76 | |||
77 | #define STATE_ON 0x1 | ||
78 | #define STATE_OFF 0x0 | ||
79 | #define STATE_DEFAULT 0xFFFF | ||
80 | |||
81 | #define MAX_ACTIVE_DEV_NUM 2 | ||
82 | |||
83 | struct device_t { | ||
84 | unsigned short crt:1; | ||
85 | unsigned short dvi:1; | ||
86 | unsigned short lcd:1; | ||
87 | unsigned short samm:1; | ||
88 | unsigned short lcd_dsp_cent:1; | ||
89 | unsigned char lcd_mode:1; | ||
90 | unsigned short epia_dvi:1; | ||
91 | unsigned short lcd_dual_edge:1; | ||
92 | unsigned short lcd2:1; | ||
93 | |||
94 | unsigned short primary_dev; | ||
95 | unsigned char lcd_panel_id; | ||
96 | unsigned short xres, yres; | ||
97 | unsigned short xres1, yres1; | ||
98 | unsigned short refresh; | ||
99 | unsigned short bpp; | ||
100 | unsigned short refresh1; | ||
101 | unsigned short bpp1; | ||
102 | unsigned short sequence; | ||
103 | unsigned short bus_width; | ||
104 | }; | ||
105 | |||
106 | struct viafb_ioctl_info { | ||
107 | u32 viafb_id; /* for identifying viafb */ | ||
108 | #define VIAID 0x56494146 /* Identify myself with 'VIAF' */ | ||
109 | u16 vendor_id; | ||
110 | u16 device_id; | ||
111 | u8 version; | ||
112 | u8 revision; | ||
113 | u8 reserved[246]; /* for future use */ | ||
114 | }; | ||
115 | |||
116 | struct viafb_ioctl_mode { | ||
117 | u32 xres; | ||
118 | u32 yres; | ||
119 | u32 refresh; | ||
120 | u32 bpp; | ||
121 | u32 xres_sec; | ||
122 | u32 yres_sec; | ||
123 | u32 virtual_xres_sec; | ||
124 | u32 virtual_yres_sec; | ||
125 | u32 refresh_sec; | ||
126 | u32 bpp_sec; | ||
127 | }; | ||
128 | struct viafb_ioctl_samm { | ||
129 | u32 samm_status; | ||
130 | u32 size_prim; | ||
131 | u32 size_sec; | ||
132 | u32 mem_base; | ||
133 | u32 offset_sec; | ||
134 | }; | ||
135 | |||
136 | struct viafb_driver_version { | ||
137 | int iMajorNum; | ||
138 | int iKernelNum; | ||
139 | int iOSNum; | ||
140 | int iMinorNum; | ||
141 | }; | ||
142 | |||
143 | struct viafb_ioctl_lcd_attribute { | ||
144 | unsigned int panel_id; | ||
145 | unsigned int display_center; | ||
146 | unsigned int lcd_mode; | ||
147 | }; | ||
148 | |||
149 | struct viafb_ioctl_setting { | ||
150 | /* Enable or disable active devices */ | ||
151 | unsigned short device_flag; | ||
152 | /* Indicate which device should be turn on or turn off. */ | ||
153 | unsigned short device_status; | ||
154 | unsigned int reserved; | ||
155 | /* Indicate which LCD's attribute can be changed. */ | ||
156 | unsigned short lcd_operation_flag; | ||
157 | /* 1: SAMM ON 0: SAMM OFF */ | ||
158 | unsigned short samm_status; | ||
159 | /* horizontal resolution of first device */ | ||
160 | unsigned short first_dev_hor_res; | ||
161 | /* vertical resolution of first device */ | ||
162 | unsigned short first_dev_ver_res; | ||
163 | /* horizontal resolution of second device */ | ||
164 | unsigned short second_dev_hor_res; | ||
165 | /* vertical resolution of second device */ | ||
166 | unsigned short second_dev_ver_res; | ||
167 | /* refresh rate of first device */ | ||
168 | unsigned short first_dev_refresh; | ||
169 | /* bpp of first device */ | ||
170 | unsigned short first_dev_bpp; | ||
171 | /* refresh rate of second device */ | ||
172 | unsigned short second_dev_refresh; | ||
173 | /* bpp of second device */ | ||
174 | unsigned short second_dev_bpp; | ||
175 | /* Indicate which device are primary display device. */ | ||
176 | unsigned int primary_device; | ||
177 | unsigned int struct_reserved[35]; | ||
178 | struct viafb_ioctl_lcd_attribute lcd_attributes; | ||
179 | }; | ||
180 | |||
181 | struct _UTFunctionCaps { | ||
182 | unsigned int dw3DScalingState; | ||
183 | unsigned int reserved[31]; | ||
184 | }; | ||
185 | |||
186 | struct _POSITIONVALUE { | ||
187 | unsigned int dwX; | ||
188 | unsigned int dwY; | ||
189 | }; | ||
190 | |||
191 | struct _panel_size_pos_info { | ||
192 | unsigned int device_type; | ||
193 | int x; | ||
194 | int y; | ||
195 | }; | ||
196 | |||
197 | extern int viafb_LCD_ON; | ||
198 | extern int viafb_DVI_ON; | ||
199 | |||
200 | int viafb_ioctl_get_viafb_info(u_long arg); | ||
201 | int viafb_ioctl_hotplug(int hres, int vres, int bpp); | ||
202 | |||
203 | #endif /* __IOCTL_H__ */ | ||
diff --git a/drivers/video/fbdev/via/lcd.c b/drivers/video/fbdev/via/lcd.c new file mode 100644 index 000000000000..5d21ff436ec8 --- /dev/null +++ b/drivers/video/fbdev/via/lcd.c | |||
@@ -0,0 +1,1005 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #include <linux/via-core.h> | ||
22 | #include <linux/via_i2c.h> | ||
23 | #include "global.h" | ||
24 | |||
25 | #define viafb_compact_res(x, y) (((x)<<16)|(y)) | ||
26 | |||
27 | /* CLE266 Software Power Sequence */ | ||
28 | /* {Mask}, {Data}, {Delay} */ | ||
29 | static const int PowerSequenceOn[3][3] = { | ||
30 | {0x10, 0x08, 0x06}, {0x10, 0x08, 0x06}, {0x19, 0x1FE, 0x01} | ||
31 | }; | ||
32 | static const int PowerSequenceOff[3][3] = { | ||
33 | {0x06, 0x08, 0x10}, {0x00, 0x00, 0x00}, {0xD2, 0x19, 0x01} | ||
34 | }; | ||
35 | |||
36 | static struct _lcd_scaling_factor lcd_scaling_factor = { | ||
37 | /* LCD Horizontal Scaling Factor Register */ | ||
38 | {LCD_HOR_SCALING_FACTOR_REG_NUM, | ||
39 | {{CR9F, 0, 1}, {CR77, 0, 7}, {CR79, 4, 5} } }, | ||
40 | /* LCD Vertical Scaling Factor Register */ | ||
41 | {LCD_VER_SCALING_FACTOR_REG_NUM, | ||
42 | {{CR79, 3, 3}, {CR78, 0, 7}, {CR79, 6, 7} } } | ||
43 | }; | ||
44 | static struct _lcd_scaling_factor lcd_scaling_factor_CLE = { | ||
45 | /* LCD Horizontal Scaling Factor Register */ | ||
46 | {LCD_HOR_SCALING_FACTOR_REG_NUM_CLE, {{CR77, 0, 7}, {CR79, 4, 5} } }, | ||
47 | /* LCD Vertical Scaling Factor Register */ | ||
48 | {LCD_VER_SCALING_FACTOR_REG_NUM_CLE, {{CR78, 0, 7}, {CR79, 6, 7} } } | ||
49 | }; | ||
50 | |||
51 | static bool lvds_identify_integratedlvds(void); | ||
52 | static void fp_id_to_vindex(int panel_id); | ||
53 | static int lvds_register_read(int index); | ||
54 | static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, | ||
55 | int panel_vres); | ||
56 | static void lcd_patch_skew_dvp0(struct lvds_setting_information | ||
57 | *plvds_setting_info, | ||
58 | struct lvds_chip_information *plvds_chip_info); | ||
59 | static void lcd_patch_skew_dvp1(struct lvds_setting_information | ||
60 | *plvds_setting_info, | ||
61 | struct lvds_chip_information *plvds_chip_info); | ||
62 | static void lcd_patch_skew(struct lvds_setting_information | ||
63 | *plvds_setting_info, struct lvds_chip_information *plvds_chip_info); | ||
64 | |||
65 | static void integrated_lvds_disable(struct lvds_setting_information | ||
66 | *plvds_setting_info, | ||
67 | struct lvds_chip_information *plvds_chip_info); | ||
68 | static void integrated_lvds_enable(struct lvds_setting_information | ||
69 | *plvds_setting_info, | ||
70 | struct lvds_chip_information *plvds_chip_info); | ||
71 | static void lcd_powersequence_off(void); | ||
72 | static void lcd_powersequence_on(void); | ||
73 | static void fill_lcd_format(void); | ||
74 | static void check_diport_of_integrated_lvds( | ||
75 | struct lvds_chip_information *plvds_chip_info, | ||
76 | struct lvds_setting_information | ||
77 | *plvds_setting_info); | ||
78 | |||
79 | static inline bool check_lvds_chip(int device_id_subaddr, int device_id) | ||
80 | { | ||
81 | return lvds_register_read(device_id_subaddr) == device_id; | ||
82 | } | ||
83 | |||
84 | void viafb_init_lcd_size(void) | ||
85 | { | ||
86 | DEBUG_MSG(KERN_INFO "viafb_init_lcd_size()\n"); | ||
87 | |||
88 | fp_id_to_vindex(viafb_lcd_panel_id); | ||
89 | viaparinfo->lvds_setting_info2->lcd_panel_hres = | ||
90 | viaparinfo->lvds_setting_info->lcd_panel_hres; | ||
91 | viaparinfo->lvds_setting_info2->lcd_panel_vres = | ||
92 | viaparinfo->lvds_setting_info->lcd_panel_vres; | ||
93 | viaparinfo->lvds_setting_info2->device_lcd_dualedge = | ||
94 | viaparinfo->lvds_setting_info->device_lcd_dualedge; | ||
95 | viaparinfo->lvds_setting_info2->LCDDithering = | ||
96 | viaparinfo->lvds_setting_info->LCDDithering; | ||
97 | } | ||
98 | |||
99 | static bool lvds_identify_integratedlvds(void) | ||
100 | { | ||
101 | if (viafb_display_hardware_layout == HW_LAYOUT_LCD_EXTERNAL_LCD2) { | ||
102 | /* Two dual channel LCD (Internal LVDS + External LVDS): */ | ||
103 | /* If we have an external LVDS, such as VT1636, we should | ||
104 | have its chip ID already. */ | ||
105 | if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) { | ||
106 | viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name = | ||
107 | INTEGRATED_LVDS; | ||
108 | DEBUG_MSG(KERN_INFO "Support two dual channel LVDS! " | ||
109 | "(Internal LVDS + External LVDS)\n"); | ||
110 | } else { | ||
111 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = | ||
112 | INTEGRATED_LVDS; | ||
113 | DEBUG_MSG(KERN_INFO "Not found external LVDS, " | ||
114 | "so can't support two dual channel LVDS!\n"); | ||
115 | } | ||
116 | } else if (viafb_display_hardware_layout == HW_LAYOUT_LCD1_LCD2) { | ||
117 | /* Two single channel LCD (Internal LVDS + Internal LVDS): */ | ||
118 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = | ||
119 | INTEGRATED_LVDS; | ||
120 | viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name = | ||
121 | INTEGRATED_LVDS; | ||
122 | DEBUG_MSG(KERN_INFO "Support two single channel LVDS! " | ||
123 | "(Internal LVDS + Internal LVDS)\n"); | ||
124 | } else if (viafb_display_hardware_layout != HW_LAYOUT_DVI_ONLY) { | ||
125 | /* If we have found external LVDS, just use it, | ||
126 | otherwise, we will use internal LVDS as default. */ | ||
127 | if (!viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) { | ||
128 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = | ||
129 | INTEGRATED_LVDS; | ||
130 | DEBUG_MSG(KERN_INFO "Found Integrated LVDS!\n"); | ||
131 | } | ||
132 | } else { | ||
133 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = | ||
134 | NON_LVDS_TRANSMITTER; | ||
135 | DEBUG_MSG(KERN_INFO "Do not support LVDS!\n"); | ||
136 | return false; | ||
137 | } | ||
138 | |||
139 | return true; | ||
140 | } | ||
141 | |||
142 | bool viafb_lvds_trasmitter_identify(void) | ||
143 | { | ||
144 | if (viafb_lvds_identify_vt1636(VIA_PORT_31)) { | ||
145 | viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_PORT_31; | ||
146 | DEBUG_MSG(KERN_INFO | ||
147 | "Found VIA VT1636 LVDS on port i2c 0x31\n"); | ||
148 | } else { | ||
149 | if (viafb_lvds_identify_vt1636(VIA_PORT_2C)) { | ||
150 | viaparinfo->chip_info->lvds_chip_info.i2c_port = | ||
151 | VIA_PORT_2C; | ||
152 | DEBUG_MSG(KERN_INFO | ||
153 | "Found VIA VT1636 LVDS on port gpio 0x2c\n"); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) | ||
158 | lvds_identify_integratedlvds(); | ||
159 | |||
160 | if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) | ||
161 | return true; | ||
162 | /* Check for VT1631: */ | ||
163 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = VT1631_LVDS; | ||
164 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr = | ||
165 | VT1631_LVDS_I2C_ADDR; | ||
166 | |||
167 | if (check_lvds_chip(VT1631_DEVICE_ID_REG, VT1631_DEVICE_ID)) { | ||
168 | DEBUG_MSG(KERN_INFO "\n VT1631 LVDS ! \n"); | ||
169 | DEBUG_MSG(KERN_INFO "\n %2d", | ||
170 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name); | ||
171 | DEBUG_MSG(KERN_INFO "\n %2d", | ||
172 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name); | ||
173 | return true; | ||
174 | } | ||
175 | |||
176 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = | ||
177 | NON_LVDS_TRANSMITTER; | ||
178 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr = | ||
179 | VT1631_LVDS_I2C_ADDR; | ||
180 | return false; | ||
181 | } | ||
182 | |||
183 | static void fp_id_to_vindex(int panel_id) | ||
184 | { | ||
185 | DEBUG_MSG(KERN_INFO "fp_get_panel_id()\n"); | ||
186 | |||
187 | if (panel_id > LCD_PANEL_ID_MAXIMUM) | ||
188 | viafb_lcd_panel_id = panel_id = | ||
189 | viafb_read_reg(VIACR, CR3F) & 0x0F; | ||
190 | |||
191 | switch (panel_id) { | ||
192 | case 0x0: | ||
193 | viaparinfo->lvds_setting_info->lcd_panel_hres = 640; | ||
194 | viaparinfo->lvds_setting_info->lcd_panel_vres = 480; | ||
195 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
196 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
197 | break; | ||
198 | case 0x1: | ||
199 | viaparinfo->lvds_setting_info->lcd_panel_hres = 800; | ||
200 | viaparinfo->lvds_setting_info->lcd_panel_vres = 600; | ||
201 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
202 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
203 | break; | ||
204 | case 0x2: | ||
205 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1024; | ||
206 | viaparinfo->lvds_setting_info->lcd_panel_vres = 768; | ||
207 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
208 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
209 | break; | ||
210 | case 0x3: | ||
211 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; | ||
212 | viaparinfo->lvds_setting_info->lcd_panel_vres = 768; | ||
213 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
214 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
215 | break; | ||
216 | case 0x4: | ||
217 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; | ||
218 | viaparinfo->lvds_setting_info->lcd_panel_vres = 1024; | ||
219 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; | ||
220 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
221 | break; | ||
222 | case 0x5: | ||
223 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1400; | ||
224 | viaparinfo->lvds_setting_info->lcd_panel_vres = 1050; | ||
225 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; | ||
226 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
227 | break; | ||
228 | case 0x6: | ||
229 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1600; | ||
230 | viaparinfo->lvds_setting_info->lcd_panel_vres = 1200; | ||
231 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; | ||
232 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
233 | break; | ||
234 | case 0x8: | ||
235 | viaparinfo->lvds_setting_info->lcd_panel_hres = 800; | ||
236 | viaparinfo->lvds_setting_info->lcd_panel_vres = 480; | ||
237 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
238 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
239 | break; | ||
240 | case 0x9: | ||
241 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1024; | ||
242 | viaparinfo->lvds_setting_info->lcd_panel_vres = 768; | ||
243 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; | ||
244 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
245 | break; | ||
246 | case 0xA: | ||
247 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1024; | ||
248 | viaparinfo->lvds_setting_info->lcd_panel_vres = 768; | ||
249 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
250 | viaparinfo->lvds_setting_info->LCDDithering = 0; | ||
251 | break; | ||
252 | case 0xB: | ||
253 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1024; | ||
254 | viaparinfo->lvds_setting_info->lcd_panel_vres = 768; | ||
255 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; | ||
256 | viaparinfo->lvds_setting_info->LCDDithering = 0; | ||
257 | break; | ||
258 | case 0xC: | ||
259 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; | ||
260 | viaparinfo->lvds_setting_info->lcd_panel_vres = 768; | ||
261 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
262 | viaparinfo->lvds_setting_info->LCDDithering = 0; | ||
263 | break; | ||
264 | case 0xD: | ||
265 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; | ||
266 | viaparinfo->lvds_setting_info->lcd_panel_vres = 1024; | ||
267 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; | ||
268 | viaparinfo->lvds_setting_info->LCDDithering = 0; | ||
269 | break; | ||
270 | case 0xE: | ||
271 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1400; | ||
272 | viaparinfo->lvds_setting_info->lcd_panel_vres = 1050; | ||
273 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; | ||
274 | viaparinfo->lvds_setting_info->LCDDithering = 0; | ||
275 | break; | ||
276 | case 0xF: | ||
277 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1600; | ||
278 | viaparinfo->lvds_setting_info->lcd_panel_vres = 1200; | ||
279 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; | ||
280 | viaparinfo->lvds_setting_info->LCDDithering = 0; | ||
281 | break; | ||
282 | case 0x10: | ||
283 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1366; | ||
284 | viaparinfo->lvds_setting_info->lcd_panel_vres = 768; | ||
285 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
286 | viaparinfo->lvds_setting_info->LCDDithering = 0; | ||
287 | break; | ||
288 | case 0x11: | ||
289 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1024; | ||
290 | viaparinfo->lvds_setting_info->lcd_panel_vres = 600; | ||
291 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
292 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
293 | break; | ||
294 | case 0x12: | ||
295 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; | ||
296 | viaparinfo->lvds_setting_info->lcd_panel_vres = 768; | ||
297 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; | ||
298 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
299 | break; | ||
300 | case 0x13: | ||
301 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; | ||
302 | viaparinfo->lvds_setting_info->lcd_panel_vres = 800; | ||
303 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
304 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
305 | break; | ||
306 | case 0x14: | ||
307 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1360; | ||
308 | viaparinfo->lvds_setting_info->lcd_panel_vres = 768; | ||
309 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
310 | viaparinfo->lvds_setting_info->LCDDithering = 0; | ||
311 | break; | ||
312 | case 0x15: | ||
313 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; | ||
314 | viaparinfo->lvds_setting_info->lcd_panel_vres = 768; | ||
315 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; | ||
316 | viaparinfo->lvds_setting_info->LCDDithering = 0; | ||
317 | break; | ||
318 | case 0x16: | ||
319 | viaparinfo->lvds_setting_info->lcd_panel_hres = 480; | ||
320 | viaparinfo->lvds_setting_info->lcd_panel_vres = 640; | ||
321 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
322 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
323 | break; | ||
324 | case 0x17: | ||
325 | /* OLPC XO-1.5 panel */ | ||
326 | viaparinfo->lvds_setting_info->lcd_panel_hres = 1200; | ||
327 | viaparinfo->lvds_setting_info->lcd_panel_vres = 900; | ||
328 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
329 | viaparinfo->lvds_setting_info->LCDDithering = 0; | ||
330 | break; | ||
331 | default: | ||
332 | viaparinfo->lvds_setting_info->lcd_panel_hres = 800; | ||
333 | viaparinfo->lvds_setting_info->lcd_panel_vres = 600; | ||
334 | viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; | ||
335 | viaparinfo->lvds_setting_info->LCDDithering = 1; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | static int lvds_register_read(int index) | ||
340 | { | ||
341 | u8 data; | ||
342 | |||
343 | viafb_i2c_readbyte(VIA_PORT_2C, | ||
344 | (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr, | ||
345 | (u8) index, &data); | ||
346 | return data; | ||
347 | } | ||
348 | |||
349 | static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, | ||
350 | int panel_vres) | ||
351 | { | ||
352 | int reg_value = 0; | ||
353 | int viafb_load_reg_num; | ||
354 | struct io_register *reg = NULL; | ||
355 | |||
356 | DEBUG_MSG(KERN_INFO "load_lcd_scaling()!!\n"); | ||
357 | |||
358 | /* LCD Scaling Enable */ | ||
359 | viafb_write_reg_mask(CR79, VIACR, 0x07, BIT0 + BIT1 + BIT2); | ||
360 | |||
361 | /* Check if expansion for horizontal */ | ||
362 | if (set_hres < panel_hres) { | ||
363 | /* Load Horizontal Scaling Factor */ | ||
364 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
365 | case UNICHROME_CLE266: | ||
366 | case UNICHROME_K400: | ||
367 | reg_value = | ||
368 | CLE266_LCD_HOR_SCF_FORMULA(set_hres, panel_hres); | ||
369 | viafb_load_reg_num = | ||
370 | lcd_scaling_factor_CLE.lcd_hor_scaling_factor. | ||
371 | reg_num; | ||
372 | reg = lcd_scaling_factor_CLE.lcd_hor_scaling_factor.reg; | ||
373 | viafb_load_reg(reg_value, | ||
374 | viafb_load_reg_num, reg, VIACR); | ||
375 | break; | ||
376 | case UNICHROME_K800: | ||
377 | case UNICHROME_PM800: | ||
378 | case UNICHROME_CN700: | ||
379 | case UNICHROME_CX700: | ||
380 | case UNICHROME_K8M890: | ||
381 | case UNICHROME_P4M890: | ||
382 | case UNICHROME_P4M900: | ||
383 | case UNICHROME_CN750: | ||
384 | case UNICHROME_VX800: | ||
385 | case UNICHROME_VX855: | ||
386 | case UNICHROME_VX900: | ||
387 | reg_value = | ||
388 | K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres); | ||
389 | /* Horizontal scaling enabled */ | ||
390 | viafb_write_reg_mask(CRA2, VIACR, 0xC0, BIT7 + BIT6); | ||
391 | viafb_load_reg_num = | ||
392 | lcd_scaling_factor.lcd_hor_scaling_factor.reg_num; | ||
393 | reg = lcd_scaling_factor.lcd_hor_scaling_factor.reg; | ||
394 | viafb_load_reg(reg_value, | ||
395 | viafb_load_reg_num, reg, VIACR); | ||
396 | break; | ||
397 | } | ||
398 | |||
399 | DEBUG_MSG(KERN_INFO "Horizontal Scaling value = %d", reg_value); | ||
400 | } else { | ||
401 | /* Horizontal scaling disabled */ | ||
402 | viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT7); | ||
403 | } | ||
404 | |||
405 | /* Check if expansion for vertical */ | ||
406 | if (set_vres < panel_vres) { | ||
407 | /* Load Vertical Scaling Factor */ | ||
408 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
409 | case UNICHROME_CLE266: | ||
410 | case UNICHROME_K400: | ||
411 | reg_value = | ||
412 | CLE266_LCD_VER_SCF_FORMULA(set_vres, panel_vres); | ||
413 | viafb_load_reg_num = | ||
414 | lcd_scaling_factor_CLE.lcd_ver_scaling_factor. | ||
415 | reg_num; | ||
416 | reg = lcd_scaling_factor_CLE.lcd_ver_scaling_factor.reg; | ||
417 | viafb_load_reg(reg_value, | ||
418 | viafb_load_reg_num, reg, VIACR); | ||
419 | break; | ||
420 | case UNICHROME_K800: | ||
421 | case UNICHROME_PM800: | ||
422 | case UNICHROME_CN700: | ||
423 | case UNICHROME_CX700: | ||
424 | case UNICHROME_K8M890: | ||
425 | case UNICHROME_P4M890: | ||
426 | case UNICHROME_P4M900: | ||
427 | case UNICHROME_CN750: | ||
428 | case UNICHROME_VX800: | ||
429 | case UNICHROME_VX855: | ||
430 | case UNICHROME_VX900: | ||
431 | reg_value = | ||
432 | K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres); | ||
433 | /* Vertical scaling enabled */ | ||
434 | viafb_write_reg_mask(CRA2, VIACR, 0x08, BIT3); | ||
435 | viafb_load_reg_num = | ||
436 | lcd_scaling_factor.lcd_ver_scaling_factor.reg_num; | ||
437 | reg = lcd_scaling_factor.lcd_ver_scaling_factor.reg; | ||
438 | viafb_load_reg(reg_value, | ||
439 | viafb_load_reg_num, reg, VIACR); | ||
440 | break; | ||
441 | } | ||
442 | |||
443 | DEBUG_MSG(KERN_INFO "Vertical Scaling value = %d", reg_value); | ||
444 | } else { | ||
445 | /* Vertical scaling disabled */ | ||
446 | viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT3); | ||
447 | } | ||
448 | } | ||
449 | |||
450 | static void via_pitch_alignment_patch_lcd(int iga_path, int hres, int bpp) | ||
451 | { | ||
452 | unsigned char cr13, cr35, cr65, cr66, cr67; | ||
453 | unsigned long dwScreenPitch = 0; | ||
454 | unsigned long dwPitch; | ||
455 | |||
456 | dwPitch = hres * (bpp >> 3); | ||
457 | if (dwPitch & 0x1F) { | ||
458 | dwScreenPitch = ((dwPitch + 31) & ~31) >> 3; | ||
459 | if (iga_path == IGA2) { | ||
460 | if (bpp > 8) { | ||
461 | cr66 = (unsigned char)(dwScreenPitch & 0xFF); | ||
462 | viafb_write_reg(CR66, VIACR, cr66); | ||
463 | cr67 = viafb_read_reg(VIACR, CR67) & 0xFC; | ||
464 | cr67 |= | ||
465 | (unsigned | ||
466 | char)((dwScreenPitch & 0x300) >> 8); | ||
467 | viafb_write_reg(CR67, VIACR, cr67); | ||
468 | } | ||
469 | |||
470 | /* Fetch Count */ | ||
471 | cr67 = viafb_read_reg(VIACR, CR67) & 0xF3; | ||
472 | cr67 |= (unsigned char)((dwScreenPitch & 0x600) >> 7); | ||
473 | viafb_write_reg(CR67, VIACR, cr67); | ||
474 | cr65 = (unsigned char)((dwScreenPitch >> 1) & 0xFF); | ||
475 | cr65 += 2; | ||
476 | viafb_write_reg(CR65, VIACR, cr65); | ||
477 | } else { | ||
478 | if (bpp > 8) { | ||
479 | cr13 = (unsigned char)(dwScreenPitch & 0xFF); | ||
480 | viafb_write_reg(CR13, VIACR, cr13); | ||
481 | cr35 = viafb_read_reg(VIACR, CR35) & 0x1F; | ||
482 | cr35 |= | ||
483 | (unsigned | ||
484 | char)((dwScreenPitch & 0x700) >> 3); | ||
485 | viafb_write_reg(CR35, VIACR, cr35); | ||
486 | } | ||
487 | } | ||
488 | } | ||
489 | } | ||
490 | static void lcd_patch_skew_dvp0(struct lvds_setting_information | ||
491 | *plvds_setting_info, | ||
492 | struct lvds_chip_information *plvds_chip_info) | ||
493 | { | ||
494 | if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) { | ||
495 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
496 | case UNICHROME_P4M900: | ||
497 | viafb_vt1636_patch_skew_on_vt3364(plvds_setting_info, | ||
498 | plvds_chip_info); | ||
499 | break; | ||
500 | case UNICHROME_P4M890: | ||
501 | viafb_vt1636_patch_skew_on_vt3327(plvds_setting_info, | ||
502 | plvds_chip_info); | ||
503 | break; | ||
504 | } | ||
505 | } | ||
506 | } | ||
507 | static void lcd_patch_skew_dvp1(struct lvds_setting_information | ||
508 | *plvds_setting_info, | ||
509 | struct lvds_chip_information *plvds_chip_info) | ||
510 | { | ||
511 | if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) { | ||
512 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
513 | case UNICHROME_CX700: | ||
514 | viafb_vt1636_patch_skew_on_vt3324(plvds_setting_info, | ||
515 | plvds_chip_info); | ||
516 | break; | ||
517 | } | ||
518 | } | ||
519 | } | ||
520 | static void lcd_patch_skew(struct lvds_setting_information | ||
521 | *plvds_setting_info, struct lvds_chip_information *plvds_chip_info) | ||
522 | { | ||
523 | DEBUG_MSG(KERN_INFO "lcd_patch_skew\n"); | ||
524 | switch (plvds_chip_info->output_interface) { | ||
525 | case INTERFACE_DVP0: | ||
526 | lcd_patch_skew_dvp0(plvds_setting_info, plvds_chip_info); | ||
527 | break; | ||
528 | case INTERFACE_DVP1: | ||
529 | lcd_patch_skew_dvp1(plvds_setting_info, plvds_chip_info); | ||
530 | break; | ||
531 | case INTERFACE_DFP_LOW: | ||
532 | if (UNICHROME_P4M900 == viaparinfo->chip_info->gfx_chip_name) { | ||
533 | viafb_write_reg_mask(CR99, VIACR, 0x08, | ||
534 | BIT0 + BIT1 + BIT2 + BIT3); | ||
535 | } | ||
536 | break; | ||
537 | } | ||
538 | } | ||
539 | |||
540 | /* LCD Set Mode */ | ||
541 | void viafb_lcd_set_mode(const struct fb_var_screeninfo *var, u16 cxres, | ||
542 | u16 cyres, struct lvds_setting_information *plvds_setting_info, | ||
543 | struct lvds_chip_information *plvds_chip_info) | ||
544 | { | ||
545 | int set_iga = plvds_setting_info->iga_path; | ||
546 | int mode_bpp = var->bits_per_pixel; | ||
547 | int set_hres = cxres ? cxres : var->xres; | ||
548 | int set_vres = cyres ? cyres : var->yres; | ||
549 | int panel_hres = plvds_setting_info->lcd_panel_hres; | ||
550 | int panel_vres = plvds_setting_info->lcd_panel_vres; | ||
551 | u32 clock; | ||
552 | struct via_display_timing timing; | ||
553 | struct fb_var_screeninfo panel_var; | ||
554 | const struct fb_videomode *mode_crt_table, *panel_crt_table; | ||
555 | |||
556 | DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n"); | ||
557 | /* Get mode table */ | ||
558 | mode_crt_table = viafb_get_best_mode(set_hres, set_vres, 60); | ||
559 | /* Get panel table Pointer */ | ||
560 | panel_crt_table = viafb_get_best_mode(panel_hres, panel_vres, 60); | ||
561 | viafb_fill_var_timing_info(&panel_var, panel_crt_table); | ||
562 | DEBUG_MSG(KERN_INFO "bellow viafb_lcd_set_mode!!\n"); | ||
563 | if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) | ||
564 | viafb_init_lvds_vt1636(plvds_setting_info, plvds_chip_info); | ||
565 | clock = PICOS2KHZ(panel_crt_table->pixclock) * 1000; | ||
566 | plvds_setting_info->vclk = clock; | ||
567 | |||
568 | if (set_iga == IGA2 && (set_hres < panel_hres || set_vres < panel_vres) | ||
569 | && plvds_setting_info->display_method == LCD_EXPANDSION) { | ||
570 | timing = var_to_timing(&panel_var, panel_hres, panel_vres); | ||
571 | load_lcd_scaling(set_hres, set_vres, panel_hres, panel_vres); | ||
572 | } else { | ||
573 | timing = var_to_timing(&panel_var, set_hres, set_vres); | ||
574 | if (set_iga == IGA2) | ||
575 | /* disable scaling */ | ||
576 | via_write_reg_mask(VIACR, 0x79, 0x00, | ||
577 | BIT0 + BIT1 + BIT2); | ||
578 | } | ||
579 | |||
580 | if (set_iga == IGA1) | ||
581 | via_set_primary_timing(&timing); | ||
582 | else if (set_iga == IGA2) | ||
583 | via_set_secondary_timing(&timing); | ||
584 | |||
585 | /* Fetch count for IGA2 only */ | ||
586 | viafb_load_fetch_count_reg(set_hres, mode_bpp / 8, set_iga); | ||
587 | |||
588 | if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266) | ||
589 | && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400)) | ||
590 | viafb_load_FIFO_reg(set_iga, set_hres, set_vres); | ||
591 | |||
592 | fill_lcd_format(); | ||
593 | viafb_set_vclock(clock, set_iga); | ||
594 | lcd_patch_skew(plvds_setting_info, plvds_chip_info); | ||
595 | |||
596 | /* If K8M800, enable LCD Prefetch Mode. */ | ||
597 | if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) | ||
598 | || (UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name)) | ||
599 | viafb_write_reg_mask(CR6A, VIACR, 0x01, BIT0); | ||
600 | |||
601 | /* Patch for non 32bit alignment mode */ | ||
602 | via_pitch_alignment_patch_lcd(plvds_setting_info->iga_path, set_hres, | ||
603 | var->bits_per_pixel); | ||
604 | } | ||
605 | |||
606 | static void integrated_lvds_disable(struct lvds_setting_information | ||
607 | *plvds_setting_info, | ||
608 | struct lvds_chip_information *plvds_chip_info) | ||
609 | { | ||
610 | bool turn_off_first_powersequence = false; | ||
611 | bool turn_off_second_powersequence = false; | ||
612 | if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface) | ||
613 | turn_off_first_powersequence = true; | ||
614 | if (INTERFACE_LVDS0 == plvds_chip_info->output_interface) | ||
615 | turn_off_first_powersequence = true; | ||
616 | if (INTERFACE_LVDS1 == plvds_chip_info->output_interface) | ||
617 | turn_off_second_powersequence = true; | ||
618 | if (turn_off_second_powersequence) { | ||
619 | /* Use second power sequence control: */ | ||
620 | |||
621 | /* Turn off power sequence. */ | ||
622 | viafb_write_reg_mask(CRD4, VIACR, 0, BIT1); | ||
623 | |||
624 | /* Turn off back light. */ | ||
625 | viafb_write_reg_mask(CRD3, VIACR, 0xC0, BIT6 + BIT7); | ||
626 | } | ||
627 | if (turn_off_first_powersequence) { | ||
628 | /* Use first power sequence control: */ | ||
629 | |||
630 | /* Turn off power sequence. */ | ||
631 | viafb_write_reg_mask(CR6A, VIACR, 0, BIT3); | ||
632 | |||
633 | /* Turn off back light. */ | ||
634 | viafb_write_reg_mask(CR91, VIACR, 0xC0, BIT6 + BIT7); | ||
635 | } | ||
636 | |||
637 | /* Power off LVDS channel. */ | ||
638 | switch (plvds_chip_info->output_interface) { | ||
639 | case INTERFACE_LVDS0: | ||
640 | { | ||
641 | viafb_write_reg_mask(CRD2, VIACR, 0x80, BIT7); | ||
642 | break; | ||
643 | } | ||
644 | |||
645 | case INTERFACE_LVDS1: | ||
646 | { | ||
647 | viafb_write_reg_mask(CRD2, VIACR, 0x40, BIT6); | ||
648 | break; | ||
649 | } | ||
650 | |||
651 | case INTERFACE_LVDS0LVDS1: | ||
652 | { | ||
653 | viafb_write_reg_mask(CRD2, VIACR, 0xC0, BIT6 + BIT7); | ||
654 | break; | ||
655 | } | ||
656 | } | ||
657 | } | ||
658 | |||
659 | static void integrated_lvds_enable(struct lvds_setting_information | ||
660 | *plvds_setting_info, | ||
661 | struct lvds_chip_information *plvds_chip_info) | ||
662 | { | ||
663 | DEBUG_MSG(KERN_INFO "integrated_lvds_enable, out_interface:%d\n", | ||
664 | plvds_chip_info->output_interface); | ||
665 | if (plvds_setting_info->lcd_mode == LCD_SPWG) | ||
666 | viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT0 + BIT1); | ||
667 | else | ||
668 | viafb_write_reg_mask(CRD2, VIACR, 0x03, BIT0 + BIT1); | ||
669 | |||
670 | switch (plvds_chip_info->output_interface) { | ||
671 | case INTERFACE_LVDS0LVDS1: | ||
672 | case INTERFACE_LVDS0: | ||
673 | /* Use first power sequence control: */ | ||
674 | /* Use hardware control power sequence. */ | ||
675 | viafb_write_reg_mask(CR91, VIACR, 0, BIT0); | ||
676 | /* Turn on back light. */ | ||
677 | viafb_write_reg_mask(CR91, VIACR, 0, BIT6 + BIT7); | ||
678 | /* Turn on hardware power sequence. */ | ||
679 | viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); | ||
680 | break; | ||
681 | case INTERFACE_LVDS1: | ||
682 | /* Use second power sequence control: */ | ||
683 | /* Use hardware control power sequence. */ | ||
684 | viafb_write_reg_mask(CRD3, VIACR, 0, BIT0); | ||
685 | /* Turn on back light. */ | ||
686 | viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7); | ||
687 | /* Turn on hardware power sequence. */ | ||
688 | viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1); | ||
689 | break; | ||
690 | } | ||
691 | |||
692 | /* Power on LVDS channel. */ | ||
693 | switch (plvds_chip_info->output_interface) { | ||
694 | case INTERFACE_LVDS0: | ||
695 | { | ||
696 | viafb_write_reg_mask(CRD2, VIACR, 0, BIT7); | ||
697 | break; | ||
698 | } | ||
699 | |||
700 | case INTERFACE_LVDS1: | ||
701 | { | ||
702 | viafb_write_reg_mask(CRD2, VIACR, 0, BIT6); | ||
703 | break; | ||
704 | } | ||
705 | |||
706 | case INTERFACE_LVDS0LVDS1: | ||
707 | { | ||
708 | viafb_write_reg_mask(CRD2, VIACR, 0, BIT6 + BIT7); | ||
709 | break; | ||
710 | } | ||
711 | } | ||
712 | } | ||
713 | |||
714 | void viafb_lcd_disable(void) | ||
715 | { | ||
716 | |||
717 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { | ||
718 | lcd_powersequence_off(); | ||
719 | /* DI1 pad off */ | ||
720 | viafb_write_reg_mask(SR1E, VIASR, 0x00, 0x30); | ||
721 | } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) { | ||
722 | if (viafb_LCD2_ON | ||
723 | && (INTEGRATED_LVDS == | ||
724 | viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name)) | ||
725 | integrated_lvds_disable(viaparinfo->lvds_setting_info, | ||
726 | &viaparinfo->chip_info->lvds_chip_info2); | ||
727 | if (INTEGRATED_LVDS == | ||
728 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) | ||
729 | integrated_lvds_disable(viaparinfo->lvds_setting_info, | ||
730 | &viaparinfo->chip_info->lvds_chip_info); | ||
731 | if (VT1636_LVDS == viaparinfo->chip_info-> | ||
732 | lvds_chip_info.lvds_chip_name) | ||
733 | viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info, | ||
734 | &viaparinfo->chip_info->lvds_chip_info); | ||
735 | } else if (VT1636_LVDS == | ||
736 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) { | ||
737 | viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info, | ||
738 | &viaparinfo->chip_info->lvds_chip_info); | ||
739 | } else { | ||
740 | /* Backlight off */ | ||
741 | viafb_write_reg_mask(SR3D, VIASR, 0x00, 0x20); | ||
742 | /* 24 bit DI data paht off */ | ||
743 | viafb_write_reg_mask(CR91, VIACR, 0x80, 0x80); | ||
744 | } | ||
745 | |||
746 | /* Disable expansion bit */ | ||
747 | viafb_write_reg_mask(CR79, VIACR, 0x00, 0x01); | ||
748 | /* Simultaneout disabled */ | ||
749 | viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08); | ||
750 | } | ||
751 | |||
752 | static void set_lcd_output_path(int set_iga, int output_interface) | ||
753 | { | ||
754 | switch (output_interface) { | ||
755 | case INTERFACE_DFP: | ||
756 | if ((UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name) | ||
757 | || (UNICHROME_P4M890 == | ||
758 | viaparinfo->chip_info->gfx_chip_name)) | ||
759 | viafb_write_reg_mask(CR97, VIACR, 0x84, | ||
760 | BIT7 + BIT2 + BIT1 + BIT0); | ||
761 | case INTERFACE_DVP0: | ||
762 | case INTERFACE_DVP1: | ||
763 | case INTERFACE_DFP_HIGH: | ||
764 | case INTERFACE_DFP_LOW: | ||
765 | if (set_iga == IGA2) | ||
766 | viafb_write_reg(CR91, VIACR, 0x00); | ||
767 | break; | ||
768 | } | ||
769 | } | ||
770 | |||
771 | void viafb_lcd_enable(void) | ||
772 | { | ||
773 | viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3); | ||
774 | viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); | ||
775 | set_lcd_output_path(viaparinfo->lvds_setting_info->iga_path, | ||
776 | viaparinfo->chip_info->lvds_chip_info.output_interface); | ||
777 | if (viafb_LCD2_ON) | ||
778 | set_lcd_output_path(viaparinfo->lvds_setting_info2->iga_path, | ||
779 | viaparinfo->chip_info-> | ||
780 | lvds_chip_info2.output_interface); | ||
781 | |||
782 | if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { | ||
783 | /* DI1 pad on */ | ||
784 | viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30); | ||
785 | lcd_powersequence_on(); | ||
786 | } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) { | ||
787 | if (viafb_LCD2_ON && (INTEGRATED_LVDS == | ||
788 | viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name)) | ||
789 | integrated_lvds_enable(viaparinfo->lvds_setting_info2, \ | ||
790 | &viaparinfo->chip_info->lvds_chip_info2); | ||
791 | if (INTEGRATED_LVDS == | ||
792 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) | ||
793 | integrated_lvds_enable(viaparinfo->lvds_setting_info, | ||
794 | &viaparinfo->chip_info->lvds_chip_info); | ||
795 | if (VT1636_LVDS == viaparinfo->chip_info-> | ||
796 | lvds_chip_info.lvds_chip_name) | ||
797 | viafb_enable_lvds_vt1636(viaparinfo-> | ||
798 | lvds_setting_info, &viaparinfo->chip_info-> | ||
799 | lvds_chip_info); | ||
800 | } else if (VT1636_LVDS == | ||
801 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) { | ||
802 | viafb_enable_lvds_vt1636(viaparinfo->lvds_setting_info, | ||
803 | &viaparinfo->chip_info->lvds_chip_info); | ||
804 | } else { | ||
805 | /* Backlight on */ | ||
806 | viafb_write_reg_mask(SR3D, VIASR, 0x20, 0x20); | ||
807 | /* 24 bit DI data paht on */ | ||
808 | viafb_write_reg_mask(CR91, VIACR, 0x00, 0x80); | ||
809 | /* LCD enabled */ | ||
810 | viafb_write_reg_mask(CR6A, VIACR, 0x48, 0x48); | ||
811 | } | ||
812 | } | ||
813 | |||
814 | static void lcd_powersequence_off(void) | ||
815 | { | ||
816 | int i, mask, data; | ||
817 | |||
818 | /* Software control power sequence */ | ||
819 | viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11); | ||
820 | |||
821 | for (i = 0; i < 3; i++) { | ||
822 | mask = PowerSequenceOff[0][i]; | ||
823 | data = PowerSequenceOff[1][i] & mask; | ||
824 | viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask); | ||
825 | udelay(PowerSequenceOff[2][i]); | ||
826 | } | ||
827 | |||
828 | /* Disable LCD */ | ||
829 | viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x08); | ||
830 | } | ||
831 | |||
832 | static void lcd_powersequence_on(void) | ||
833 | { | ||
834 | int i, mask, data; | ||
835 | |||
836 | /* Software control power sequence */ | ||
837 | viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11); | ||
838 | |||
839 | /* Enable LCD */ | ||
840 | viafb_write_reg_mask(CR6A, VIACR, 0x08, 0x08); | ||
841 | |||
842 | for (i = 0; i < 3; i++) { | ||
843 | mask = PowerSequenceOn[0][i]; | ||
844 | data = PowerSequenceOn[1][i] & mask; | ||
845 | viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask); | ||
846 | udelay(PowerSequenceOn[2][i]); | ||
847 | } | ||
848 | |||
849 | udelay(1); | ||
850 | } | ||
851 | |||
852 | static void fill_lcd_format(void) | ||
853 | { | ||
854 | u8 bdithering = 0, bdual = 0; | ||
855 | |||
856 | if (viaparinfo->lvds_setting_info->device_lcd_dualedge) | ||
857 | bdual = BIT4; | ||
858 | if (viaparinfo->lvds_setting_info->LCDDithering) | ||
859 | bdithering = BIT0; | ||
860 | /* Dual & Dithering */ | ||
861 | viafb_write_reg_mask(CR88, VIACR, (bdithering | bdual), BIT4 + BIT0); | ||
862 | } | ||
863 | |||
864 | static void check_diport_of_integrated_lvds( | ||
865 | struct lvds_chip_information *plvds_chip_info, | ||
866 | struct lvds_setting_information | ||
867 | *plvds_setting_info) | ||
868 | { | ||
869 | /* Determine LCD DI Port by hardware layout. */ | ||
870 | switch (viafb_display_hardware_layout) { | ||
871 | case HW_LAYOUT_LCD_ONLY: | ||
872 | { | ||
873 | if (plvds_setting_info->device_lcd_dualedge) { | ||
874 | plvds_chip_info->output_interface = | ||
875 | INTERFACE_LVDS0LVDS1; | ||
876 | } else { | ||
877 | plvds_chip_info->output_interface = | ||
878 | INTERFACE_LVDS0; | ||
879 | } | ||
880 | |||
881 | break; | ||
882 | } | ||
883 | |||
884 | case HW_LAYOUT_DVI_ONLY: | ||
885 | { | ||
886 | plvds_chip_info->output_interface = INTERFACE_NONE; | ||
887 | break; | ||
888 | } | ||
889 | |||
890 | case HW_LAYOUT_LCD1_LCD2: | ||
891 | case HW_LAYOUT_LCD_EXTERNAL_LCD2: | ||
892 | { | ||
893 | plvds_chip_info->output_interface = | ||
894 | INTERFACE_LVDS0LVDS1; | ||
895 | break; | ||
896 | } | ||
897 | |||
898 | case HW_LAYOUT_LCD_DVI: | ||
899 | { | ||
900 | plvds_chip_info->output_interface = INTERFACE_LVDS1; | ||
901 | break; | ||
902 | } | ||
903 | |||
904 | default: | ||
905 | { | ||
906 | plvds_chip_info->output_interface = INTERFACE_LVDS1; | ||
907 | break; | ||
908 | } | ||
909 | } | ||
910 | |||
911 | DEBUG_MSG(KERN_INFO | ||
912 | "Display Hardware Layout: 0x%x, LCD DI Port: 0x%x\n", | ||
913 | viafb_display_hardware_layout, | ||
914 | plvds_chip_info->output_interface); | ||
915 | } | ||
916 | |||
917 | void viafb_init_lvds_output_interface(struct lvds_chip_information | ||
918 | *plvds_chip_info, | ||
919 | struct lvds_setting_information | ||
920 | *plvds_setting_info) | ||
921 | { | ||
922 | if (INTERFACE_NONE != plvds_chip_info->output_interface) { | ||
923 | /*Do nothing, lcd port is specified by module parameter */ | ||
924 | return; | ||
925 | } | ||
926 | |||
927 | switch (plvds_chip_info->lvds_chip_name) { | ||
928 | |||
929 | case VT1636_LVDS: | ||
930 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
931 | case UNICHROME_CX700: | ||
932 | plvds_chip_info->output_interface = INTERFACE_DVP1; | ||
933 | break; | ||
934 | case UNICHROME_CN700: | ||
935 | plvds_chip_info->output_interface = INTERFACE_DFP_LOW; | ||
936 | break; | ||
937 | default: | ||
938 | plvds_chip_info->output_interface = INTERFACE_DVP0; | ||
939 | break; | ||
940 | } | ||
941 | break; | ||
942 | |||
943 | case INTEGRATED_LVDS: | ||
944 | check_diport_of_integrated_lvds(plvds_chip_info, | ||
945 | plvds_setting_info); | ||
946 | break; | ||
947 | |||
948 | default: | ||
949 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
950 | case UNICHROME_K8M890: | ||
951 | case UNICHROME_P4M900: | ||
952 | case UNICHROME_P4M890: | ||
953 | plvds_chip_info->output_interface = INTERFACE_DFP_LOW; | ||
954 | break; | ||
955 | default: | ||
956 | plvds_chip_info->output_interface = INTERFACE_DFP; | ||
957 | break; | ||
958 | } | ||
959 | break; | ||
960 | } | ||
961 | } | ||
962 | |||
963 | bool viafb_lcd_get_mobile_state(bool *mobile) | ||
964 | { | ||
965 | unsigned char __iomem *romptr, *tableptr, *biosptr; | ||
966 | u8 core_base; | ||
967 | /* Rom address */ | ||
968 | const u32 romaddr = 0x000C0000; | ||
969 | u16 start_pattern; | ||
970 | |||
971 | biosptr = ioremap(romaddr, 0x10000); | ||
972 | start_pattern = readw(biosptr); | ||
973 | |||
974 | /* Compare pattern */ | ||
975 | if (start_pattern == 0xAA55) { | ||
976 | /* Get the start of Table */ | ||
977 | /* 0x1B means BIOS offset position */ | ||
978 | romptr = biosptr + 0x1B; | ||
979 | tableptr = biosptr + readw(romptr); | ||
980 | |||
981 | /* Get the start of biosver structure */ | ||
982 | /* 18 means BIOS version position. */ | ||
983 | romptr = tableptr + 18; | ||
984 | romptr = biosptr + readw(romptr); | ||
985 | |||
986 | /* The offset should be 44, but the | ||
987 | actual image is less three char. */ | ||
988 | /* pRom += 44; */ | ||
989 | romptr += 41; | ||
990 | |||
991 | core_base = readb(romptr); | ||
992 | |||
993 | if (core_base & 0x8) | ||
994 | *mobile = false; | ||
995 | else | ||
996 | *mobile = true; | ||
997 | /* release memory */ | ||
998 | iounmap(biosptr); | ||
999 | |||
1000 | return true; | ||
1001 | } else { | ||
1002 | iounmap(biosptr); | ||
1003 | return false; | ||
1004 | } | ||
1005 | } | ||
diff --git a/drivers/video/fbdev/via/lcd.h b/drivers/video/fbdev/via/lcd.h new file mode 100644 index 000000000000..5c988a063ad5 --- /dev/null +++ b/drivers/video/fbdev/via/lcd.h | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #ifndef __LCD_H__ | ||
22 | #define __LCD_H__ | ||
23 | |||
24 | /*Definition TMDS Device ID register*/ | ||
25 | #define VT1631_DEVICE_ID_REG 0x02 | ||
26 | #define VT1631_DEVICE_ID 0x92 | ||
27 | |||
28 | #define VT3271_DEVICE_ID_REG 0x02 | ||
29 | #define VT3271_DEVICE_ID 0x71 | ||
30 | |||
31 | /* Definition DVI Panel ID*/ | ||
32 | /* Resolution: 640x480, Channel: single, Dithering: Enable */ | ||
33 | #define LCD_PANEL_ID0_640X480 0x00 | ||
34 | /* Resolution: 800x600, Channel: single, Dithering: Enable */ | ||
35 | #define LCD_PANEL_ID1_800X600 0x01 | ||
36 | /* Resolution: 1024x768, Channel: single, Dithering: Enable */ | ||
37 | #define LCD_PANEL_ID2_1024X768 0x02 | ||
38 | /* Resolution: 1280x768, Channel: single, Dithering: Enable */ | ||
39 | #define LCD_PANEL_ID3_1280X768 0x03 | ||
40 | /* Resolution: 1280x1024, Channel: dual, Dithering: Enable */ | ||
41 | #define LCD_PANEL_ID4_1280X1024 0x04 | ||
42 | /* Resolution: 1400x1050, Channel: dual, Dithering: Enable */ | ||
43 | #define LCD_PANEL_ID5_1400X1050 0x05 | ||
44 | /* Resolution: 1600x1200, Channel: dual, Dithering: Enable */ | ||
45 | #define LCD_PANEL_ID6_1600X1200 0x06 | ||
46 | /* Resolution: 1366x768, Channel: single, Dithering: Disable */ | ||
47 | #define LCD_PANEL_ID7_1366X768 0x07 | ||
48 | /* Resolution: 1024x600, Channel: single, Dithering: Enable*/ | ||
49 | #define LCD_PANEL_ID8_1024X600 0x08 | ||
50 | /* Resolution: 1280x800, Channel: single, Dithering: Enable*/ | ||
51 | #define LCD_PANEL_ID9_1280X800 0x09 | ||
52 | /* Resolution: 800x480, Channel: single, Dithering: Enable*/ | ||
53 | #define LCD_PANEL_IDA_800X480 0x0A | ||
54 | /* Resolution: 1360x768, Channel: single, Dithering: Disable*/ | ||
55 | #define LCD_PANEL_IDB_1360X768 0x0B | ||
56 | /* Resolution: 480x640, Channel: single, Dithering: Enable */ | ||
57 | #define LCD_PANEL_IDC_480X640 0x0C | ||
58 | /* Resolution: 1200x900, Channel: single, Dithering: Disable */ | ||
59 | #define LCD_PANEL_IDD_1200X900 0x0D | ||
60 | |||
61 | |||
62 | extern int viafb_LCD2_ON; | ||
63 | extern int viafb_LCD_ON; | ||
64 | extern int viafb_DVI_ON; | ||
65 | |||
66 | void viafb_disable_lvds_vt1636(struct lvds_setting_information | ||
67 | *plvds_setting_info, | ||
68 | struct lvds_chip_information *plvds_chip_info); | ||
69 | void viafb_enable_lvds_vt1636(struct lvds_setting_information | ||
70 | *plvds_setting_info, | ||
71 | struct lvds_chip_information *plvds_chip_info); | ||
72 | void viafb_lcd_disable(void); | ||
73 | void viafb_lcd_enable(void); | ||
74 | void viafb_init_lcd_size(void); | ||
75 | void viafb_init_lvds_output_interface(struct lvds_chip_information | ||
76 | *plvds_chip_info, | ||
77 | struct lvds_setting_information | ||
78 | *plvds_setting_info); | ||
79 | void viafb_lcd_set_mode(const struct fb_var_screeninfo *var, u16 cxres, | ||
80 | u16 cyres, struct lvds_setting_information *plvds_setting_info, | ||
81 | struct lvds_chip_information *plvds_chip_info); | ||
82 | bool viafb_lvds_trasmitter_identify(void); | ||
83 | void viafb_init_lvds_output_interface(struct lvds_chip_information | ||
84 | *plvds_chip_info, | ||
85 | struct lvds_setting_information | ||
86 | *plvds_setting_info); | ||
87 | bool viafb_lcd_get_mobile_state(bool *mobile); | ||
88 | |||
89 | #endif /* __LCD_H__ */ | ||
diff --git a/drivers/video/fbdev/via/share.h b/drivers/video/fbdev/via/share.h new file mode 100644 index 000000000000..65c65c611e0a --- /dev/null +++ b/drivers/video/fbdev/via/share.h | |||
@@ -0,0 +1,332 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef __SHARE_H__ | ||
23 | #define __SHARE_H__ | ||
24 | |||
25 | #include "via_modesetting.h" | ||
26 | |||
27 | /* Define Bit Field */ | ||
28 | #define BIT0 0x01 | ||
29 | #define BIT1 0x02 | ||
30 | #define BIT2 0x04 | ||
31 | #define BIT3 0x08 | ||
32 | #define BIT4 0x10 | ||
33 | #define BIT5 0x20 | ||
34 | #define BIT6 0x40 | ||
35 | #define BIT7 0x80 | ||
36 | |||
37 | /* Video Memory Size */ | ||
38 | #define VIDEO_MEMORY_SIZE_16M 0x1000000 | ||
39 | |||
40 | /* | ||
41 | * Lengths of the VPIT structure arrays. | ||
42 | */ | ||
43 | #define StdCR 0x19 | ||
44 | #define StdSR 0x04 | ||
45 | #define StdGR 0x09 | ||
46 | #define StdAR 0x14 | ||
47 | |||
48 | #define PatchCR 11 | ||
49 | |||
50 | /* Display path */ | ||
51 | #define IGA1 1 | ||
52 | #define IGA2 2 | ||
53 | |||
54 | /* Define Color Depth */ | ||
55 | #define MODE_8BPP 1 | ||
56 | #define MODE_16BPP 2 | ||
57 | #define MODE_32BPP 4 | ||
58 | |||
59 | #define GR20 0x20 | ||
60 | #define GR21 0x21 | ||
61 | #define GR22 0x22 | ||
62 | |||
63 | /* Sequencer Registers */ | ||
64 | #define SR01 0x01 | ||
65 | #define SR10 0x10 | ||
66 | #define SR12 0x12 | ||
67 | #define SR15 0x15 | ||
68 | #define SR16 0x16 | ||
69 | #define SR17 0x17 | ||
70 | #define SR18 0x18 | ||
71 | #define SR1B 0x1B | ||
72 | #define SR1A 0x1A | ||
73 | #define SR1C 0x1C | ||
74 | #define SR1D 0x1D | ||
75 | #define SR1E 0x1E | ||
76 | #define SR1F 0x1F | ||
77 | #define SR20 0x20 | ||
78 | #define SR21 0x21 | ||
79 | #define SR22 0x22 | ||
80 | #define SR2A 0x2A | ||
81 | #define SR2D 0x2D | ||
82 | #define SR2E 0x2E | ||
83 | |||
84 | #define SR30 0x30 | ||
85 | #define SR39 0x39 | ||
86 | #define SR3D 0x3D | ||
87 | #define SR3E 0x3E | ||
88 | #define SR3F 0x3F | ||
89 | #define SR40 0x40 | ||
90 | #define SR43 0x43 | ||
91 | #define SR44 0x44 | ||
92 | #define SR45 0x45 | ||
93 | #define SR46 0x46 | ||
94 | #define SR47 0x47 | ||
95 | #define SR48 0x48 | ||
96 | #define SR49 0x49 | ||
97 | #define SR4A 0x4A | ||
98 | #define SR4B 0x4B | ||
99 | #define SR4C 0x4C | ||
100 | #define SR52 0x52 | ||
101 | #define SR57 0x57 | ||
102 | #define SR58 0x58 | ||
103 | #define SR59 0x59 | ||
104 | #define SR5D 0x5D | ||
105 | #define SR5E 0x5E | ||
106 | #define SR65 0x65 | ||
107 | |||
108 | /* CRT Controller Registers */ | ||
109 | #define CR00 0x00 | ||
110 | #define CR01 0x01 | ||
111 | #define CR02 0x02 | ||
112 | #define CR03 0x03 | ||
113 | #define CR04 0x04 | ||
114 | #define CR05 0x05 | ||
115 | #define CR06 0x06 | ||
116 | #define CR07 0x07 | ||
117 | #define CR08 0x08 | ||
118 | #define CR09 0x09 | ||
119 | #define CR0A 0x0A | ||
120 | #define CR0B 0x0B | ||
121 | #define CR0C 0x0C | ||
122 | #define CR0D 0x0D | ||
123 | #define CR0E 0x0E | ||
124 | #define CR0F 0x0F | ||
125 | #define CR10 0x10 | ||
126 | #define CR11 0x11 | ||
127 | #define CR12 0x12 | ||
128 | #define CR13 0x13 | ||
129 | #define CR14 0x14 | ||
130 | #define CR15 0x15 | ||
131 | #define CR16 0x16 | ||
132 | #define CR17 0x17 | ||
133 | #define CR18 0x18 | ||
134 | |||
135 | /* Extend CRT Controller Registers */ | ||
136 | #define CR30 0x30 | ||
137 | #define CR31 0x31 | ||
138 | #define CR32 0x32 | ||
139 | #define CR33 0x33 | ||
140 | #define CR34 0x34 | ||
141 | #define CR35 0x35 | ||
142 | #define CR36 0x36 | ||
143 | #define CR37 0x37 | ||
144 | #define CR38 0x38 | ||
145 | #define CR39 0x39 | ||
146 | #define CR3A 0x3A | ||
147 | #define CR3B 0x3B | ||
148 | #define CR3C 0x3C | ||
149 | #define CR3D 0x3D | ||
150 | #define CR3E 0x3E | ||
151 | #define CR3F 0x3F | ||
152 | #define CR40 0x40 | ||
153 | #define CR41 0x41 | ||
154 | #define CR42 0x42 | ||
155 | #define CR43 0x43 | ||
156 | #define CR44 0x44 | ||
157 | #define CR45 0x45 | ||
158 | #define CR46 0x46 | ||
159 | #define CR47 0x47 | ||
160 | #define CR48 0x48 | ||
161 | #define CR49 0x49 | ||
162 | #define CR4A 0x4A | ||
163 | #define CR4B 0x4B | ||
164 | #define CR4C 0x4C | ||
165 | #define CR4D 0x4D | ||
166 | #define CR4E 0x4E | ||
167 | #define CR4F 0x4F | ||
168 | #define CR50 0x50 | ||
169 | #define CR51 0x51 | ||
170 | #define CR52 0x52 | ||
171 | #define CR53 0x53 | ||
172 | #define CR54 0x54 | ||
173 | #define CR55 0x55 | ||
174 | #define CR56 0x56 | ||
175 | #define CR57 0x57 | ||
176 | #define CR58 0x58 | ||
177 | #define CR59 0x59 | ||
178 | #define CR5A 0x5A | ||
179 | #define CR5B 0x5B | ||
180 | #define CR5C 0x5C | ||
181 | #define CR5D 0x5D | ||
182 | #define CR5E 0x5E | ||
183 | #define CR5F 0x5F | ||
184 | #define CR60 0x60 | ||
185 | #define CR61 0x61 | ||
186 | #define CR62 0x62 | ||
187 | #define CR63 0x63 | ||
188 | #define CR64 0x64 | ||
189 | #define CR65 0x65 | ||
190 | #define CR66 0x66 | ||
191 | #define CR67 0x67 | ||
192 | #define CR68 0x68 | ||
193 | #define CR69 0x69 | ||
194 | #define CR6A 0x6A | ||
195 | #define CR6B 0x6B | ||
196 | #define CR6C 0x6C | ||
197 | #define CR6D 0x6D | ||
198 | #define CR6E 0x6E | ||
199 | #define CR6F 0x6F | ||
200 | #define CR70 0x70 | ||
201 | #define CR71 0x71 | ||
202 | #define CR72 0x72 | ||
203 | #define CR73 0x73 | ||
204 | #define CR74 0x74 | ||
205 | #define CR75 0x75 | ||
206 | #define CR76 0x76 | ||
207 | #define CR77 0x77 | ||
208 | #define CR78 0x78 | ||
209 | #define CR79 0x79 | ||
210 | #define CR7A 0x7A | ||
211 | #define CR7B 0x7B | ||
212 | #define CR7C 0x7C | ||
213 | #define CR7D 0x7D | ||
214 | #define CR7E 0x7E | ||
215 | #define CR7F 0x7F | ||
216 | #define CR80 0x80 | ||
217 | #define CR81 0x81 | ||
218 | #define CR82 0x82 | ||
219 | #define CR83 0x83 | ||
220 | #define CR84 0x84 | ||
221 | #define CR85 0x85 | ||
222 | #define CR86 0x86 | ||
223 | #define CR87 0x87 | ||
224 | #define CR88 0x88 | ||
225 | #define CR89 0x89 | ||
226 | #define CR8A 0x8A | ||
227 | #define CR8B 0x8B | ||
228 | #define CR8C 0x8C | ||
229 | #define CR8D 0x8D | ||
230 | #define CR8E 0x8E | ||
231 | #define CR8F 0x8F | ||
232 | #define CR90 0x90 | ||
233 | #define CR91 0x91 | ||
234 | #define CR92 0x92 | ||
235 | #define CR93 0x93 | ||
236 | #define CR94 0x94 | ||
237 | #define CR95 0x95 | ||
238 | #define CR96 0x96 | ||
239 | #define CR97 0x97 | ||
240 | #define CR98 0x98 | ||
241 | #define CR99 0x99 | ||
242 | #define CR9A 0x9A | ||
243 | #define CR9B 0x9B | ||
244 | #define CR9C 0x9C | ||
245 | #define CR9D 0x9D | ||
246 | #define CR9E 0x9E | ||
247 | #define CR9F 0x9F | ||
248 | #define CRA0 0xA0 | ||
249 | #define CRA1 0xA1 | ||
250 | #define CRA2 0xA2 | ||
251 | #define CRA3 0xA3 | ||
252 | #define CRD2 0xD2 | ||
253 | #define CRD3 0xD3 | ||
254 | #define CRD4 0xD4 | ||
255 | |||
256 | /* LUT Table*/ | ||
257 | #define LUT_DATA 0x3C9 /* DACDATA */ | ||
258 | #define LUT_INDEX_READ 0x3C7 /* DACRX */ | ||
259 | #define LUT_INDEX_WRITE 0x3C8 /* DACWX */ | ||
260 | #define DACMASK 0x3C6 | ||
261 | |||
262 | /* Definition Device */ | ||
263 | #define DEVICE_CRT 0x01 | ||
264 | #define DEVICE_DVI 0x03 | ||
265 | #define DEVICE_LCD 0x04 | ||
266 | |||
267 | /* Device output interface */ | ||
268 | #define INTERFACE_NONE 0x00 | ||
269 | #define INTERFACE_ANALOG_RGB 0x01 | ||
270 | #define INTERFACE_DVP0 0x02 | ||
271 | #define INTERFACE_DVP1 0x03 | ||
272 | #define INTERFACE_DFP_HIGH 0x04 | ||
273 | #define INTERFACE_DFP_LOW 0x05 | ||
274 | #define INTERFACE_DFP 0x06 | ||
275 | #define INTERFACE_LVDS0 0x07 | ||
276 | #define INTERFACE_LVDS1 0x08 | ||
277 | #define INTERFACE_LVDS0LVDS1 0x09 | ||
278 | #define INTERFACE_TMDS 0x0A | ||
279 | |||
280 | #define HW_LAYOUT_LCD_ONLY 0x01 | ||
281 | #define HW_LAYOUT_DVI_ONLY 0x02 | ||
282 | #define HW_LAYOUT_LCD_DVI 0x03 | ||
283 | #define HW_LAYOUT_LCD1_LCD2 0x04 | ||
284 | #define HW_LAYOUT_LCD_EXTERNAL_LCD2 0x10 | ||
285 | |||
286 | /* Definition CRTC Timing Index */ | ||
287 | #define H_TOTAL_INDEX 0 | ||
288 | #define H_ADDR_INDEX 1 | ||
289 | #define H_BLANK_START_INDEX 2 | ||
290 | #define H_BLANK_END_INDEX 3 | ||
291 | #define H_SYNC_START_INDEX 4 | ||
292 | #define H_SYNC_END_INDEX 5 | ||
293 | #define V_TOTAL_INDEX 6 | ||
294 | #define V_ADDR_INDEX 7 | ||
295 | #define V_BLANK_START_INDEX 8 | ||
296 | #define V_BLANK_END_INDEX 9 | ||
297 | #define V_SYNC_START_INDEX 10 | ||
298 | #define V_SYNC_END_INDEX 11 | ||
299 | #define H_TOTAL_SHADOW_INDEX 12 | ||
300 | #define H_BLANK_END_SHADOW_INDEX 13 | ||
301 | #define V_TOTAL_SHADOW_INDEX 14 | ||
302 | #define V_ADDR_SHADOW_INDEX 15 | ||
303 | #define V_BLANK_SATRT_SHADOW_INDEX 16 | ||
304 | #define V_BLANK_END_SHADOW_INDEX 17 | ||
305 | #define V_SYNC_SATRT_SHADOW_INDEX 18 | ||
306 | #define V_SYNC_END_SHADOW_INDEX 19 | ||
307 | |||
308 | /* LCD display method | ||
309 | */ | ||
310 | #define LCD_EXPANDSION 0x00 | ||
311 | #define LCD_CENTERING 0x01 | ||
312 | |||
313 | /* LCD mode | ||
314 | */ | ||
315 | #define LCD_OPENLDI 0x00 | ||
316 | #define LCD_SPWG 0x01 | ||
317 | |||
318 | struct crt_mode_table { | ||
319 | int refresh_rate; | ||
320 | int h_sync_polarity; | ||
321 | int v_sync_polarity; | ||
322 | struct via_display_timing crtc; | ||
323 | }; | ||
324 | |||
325 | struct io_reg { | ||
326 | int port; | ||
327 | u8 index; | ||
328 | u8 mask; | ||
329 | u8 value; | ||
330 | }; | ||
331 | |||
332 | #endif /* __SHARE_H__ */ | ||
diff --git a/drivers/video/fbdev/via/tblDPASetting.c b/drivers/video/fbdev/via/tblDPASetting.c new file mode 100644 index 000000000000..73bb554e7c1e --- /dev/null +++ b/drivers/video/fbdev/via/tblDPASetting.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include "global.h" | ||
23 | |||
24 | struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3324[] = { | ||
25 | /* ClkRange, DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1, | ||
26 | DVP1Driving, DFPHigh, DFPLow */ | ||
27 | /* CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], CR9B, | ||
28 | SR65, CR97, CR99 */ | ||
29 | /* LCK/VCK < 30000000 will use this value */ | ||
30 | {DPA_CLK_RANGE_30M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, | ||
31 | 0x00}, | ||
32 | /* 30000000 < LCK/VCK < 50000000 will use this value */ | ||
33 | {DPA_CLK_RANGE_30_50M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, | ||
34 | 0x00}, | ||
35 | /* 50000000 < LCK/VCK < 70000000 will use this value */ | ||
36 | {DPA_CLK_RANGE_50_70M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, | ||
37 | 0x00}, | ||
38 | /* 70000000 < LCK/VCK < 100000000 will use this value */ | ||
39 | {DPA_CLK_RANGE_70_100M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, | ||
40 | 0x00}, | ||
41 | /* 100000000 < LCK/VCK < 15000000 will use this value */ | ||
42 | {DPA_CLK_RANGE_100_150M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, | ||
43 | 0x00}, | ||
44 | /* 15000000 < LCK/VCK will use this value */ | ||
45 | {DPA_CLK_RANGE_150M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0E, 0x00, | ||
46 | 0x00}, | ||
47 | }; | ||
48 | |||
49 | struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3327[] = { | ||
50 | /* ClkRange,DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1, | ||
51 | DVP1Driving, DFPHigh, DFPLow */ | ||
52 | /* CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], CR9B, | ||
53 | SR65, CR97, CR99 */ | ||
54 | /* LCK/VCK < 30000000 will use this value */ | ||
55 | {DPA_CLK_RANGE_30M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x01}, | ||
56 | /* 30000000 < LCK/VCK < 50000000 will use this value */ | ||
57 | {DPA_CLK_RANGE_30_50M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x01}, | ||
58 | /* 50000000 < LCK/VCK < 70000000 will use this value */ | ||
59 | {DPA_CLK_RANGE_50_70M, 0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x01}, | ||
60 | /* 70000000 < LCK/VCK < 100000000 will use this value */ | ||
61 | {DPA_CLK_RANGE_70_100M, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x03}, | ||
62 | /* 100000000 < LCK/VCK < 15000000 will use this value */ | ||
63 | {DPA_CLK_RANGE_100_150M, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x02}, | ||
64 | /* 15000000 < LCK/VCK will use this value */ | ||
65 | {DPA_CLK_RANGE_150M, 0x00, 0x20, 0x00, 0x10, 0x00, 0x03, 0x00, 0x0D, 0x03}, | ||
66 | }; | ||
67 | |||
68 | /* For VT3364: */ | ||
69 | struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3364[] = { | ||
70 | /* ClkRange,DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1, | ||
71 | DVP1Driving, DFPHigh, DFPLow */ | ||
72 | /* CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], CR9B, | ||
73 | SR65, CR97, CR99 */ | ||
74 | /* LCK/VCK < 30000000 will use this value */ | ||
75 | {DPA_CLK_RANGE_30M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08}, | ||
76 | /* 30000000 < LCK/VCK < 50000000 will use this value */ | ||
77 | {DPA_CLK_RANGE_30_50M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08}, | ||
78 | /* 50000000 < LCK/VCK < 70000000 will use this value */ | ||
79 | {DPA_CLK_RANGE_50_70M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08}, | ||
80 | /* 70000000 < LCK/VCK < 100000000 will use this value */ | ||
81 | {DPA_CLK_RANGE_70_100M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08}, | ||
82 | /* 100000000 < LCK/VCK < 15000000 will use this value */ | ||
83 | {DPA_CLK_RANGE_100_150M, 0x03, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08}, | ||
84 | /* 15000000 < LCK/VCK will use this value */ | ||
85 | {DPA_CLK_RANGE_150M, 0x01, 0x00, 0x02, 0x10, 0x00, 0x03, 0x00, 0x00, 0x08}, | ||
86 | }; | ||
diff --git a/drivers/video/fbdev/via/tblDPASetting.h b/drivers/video/fbdev/via/tblDPASetting.h new file mode 100644 index 000000000000..6db61519cb5d --- /dev/null +++ b/drivers/video/fbdev/via/tblDPASetting.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef _TBLDPASETTING_H_ | ||
23 | #define _TBLDPASETTING_H_ | ||
24 | #include "global.h" | ||
25 | |||
26 | #define DPA_CLK_30M 30000000 | ||
27 | #define DPA_CLK_50M 50000000 | ||
28 | #define DPA_CLK_70M 70000000 | ||
29 | #define DPA_CLK_100M 100000000 | ||
30 | #define DPA_CLK_150M 150000000 | ||
31 | |||
32 | enum DPA_RANGE { | ||
33 | DPA_CLK_RANGE_30M, | ||
34 | DPA_CLK_RANGE_30_50M, | ||
35 | DPA_CLK_RANGE_50_70M, | ||
36 | DPA_CLK_RANGE_70_100M, | ||
37 | DPA_CLK_RANGE_100_150M, | ||
38 | DPA_CLK_RANGE_150M | ||
39 | }; | ||
40 | |||
41 | extern struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3324[6]; | ||
42 | extern struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3327[]; | ||
43 | extern struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3364[6]; | ||
44 | |||
45 | #endif | ||
diff --git a/drivers/video/fbdev/via/via-core.c b/drivers/video/fbdev/via/via-core.c new file mode 100644 index 000000000000..6e274825fb31 --- /dev/null +++ b/drivers/video/fbdev/via/via-core.c | |||
@@ -0,0 +1,790 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | * Copyright 2009 Jonathan Corbet <corbet@lwn.net> | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Core code for the Via multifunction framebuffer device. | ||
9 | */ | ||
10 | #include <linux/via-core.h> | ||
11 | #include <linux/via_i2c.h> | ||
12 | #include <linux/via-gpio.h> | ||
13 | #include "global.h" | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/list.h> | ||
19 | #include <linux/pm.h> | ||
20 | #include <asm/olpc.h> | ||
21 | |||
22 | /* | ||
23 | * The default port config. | ||
24 | */ | ||
25 | static struct via_port_cfg adap_configs[] = { | ||
26 | [VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x26 }, | ||
27 | [VIA_PORT_31] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x31 }, | ||
28 | [VIA_PORT_25] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 }, | ||
29 | [VIA_PORT_2C] = { VIA_PORT_GPIO, VIA_MODE_I2C, VIASR, 0x2c }, | ||
30 | [VIA_PORT_3D] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x3d }, | ||
31 | { 0, 0, 0, 0 } | ||
32 | }; | ||
33 | |||
34 | /* | ||
35 | * The OLPC XO-1.5 puts the camera power and reset lines onto | ||
36 | * GPIO 2C. | ||
37 | */ | ||
38 | static struct via_port_cfg olpc_adap_configs[] = { | ||
39 | [VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x26 }, | ||
40 | [VIA_PORT_31] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x31 }, | ||
41 | [VIA_PORT_25] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 }, | ||
42 | [VIA_PORT_2C] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x2c }, | ||
43 | [VIA_PORT_3D] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x3d }, | ||
44 | { 0, 0, 0, 0 } | ||
45 | }; | ||
46 | |||
47 | /* | ||
48 | * We currently only support one viafb device (will there ever be | ||
49 | * more than one?), so just declare it globally here. | ||
50 | */ | ||
51 | static struct viafb_dev global_dev; | ||
52 | |||
53 | |||
54 | /* | ||
55 | * Basic register access; spinlock required. | ||
56 | */ | ||
57 | static inline void viafb_mmio_write(int reg, u32 v) | ||
58 | { | ||
59 | iowrite32(v, global_dev.engine_mmio + reg); | ||
60 | } | ||
61 | |||
62 | static inline int viafb_mmio_read(int reg) | ||
63 | { | ||
64 | return ioread32(global_dev.engine_mmio + reg); | ||
65 | } | ||
66 | |||
67 | /* ---------------------------------------------------------------------- */ | ||
68 | /* | ||
69 | * Interrupt management. We have a single IRQ line for a lot of | ||
70 | * different functions, so we need to share it. The design here | ||
71 | * is that we don't want to reimplement the shared IRQ code here; | ||
72 | * we also want to avoid having contention for a single handler thread. | ||
73 | * So each subdev driver which needs interrupts just requests | ||
74 | * them directly from the kernel. We just have what's needed for | ||
75 | * overall access to the interrupt control register. | ||
76 | */ | ||
77 | |||
78 | /* | ||
79 | * Which interrupts are enabled now? | ||
80 | */ | ||
81 | static u32 viafb_enabled_ints; | ||
82 | |||
83 | static void viafb_int_init(void) | ||
84 | { | ||
85 | viafb_enabled_ints = 0; | ||
86 | |||
87 | viafb_mmio_write(VDE_INTERRUPT, 0); | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Allow subdevs to ask for specific interrupts to be enabled. These | ||
92 | * functions must be called with reg_lock held | ||
93 | */ | ||
94 | void viafb_irq_enable(u32 mask) | ||
95 | { | ||
96 | viafb_enabled_ints |= mask; | ||
97 | viafb_mmio_write(VDE_INTERRUPT, viafb_enabled_ints | VDE_I_ENABLE); | ||
98 | } | ||
99 | EXPORT_SYMBOL_GPL(viafb_irq_enable); | ||
100 | |||
101 | void viafb_irq_disable(u32 mask) | ||
102 | { | ||
103 | viafb_enabled_ints &= ~mask; | ||
104 | if (viafb_enabled_ints == 0) | ||
105 | viafb_mmio_write(VDE_INTERRUPT, 0); /* Disable entirely */ | ||
106 | else | ||
107 | viafb_mmio_write(VDE_INTERRUPT, | ||
108 | viafb_enabled_ints | VDE_I_ENABLE); | ||
109 | } | ||
110 | EXPORT_SYMBOL_GPL(viafb_irq_disable); | ||
111 | |||
112 | /* ---------------------------------------------------------------------- */ | ||
113 | /* | ||
114 | * Currently, the camera driver is the only user of the DMA code, so we | ||
115 | * only compile it in if the camera driver is being built. Chances are, | ||
116 | * most viafb systems will not need to have this extra code for a while. | ||
117 | * As soon as another user comes long, the ifdef can be removed. | ||
118 | */ | ||
119 | #if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE) | ||
120 | /* | ||
121 | * Access to the DMA engine. This currently provides what the camera | ||
122 | * driver needs (i.e. outgoing only) but is easily expandable if need | ||
123 | * be. | ||
124 | */ | ||
125 | |||
126 | /* | ||
127 | * There are four DMA channels in the vx855. For now, we only | ||
128 | * use one of them, though. Most of the time, the DMA channel | ||
129 | * will be idle, so we keep the IRQ handler unregistered except | ||
130 | * when some subsystem has indicated an interest. | ||
131 | */ | ||
132 | static int viafb_dma_users; | ||
133 | static DECLARE_COMPLETION(viafb_dma_completion); | ||
134 | /* | ||
135 | * This mutex protects viafb_dma_users and our global interrupt | ||
136 | * registration state; it also serializes access to the DMA | ||
137 | * engine. | ||
138 | */ | ||
139 | static DEFINE_MUTEX(viafb_dma_lock); | ||
140 | |||
141 | /* | ||
142 | * The VX855 DMA descriptor (used for s/g transfers) looks | ||
143 | * like this. | ||
144 | */ | ||
145 | struct viafb_vx855_dma_descr { | ||
146 | u32 addr_low; /* Low part of phys addr */ | ||
147 | u32 addr_high; /* High 12 bits of addr */ | ||
148 | u32 fb_offset; /* Offset into FB memory */ | ||
149 | u32 seg_size; /* Size, 16-byte units */ | ||
150 | u32 tile_mode; /* "tile mode" setting */ | ||
151 | u32 next_desc_low; /* Next descriptor addr */ | ||
152 | u32 next_desc_high; | ||
153 | u32 pad; /* Fill out to 64 bytes */ | ||
154 | }; | ||
155 | |||
156 | /* | ||
157 | * Flags added to the "next descriptor low" pointers | ||
158 | */ | ||
159 | #define VIAFB_DMA_MAGIC 0x01 /* ??? Just has to be there */ | ||
160 | #define VIAFB_DMA_FINAL_SEGMENT 0x02 /* Final segment */ | ||
161 | |||
162 | /* | ||
163 | * The completion IRQ handler. | ||
164 | */ | ||
165 | static irqreturn_t viafb_dma_irq(int irq, void *data) | ||
166 | { | ||
167 | int csr; | ||
168 | irqreturn_t ret = IRQ_NONE; | ||
169 | |||
170 | spin_lock(&global_dev.reg_lock); | ||
171 | csr = viafb_mmio_read(VDMA_CSR0); | ||
172 | if (csr & VDMA_C_DONE) { | ||
173 | viafb_mmio_write(VDMA_CSR0, VDMA_C_DONE); | ||
174 | complete(&viafb_dma_completion); | ||
175 | ret = IRQ_HANDLED; | ||
176 | } | ||
177 | spin_unlock(&global_dev.reg_lock); | ||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * Indicate a need for DMA functionality. | ||
183 | */ | ||
184 | int viafb_request_dma(void) | ||
185 | { | ||
186 | int ret = 0; | ||
187 | |||
188 | /* | ||
189 | * Only VX855 is supported currently. | ||
190 | */ | ||
191 | if (global_dev.chip_type != UNICHROME_VX855) | ||
192 | return -ENODEV; | ||
193 | /* | ||
194 | * Note the new user and set up our interrupt handler | ||
195 | * if need be. | ||
196 | */ | ||
197 | mutex_lock(&viafb_dma_lock); | ||
198 | viafb_dma_users++; | ||
199 | if (viafb_dma_users == 1) { | ||
200 | ret = request_irq(global_dev.pdev->irq, viafb_dma_irq, | ||
201 | IRQF_SHARED, "via-dma", &viafb_dma_users); | ||
202 | if (ret) | ||
203 | viafb_dma_users--; | ||
204 | else | ||
205 | viafb_irq_enable(VDE_I_DMA0TDEN); | ||
206 | } | ||
207 | mutex_unlock(&viafb_dma_lock); | ||
208 | return ret; | ||
209 | } | ||
210 | EXPORT_SYMBOL_GPL(viafb_request_dma); | ||
211 | |||
212 | void viafb_release_dma(void) | ||
213 | { | ||
214 | mutex_lock(&viafb_dma_lock); | ||
215 | viafb_dma_users--; | ||
216 | if (viafb_dma_users == 0) { | ||
217 | viafb_irq_disable(VDE_I_DMA0TDEN); | ||
218 | free_irq(global_dev.pdev->irq, &viafb_dma_users); | ||
219 | } | ||
220 | mutex_unlock(&viafb_dma_lock); | ||
221 | } | ||
222 | EXPORT_SYMBOL_GPL(viafb_release_dma); | ||
223 | |||
224 | |||
225 | #if 0 | ||
226 | /* | ||
227 | * Copy a single buffer from FB memory, synchronously. This code works | ||
228 | * but is not currently used. | ||
229 | */ | ||
230 | void viafb_dma_copy_out(unsigned int offset, dma_addr_t paddr, int len) | ||
231 | { | ||
232 | unsigned long flags; | ||
233 | int csr; | ||
234 | |||
235 | mutex_lock(&viafb_dma_lock); | ||
236 | init_completion(&viafb_dma_completion); | ||
237 | /* | ||
238 | * Program the controller. | ||
239 | */ | ||
240 | spin_lock_irqsave(&global_dev.reg_lock, flags); | ||
241 | viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_DONE); | ||
242 | /* Enable ints; must happen after CSR0 write! */ | ||
243 | viafb_mmio_write(VDMA_MR0, VDMA_MR_TDIE); | ||
244 | viafb_mmio_write(VDMA_MARL0, (int) (paddr & 0xfffffff0)); | ||
245 | viafb_mmio_write(VDMA_MARH0, (int) ((paddr >> 28) & 0xfff)); | ||
246 | /* Data sheet suggests DAR0 should be <<4, but it lies */ | ||
247 | viafb_mmio_write(VDMA_DAR0, offset); | ||
248 | viafb_mmio_write(VDMA_DQWCR0, len >> 4); | ||
249 | viafb_mmio_write(VDMA_TMR0, 0); | ||
250 | viafb_mmio_write(VDMA_DPRL0, 0); | ||
251 | viafb_mmio_write(VDMA_DPRH0, 0); | ||
252 | viafb_mmio_write(VDMA_PMR0, 0); | ||
253 | csr = viafb_mmio_read(VDMA_CSR0); | ||
254 | viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_START); | ||
255 | spin_unlock_irqrestore(&global_dev.reg_lock, flags); | ||
256 | /* | ||
257 | * Now we just wait until the interrupt handler says | ||
258 | * we're done. | ||
259 | */ | ||
260 | wait_for_completion_interruptible(&viafb_dma_completion); | ||
261 | viafb_mmio_write(VDMA_MR0, 0); /* Reset int enable */ | ||
262 | mutex_unlock(&viafb_dma_lock); | ||
263 | } | ||
264 | EXPORT_SYMBOL_GPL(viafb_dma_copy_out); | ||
265 | #endif | ||
266 | |||
267 | /* | ||
268 | * Do a scatter/gather DMA copy from FB memory. You must have done | ||
269 | * a successful call to viafb_request_dma() first. | ||
270 | */ | ||
271 | int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg) | ||
272 | { | ||
273 | struct viafb_vx855_dma_descr *descr; | ||
274 | void *descrpages; | ||
275 | dma_addr_t descr_handle; | ||
276 | unsigned long flags; | ||
277 | int i; | ||
278 | struct scatterlist *sgentry; | ||
279 | dma_addr_t nextdesc; | ||
280 | |||
281 | /* | ||
282 | * Get a place to put the descriptors. | ||
283 | */ | ||
284 | descrpages = dma_alloc_coherent(&global_dev.pdev->dev, | ||
285 | nsg*sizeof(struct viafb_vx855_dma_descr), | ||
286 | &descr_handle, GFP_KERNEL); | ||
287 | if (descrpages == NULL) { | ||
288 | dev_err(&global_dev.pdev->dev, "Unable to get descr page.\n"); | ||
289 | return -ENOMEM; | ||
290 | } | ||
291 | mutex_lock(&viafb_dma_lock); | ||
292 | /* | ||
293 | * Fill them in. | ||
294 | */ | ||
295 | descr = descrpages; | ||
296 | nextdesc = descr_handle + sizeof(struct viafb_vx855_dma_descr); | ||
297 | for_each_sg(sg, sgentry, nsg, i) { | ||
298 | dma_addr_t paddr = sg_dma_address(sgentry); | ||
299 | descr->addr_low = paddr & 0xfffffff0; | ||
300 | descr->addr_high = ((u64) paddr >> 32) & 0x0fff; | ||
301 | descr->fb_offset = offset; | ||
302 | descr->seg_size = sg_dma_len(sgentry) >> 4; | ||
303 | descr->tile_mode = 0; | ||
304 | descr->next_desc_low = (nextdesc&0xfffffff0) | VIAFB_DMA_MAGIC; | ||
305 | descr->next_desc_high = ((u64) nextdesc >> 32) & 0x0fff; | ||
306 | descr->pad = 0xffffffff; /* VIA driver does this */ | ||
307 | offset += sg_dma_len(sgentry); | ||
308 | nextdesc += sizeof(struct viafb_vx855_dma_descr); | ||
309 | descr++; | ||
310 | } | ||
311 | descr[-1].next_desc_low = VIAFB_DMA_FINAL_SEGMENT|VIAFB_DMA_MAGIC; | ||
312 | /* | ||
313 | * Program the engine. | ||
314 | */ | ||
315 | spin_lock_irqsave(&global_dev.reg_lock, flags); | ||
316 | init_completion(&viafb_dma_completion); | ||
317 | viafb_mmio_write(VDMA_DQWCR0, 0); | ||
318 | viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_DONE); | ||
319 | viafb_mmio_write(VDMA_MR0, VDMA_MR_TDIE | VDMA_MR_CHAIN); | ||
320 | viafb_mmio_write(VDMA_DPRL0, descr_handle | VIAFB_DMA_MAGIC); | ||
321 | viafb_mmio_write(VDMA_DPRH0, | ||
322 | (((u64)descr_handle >> 32) & 0x0fff) | 0xf0000); | ||
323 | (void) viafb_mmio_read(VDMA_CSR0); | ||
324 | viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_START); | ||
325 | spin_unlock_irqrestore(&global_dev.reg_lock, flags); | ||
326 | /* | ||
327 | * Now we just wait until the interrupt handler says | ||
328 | * we're done. Except that, actually, we need to wait a little | ||
329 | * longer: the interrupts seem to jump the gun a little and we | ||
330 | * get corrupted frames sometimes. | ||
331 | */ | ||
332 | wait_for_completion_timeout(&viafb_dma_completion, 1); | ||
333 | msleep(1); | ||
334 | if ((viafb_mmio_read(VDMA_CSR0)&VDMA_C_DONE) == 0) | ||
335 | printk(KERN_ERR "VIA DMA timeout!\n"); | ||
336 | /* | ||
337 | * Clean up and we're done. | ||
338 | */ | ||
339 | viafb_mmio_write(VDMA_CSR0, VDMA_C_DONE); | ||
340 | viafb_mmio_write(VDMA_MR0, 0); /* Reset int enable */ | ||
341 | mutex_unlock(&viafb_dma_lock); | ||
342 | dma_free_coherent(&global_dev.pdev->dev, | ||
343 | nsg*sizeof(struct viafb_vx855_dma_descr), descrpages, | ||
344 | descr_handle); | ||
345 | return 0; | ||
346 | } | ||
347 | EXPORT_SYMBOL_GPL(viafb_dma_copy_out_sg); | ||
348 | #endif /* CONFIG_VIDEO_VIA_CAMERA */ | ||
349 | |||
350 | /* ---------------------------------------------------------------------- */ | ||
351 | /* | ||
352 | * Figure out how big our framebuffer memory is. Kind of ugly, | ||
353 | * but evidently we can't trust the information found in the | ||
354 | * fbdev configuration area. | ||
355 | */ | ||
356 | static u16 via_function3[] = { | ||
357 | CLE266_FUNCTION3, KM400_FUNCTION3, CN400_FUNCTION3, CN700_FUNCTION3, | ||
358 | CX700_FUNCTION3, KM800_FUNCTION3, KM890_FUNCTION3, P4M890_FUNCTION3, | ||
359 | P4M900_FUNCTION3, VX800_FUNCTION3, VX855_FUNCTION3, VX900_FUNCTION3, | ||
360 | }; | ||
361 | |||
362 | /* Get the BIOS-configured framebuffer size from PCI configuration space | ||
363 | * of function 3 in the respective chipset */ | ||
364 | static int viafb_get_fb_size_from_pci(int chip_type) | ||
365 | { | ||
366 | int i; | ||
367 | u8 offset = 0; | ||
368 | u32 FBSize; | ||
369 | u32 VideoMemSize; | ||
370 | |||
371 | /* search for the "FUNCTION3" device in this chipset */ | ||
372 | for (i = 0; i < ARRAY_SIZE(via_function3); i++) { | ||
373 | struct pci_dev *pdev; | ||
374 | |||
375 | pdev = pci_get_device(PCI_VENDOR_ID_VIA, via_function3[i], | ||
376 | NULL); | ||
377 | if (!pdev) | ||
378 | continue; | ||
379 | |||
380 | DEBUG_MSG(KERN_INFO "Device ID = %x\n", pdev->device); | ||
381 | |||
382 | switch (pdev->device) { | ||
383 | case CLE266_FUNCTION3: | ||
384 | case KM400_FUNCTION3: | ||
385 | offset = 0xE0; | ||
386 | break; | ||
387 | case CN400_FUNCTION3: | ||
388 | case CN700_FUNCTION3: | ||
389 | case CX700_FUNCTION3: | ||
390 | case KM800_FUNCTION3: | ||
391 | case KM890_FUNCTION3: | ||
392 | case P4M890_FUNCTION3: | ||
393 | case P4M900_FUNCTION3: | ||
394 | case VX800_FUNCTION3: | ||
395 | case VX855_FUNCTION3: | ||
396 | case VX900_FUNCTION3: | ||
397 | /*case CN750_FUNCTION3: */ | ||
398 | offset = 0xA0; | ||
399 | break; | ||
400 | } | ||
401 | |||
402 | if (!offset) | ||
403 | break; | ||
404 | |||
405 | pci_read_config_dword(pdev, offset, &FBSize); | ||
406 | pci_dev_put(pdev); | ||
407 | } | ||
408 | |||
409 | if (!offset) { | ||
410 | printk(KERN_ERR "cannot determine framebuffer size\n"); | ||
411 | return -EIO; | ||
412 | } | ||
413 | |||
414 | FBSize = FBSize & 0x00007000; | ||
415 | DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize); | ||
416 | |||
417 | if (chip_type < UNICHROME_CX700) { | ||
418 | switch (FBSize) { | ||
419 | case 0x00004000: | ||
420 | VideoMemSize = (16 << 20); /*16M */ | ||
421 | break; | ||
422 | |||
423 | case 0x00005000: | ||
424 | VideoMemSize = (32 << 20); /*32M */ | ||
425 | break; | ||
426 | |||
427 | case 0x00006000: | ||
428 | VideoMemSize = (64 << 20); /*64M */ | ||
429 | break; | ||
430 | |||
431 | default: | ||
432 | VideoMemSize = (32 << 20); /*32M */ | ||
433 | break; | ||
434 | } | ||
435 | } else { | ||
436 | switch (FBSize) { | ||
437 | case 0x00001000: | ||
438 | VideoMemSize = (8 << 20); /*8M */ | ||
439 | break; | ||
440 | |||
441 | case 0x00002000: | ||
442 | VideoMemSize = (16 << 20); /*16M */ | ||
443 | break; | ||
444 | |||
445 | case 0x00003000: | ||
446 | VideoMemSize = (32 << 20); /*32M */ | ||
447 | break; | ||
448 | |||
449 | case 0x00004000: | ||
450 | VideoMemSize = (64 << 20); /*64M */ | ||
451 | break; | ||
452 | |||
453 | case 0x00005000: | ||
454 | VideoMemSize = (128 << 20); /*128M */ | ||
455 | break; | ||
456 | |||
457 | case 0x00006000: | ||
458 | VideoMemSize = (256 << 20); /*256M */ | ||
459 | break; | ||
460 | |||
461 | case 0x00007000: /* Only on VX855/875 */ | ||
462 | VideoMemSize = (512 << 20); /*512M */ | ||
463 | break; | ||
464 | |||
465 | default: | ||
466 | VideoMemSize = (32 << 20); /*32M */ | ||
467 | break; | ||
468 | } | ||
469 | } | ||
470 | |||
471 | return VideoMemSize; | ||
472 | } | ||
473 | |||
474 | |||
475 | /* | ||
476 | * Figure out and map our MMIO regions. | ||
477 | */ | ||
478 | static int via_pci_setup_mmio(struct viafb_dev *vdev) | ||
479 | { | ||
480 | int ret; | ||
481 | /* | ||
482 | * Hook up to the device registers. Note that we soldier | ||
483 | * on if it fails; the framebuffer can operate (without | ||
484 | * acceleration) without this region. | ||
485 | */ | ||
486 | vdev->engine_start = pci_resource_start(vdev->pdev, 1); | ||
487 | vdev->engine_len = pci_resource_len(vdev->pdev, 1); | ||
488 | vdev->engine_mmio = ioremap_nocache(vdev->engine_start, | ||
489 | vdev->engine_len); | ||
490 | if (vdev->engine_mmio == NULL) | ||
491 | dev_err(&vdev->pdev->dev, | ||
492 | "Unable to map engine MMIO; operation will be " | ||
493 | "slow and crippled.\n"); | ||
494 | /* | ||
495 | * Map in framebuffer memory. For now, failure here is | ||
496 | * fatal. Unfortunately, in the absence of significant | ||
497 | * vmalloc space, failure here is also entirely plausible. | ||
498 | * Eventually we want to move away from mapping this | ||
499 | * entire region. | ||
500 | */ | ||
501 | if (vdev->chip_type == UNICHROME_VX900) | ||
502 | vdev->fbmem_start = pci_resource_start(vdev->pdev, 2); | ||
503 | else | ||
504 | vdev->fbmem_start = pci_resource_start(vdev->pdev, 0); | ||
505 | ret = vdev->fbmem_len = viafb_get_fb_size_from_pci(vdev->chip_type); | ||
506 | if (ret < 0) | ||
507 | goto out_unmap; | ||
508 | |||
509 | /* try to map less memory on failure, 8 MB should be still enough */ | ||
510 | for (; vdev->fbmem_len >= 8 << 20; vdev->fbmem_len /= 2) { | ||
511 | vdev->fbmem = ioremap_wc(vdev->fbmem_start, vdev->fbmem_len); | ||
512 | if (vdev->fbmem) | ||
513 | break; | ||
514 | } | ||
515 | |||
516 | if (vdev->fbmem == NULL) { | ||
517 | ret = -ENOMEM; | ||
518 | goto out_unmap; | ||
519 | } | ||
520 | return 0; | ||
521 | out_unmap: | ||
522 | iounmap(vdev->engine_mmio); | ||
523 | return ret; | ||
524 | } | ||
525 | |||
526 | static void via_pci_teardown_mmio(struct viafb_dev *vdev) | ||
527 | { | ||
528 | iounmap(vdev->fbmem); | ||
529 | iounmap(vdev->engine_mmio); | ||
530 | } | ||
531 | |||
532 | /* | ||
533 | * Create our subsidiary devices. | ||
534 | */ | ||
535 | static struct viafb_subdev_info { | ||
536 | char *name; | ||
537 | struct platform_device *platdev; | ||
538 | } viafb_subdevs[] = { | ||
539 | { | ||
540 | .name = "viafb-gpio", | ||
541 | }, | ||
542 | { | ||
543 | .name = "viafb-i2c", | ||
544 | }, | ||
545 | #if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE) | ||
546 | { | ||
547 | .name = "viafb-camera", | ||
548 | }, | ||
549 | #endif | ||
550 | }; | ||
551 | #define N_SUBDEVS ARRAY_SIZE(viafb_subdevs) | ||
552 | |||
553 | static int via_create_subdev(struct viafb_dev *vdev, | ||
554 | struct viafb_subdev_info *info) | ||
555 | { | ||
556 | int ret; | ||
557 | |||
558 | info->platdev = platform_device_alloc(info->name, -1); | ||
559 | if (!info->platdev) { | ||
560 | dev_err(&vdev->pdev->dev, "Unable to allocate pdev %s\n", | ||
561 | info->name); | ||
562 | return -ENOMEM; | ||
563 | } | ||
564 | info->platdev->dev.parent = &vdev->pdev->dev; | ||
565 | info->platdev->dev.platform_data = vdev; | ||
566 | ret = platform_device_add(info->platdev); | ||
567 | if (ret) { | ||
568 | dev_err(&vdev->pdev->dev, "Unable to add pdev %s\n", | ||
569 | info->name); | ||
570 | platform_device_put(info->platdev); | ||
571 | info->platdev = NULL; | ||
572 | } | ||
573 | return ret; | ||
574 | } | ||
575 | |||
576 | static int via_setup_subdevs(struct viafb_dev *vdev) | ||
577 | { | ||
578 | int i; | ||
579 | |||
580 | /* | ||
581 | * Ignore return values. Even if some of the devices | ||
582 | * fail to be created, we'll still be able to use some | ||
583 | * of the rest. | ||
584 | */ | ||
585 | for (i = 0; i < N_SUBDEVS; i++) | ||
586 | via_create_subdev(vdev, viafb_subdevs + i); | ||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static void via_teardown_subdevs(void) | ||
591 | { | ||
592 | int i; | ||
593 | |||
594 | for (i = 0; i < N_SUBDEVS; i++) | ||
595 | if (viafb_subdevs[i].platdev) { | ||
596 | viafb_subdevs[i].platdev->dev.platform_data = NULL; | ||
597 | platform_device_unregister(viafb_subdevs[i].platdev); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | /* | ||
602 | * Power management functions | ||
603 | */ | ||
604 | #ifdef CONFIG_PM | ||
605 | static LIST_HEAD(viafb_pm_hooks); | ||
606 | static DEFINE_MUTEX(viafb_pm_hooks_lock); | ||
607 | |||
608 | void viafb_pm_register(struct viafb_pm_hooks *hooks) | ||
609 | { | ||
610 | INIT_LIST_HEAD(&hooks->list); | ||
611 | |||
612 | mutex_lock(&viafb_pm_hooks_lock); | ||
613 | list_add_tail(&hooks->list, &viafb_pm_hooks); | ||
614 | mutex_unlock(&viafb_pm_hooks_lock); | ||
615 | } | ||
616 | EXPORT_SYMBOL_GPL(viafb_pm_register); | ||
617 | |||
618 | void viafb_pm_unregister(struct viafb_pm_hooks *hooks) | ||
619 | { | ||
620 | mutex_lock(&viafb_pm_hooks_lock); | ||
621 | list_del(&hooks->list); | ||
622 | mutex_unlock(&viafb_pm_hooks_lock); | ||
623 | } | ||
624 | EXPORT_SYMBOL_GPL(viafb_pm_unregister); | ||
625 | |||
626 | static int via_suspend(struct pci_dev *pdev, pm_message_t state) | ||
627 | { | ||
628 | struct viafb_pm_hooks *hooks; | ||
629 | |||
630 | if (state.event != PM_EVENT_SUSPEND) | ||
631 | return 0; | ||
632 | /* | ||
633 | * "I've occasionally hit a few drivers that caused suspend | ||
634 | * failures, and each and every time it was a driver bug, and | ||
635 | * the right thing to do was to just ignore the error and suspend | ||
636 | * anyway - returning an error code and trying to undo the suspend | ||
637 | * is not what anybody ever really wants, even if our model | ||
638 | *_allows_ for it." | ||
639 | * -- Linus Torvalds, Dec. 7, 2009 | ||
640 | */ | ||
641 | mutex_lock(&viafb_pm_hooks_lock); | ||
642 | list_for_each_entry_reverse(hooks, &viafb_pm_hooks, list) | ||
643 | hooks->suspend(hooks->private); | ||
644 | mutex_unlock(&viafb_pm_hooks_lock); | ||
645 | |||
646 | pci_save_state(pdev); | ||
647 | pci_disable_device(pdev); | ||
648 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static int via_resume(struct pci_dev *pdev) | ||
653 | { | ||
654 | struct viafb_pm_hooks *hooks; | ||
655 | |||
656 | /* Get the bus side powered up */ | ||
657 | pci_set_power_state(pdev, PCI_D0); | ||
658 | pci_restore_state(pdev); | ||
659 | if (pci_enable_device(pdev)) | ||
660 | return 0; | ||
661 | |||
662 | pci_set_master(pdev); | ||
663 | |||
664 | /* Now bring back any subdevs */ | ||
665 | mutex_lock(&viafb_pm_hooks_lock); | ||
666 | list_for_each_entry(hooks, &viafb_pm_hooks, list) | ||
667 | hooks->resume(hooks->private); | ||
668 | mutex_unlock(&viafb_pm_hooks_lock); | ||
669 | |||
670 | return 0; | ||
671 | } | ||
672 | #endif /* CONFIG_PM */ | ||
673 | |||
674 | static int via_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
675 | { | ||
676 | int ret; | ||
677 | |||
678 | ret = pci_enable_device(pdev); | ||
679 | if (ret) | ||
680 | return ret; | ||
681 | |||
682 | /* | ||
683 | * Global device initialization. | ||
684 | */ | ||
685 | memset(&global_dev, 0, sizeof(global_dev)); | ||
686 | global_dev.pdev = pdev; | ||
687 | global_dev.chip_type = ent->driver_data; | ||
688 | global_dev.port_cfg = adap_configs; | ||
689 | if (machine_is_olpc()) | ||
690 | global_dev.port_cfg = olpc_adap_configs; | ||
691 | |||
692 | spin_lock_init(&global_dev.reg_lock); | ||
693 | ret = via_pci_setup_mmio(&global_dev); | ||
694 | if (ret) | ||
695 | goto out_disable; | ||
696 | /* | ||
697 | * Set up interrupts and create our subdevices. Continue even if | ||
698 | * some things fail. | ||
699 | */ | ||
700 | viafb_int_init(); | ||
701 | via_setup_subdevs(&global_dev); | ||
702 | /* | ||
703 | * Set up the framebuffer device | ||
704 | */ | ||
705 | ret = via_fb_pci_probe(&global_dev); | ||
706 | if (ret) | ||
707 | goto out_subdevs; | ||
708 | return 0; | ||
709 | |||
710 | out_subdevs: | ||
711 | via_teardown_subdevs(); | ||
712 | via_pci_teardown_mmio(&global_dev); | ||
713 | out_disable: | ||
714 | pci_disable_device(pdev); | ||
715 | return ret; | ||
716 | } | ||
717 | |||
718 | static void via_pci_remove(struct pci_dev *pdev) | ||
719 | { | ||
720 | via_teardown_subdevs(); | ||
721 | via_fb_pci_remove(pdev); | ||
722 | via_pci_teardown_mmio(&global_dev); | ||
723 | pci_disable_device(pdev); | ||
724 | } | ||
725 | |||
726 | |||
727 | static struct pci_device_id via_pci_table[] = { | ||
728 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CLE266_DID), | ||
729 | .driver_data = UNICHROME_CLE266 }, | ||
730 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K400_DID), | ||
731 | .driver_data = UNICHROME_K400 }, | ||
732 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K800_DID), | ||
733 | .driver_data = UNICHROME_K800 }, | ||
734 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID), | ||
735 | .driver_data = UNICHROME_PM800 }, | ||
736 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN700_DID), | ||
737 | .driver_data = UNICHROME_CN700 }, | ||
738 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CX700_DID), | ||
739 | .driver_data = UNICHROME_CX700 }, | ||
740 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN750_DID), | ||
741 | .driver_data = UNICHROME_CN750 }, | ||
742 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID), | ||
743 | .driver_data = UNICHROME_K8M890 }, | ||
744 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID), | ||
745 | .driver_data = UNICHROME_P4M890 }, | ||
746 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID), | ||
747 | .driver_data = UNICHROME_P4M900 }, | ||
748 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX800_DID), | ||
749 | .driver_data = UNICHROME_VX800 }, | ||
750 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID), | ||
751 | .driver_data = UNICHROME_VX855 }, | ||
752 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX900_DID), | ||
753 | .driver_data = UNICHROME_VX900 }, | ||
754 | { } | ||
755 | }; | ||
756 | MODULE_DEVICE_TABLE(pci, via_pci_table); | ||
757 | |||
758 | static struct pci_driver via_driver = { | ||
759 | .name = "viafb", | ||
760 | .id_table = via_pci_table, | ||
761 | .probe = via_pci_probe, | ||
762 | .remove = via_pci_remove, | ||
763 | #ifdef CONFIG_PM | ||
764 | .suspend = via_suspend, | ||
765 | .resume = via_resume, | ||
766 | #endif | ||
767 | }; | ||
768 | |||
769 | static int __init via_core_init(void) | ||
770 | { | ||
771 | int ret; | ||
772 | |||
773 | ret = viafb_init(); | ||
774 | if (ret) | ||
775 | return ret; | ||
776 | viafb_i2c_init(); | ||
777 | viafb_gpio_init(); | ||
778 | return pci_register_driver(&via_driver); | ||
779 | } | ||
780 | |||
781 | static void __exit via_core_exit(void) | ||
782 | { | ||
783 | pci_unregister_driver(&via_driver); | ||
784 | viafb_gpio_exit(); | ||
785 | viafb_i2c_exit(); | ||
786 | viafb_exit(); | ||
787 | } | ||
788 | |||
789 | module_init(via_core_init); | ||
790 | module_exit(via_core_exit); | ||
diff --git a/drivers/video/fbdev/via/via-gpio.c b/drivers/video/fbdev/via/via-gpio.c new file mode 100644 index 000000000000..e408679081ab --- /dev/null +++ b/drivers/video/fbdev/via/via-gpio.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | * Support for viafb GPIO ports. | ||
3 | * | ||
4 | * Copyright 2009 Jonathan Corbet <corbet@lwn.net> | ||
5 | * Distributable under version 2 of the GNU General Public License. | ||
6 | */ | ||
7 | |||
8 | #include <linux/spinlock.h> | ||
9 | #include <linux/gpio.h> | ||
10 | #include <linux/platform_device.h> | ||
11 | #include <linux/via-core.h> | ||
12 | #include <linux/via-gpio.h> | ||
13 | #include <linux/export.h> | ||
14 | |||
15 | /* | ||
16 | * The ports we know about. Note that the port-25 gpios are not | ||
17 | * mentioned in the datasheet. | ||
18 | */ | ||
19 | |||
20 | struct viafb_gpio { | ||
21 | char *vg_name; /* Data sheet name */ | ||
22 | u16 vg_io_port; | ||
23 | u8 vg_port_index; | ||
24 | int vg_mask_shift; | ||
25 | }; | ||
26 | |||
27 | static struct viafb_gpio viafb_all_gpios[] = { | ||
28 | { | ||
29 | .vg_name = "VGPIO0", /* Guess - not in datasheet */ | ||
30 | .vg_io_port = VIASR, | ||
31 | .vg_port_index = 0x25, | ||
32 | .vg_mask_shift = 1 | ||
33 | }, | ||
34 | { | ||
35 | .vg_name = "VGPIO1", | ||
36 | .vg_io_port = VIASR, | ||
37 | .vg_port_index = 0x25, | ||
38 | .vg_mask_shift = 0 | ||
39 | }, | ||
40 | { | ||
41 | .vg_name = "VGPIO2", /* aka DISPCLKI0 */ | ||
42 | .vg_io_port = VIASR, | ||
43 | .vg_port_index = 0x2c, | ||
44 | .vg_mask_shift = 1 | ||
45 | }, | ||
46 | { | ||
47 | .vg_name = "VGPIO3", /* aka DISPCLKO0 */ | ||
48 | .vg_io_port = VIASR, | ||
49 | .vg_port_index = 0x2c, | ||
50 | .vg_mask_shift = 0 | ||
51 | }, | ||
52 | { | ||
53 | .vg_name = "VGPIO4", /* DISPCLKI1 */ | ||
54 | .vg_io_port = VIASR, | ||
55 | .vg_port_index = 0x3d, | ||
56 | .vg_mask_shift = 1 | ||
57 | }, | ||
58 | { | ||
59 | .vg_name = "VGPIO5", /* DISPCLKO1 */ | ||
60 | .vg_io_port = VIASR, | ||
61 | .vg_port_index = 0x3d, | ||
62 | .vg_mask_shift = 0 | ||
63 | }, | ||
64 | }; | ||
65 | |||
66 | #define VIAFB_NUM_GPIOS ARRAY_SIZE(viafb_all_gpios) | ||
67 | |||
68 | /* | ||
69 | * This structure controls the active GPIOs, which may be a subset | ||
70 | * of those which are known. | ||
71 | */ | ||
72 | |||
73 | struct viafb_gpio_cfg { | ||
74 | struct gpio_chip gpio_chip; | ||
75 | struct viafb_dev *vdev; | ||
76 | struct viafb_gpio *active_gpios[VIAFB_NUM_GPIOS]; | ||
77 | const char *gpio_names[VIAFB_NUM_GPIOS]; | ||
78 | }; | ||
79 | |||
80 | /* | ||
81 | * GPIO access functions | ||
82 | */ | ||
83 | static void via_gpio_set(struct gpio_chip *chip, unsigned int nr, | ||
84 | int value) | ||
85 | { | ||
86 | struct viafb_gpio_cfg *cfg = container_of(chip, | ||
87 | struct viafb_gpio_cfg, | ||
88 | gpio_chip); | ||
89 | u8 reg; | ||
90 | struct viafb_gpio *gpio; | ||
91 | unsigned long flags; | ||
92 | |||
93 | spin_lock_irqsave(&cfg->vdev->reg_lock, flags); | ||
94 | gpio = cfg->active_gpios[nr]; | ||
95 | reg = via_read_reg(VIASR, gpio->vg_port_index); | ||
96 | reg |= 0x40 << gpio->vg_mask_shift; /* output enable */ | ||
97 | if (value) | ||
98 | reg |= 0x10 << gpio->vg_mask_shift; | ||
99 | else | ||
100 | reg &= ~(0x10 << gpio->vg_mask_shift); | ||
101 | via_write_reg(VIASR, gpio->vg_port_index, reg); | ||
102 | spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); | ||
103 | } | ||
104 | |||
105 | static int via_gpio_dir_out(struct gpio_chip *chip, unsigned int nr, | ||
106 | int value) | ||
107 | { | ||
108 | via_gpio_set(chip, nr, value); | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Set the input direction. I'm not sure this is right; we should | ||
114 | * be able to do input without disabling output. | ||
115 | */ | ||
116 | static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr) | ||
117 | { | ||
118 | struct viafb_gpio_cfg *cfg = container_of(chip, | ||
119 | struct viafb_gpio_cfg, | ||
120 | gpio_chip); | ||
121 | struct viafb_gpio *gpio; | ||
122 | unsigned long flags; | ||
123 | |||
124 | spin_lock_irqsave(&cfg->vdev->reg_lock, flags); | ||
125 | gpio = cfg->active_gpios[nr]; | ||
126 | via_write_reg_mask(VIASR, gpio->vg_port_index, 0, | ||
127 | 0x40 << gpio->vg_mask_shift); | ||
128 | spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); | ||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int via_gpio_get(struct gpio_chip *chip, unsigned int nr) | ||
133 | { | ||
134 | struct viafb_gpio_cfg *cfg = container_of(chip, | ||
135 | struct viafb_gpio_cfg, | ||
136 | gpio_chip); | ||
137 | u8 reg; | ||
138 | struct viafb_gpio *gpio; | ||
139 | unsigned long flags; | ||
140 | |||
141 | spin_lock_irqsave(&cfg->vdev->reg_lock, flags); | ||
142 | gpio = cfg->active_gpios[nr]; | ||
143 | reg = via_read_reg(VIASR, gpio->vg_port_index); | ||
144 | spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); | ||
145 | return reg & (0x04 << gpio->vg_mask_shift); | ||
146 | } | ||
147 | |||
148 | |||
149 | static struct viafb_gpio_cfg viafb_gpio_config = { | ||
150 | .gpio_chip = { | ||
151 | .label = "VIAFB onboard GPIO", | ||
152 | .owner = THIS_MODULE, | ||
153 | .direction_output = via_gpio_dir_out, | ||
154 | .set = via_gpio_set, | ||
155 | .direction_input = via_gpio_dir_input, | ||
156 | .get = via_gpio_get, | ||
157 | .base = -1, | ||
158 | .ngpio = 0, | ||
159 | .can_sleep = 0 | ||
160 | } | ||
161 | }; | ||
162 | |||
163 | /* | ||
164 | * Manage the software enable bit. | ||
165 | */ | ||
166 | static void viafb_gpio_enable(struct viafb_gpio *gpio) | ||
167 | { | ||
168 | via_write_reg_mask(VIASR, gpio->vg_port_index, 0x02, 0x02); | ||
169 | } | ||
170 | |||
171 | static void viafb_gpio_disable(struct viafb_gpio *gpio) | ||
172 | { | ||
173 | via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02); | ||
174 | } | ||
175 | |||
176 | #ifdef CONFIG_PM | ||
177 | |||
178 | static int viafb_gpio_suspend(void *private) | ||
179 | { | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int viafb_gpio_resume(void *private) | ||
184 | { | ||
185 | int i; | ||
186 | |||
187 | for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2) | ||
188 | viafb_gpio_enable(viafb_gpio_config.active_gpios[i]); | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static struct viafb_pm_hooks viafb_gpio_pm_hooks = { | ||
193 | .suspend = viafb_gpio_suspend, | ||
194 | .resume = viafb_gpio_resume | ||
195 | }; | ||
196 | #endif /* CONFIG_PM */ | ||
197 | |||
198 | /* | ||
199 | * Look up a specific gpio and return the number it was assigned. | ||
200 | */ | ||
201 | int viafb_gpio_lookup(const char *name) | ||
202 | { | ||
203 | int i; | ||
204 | |||
205 | for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i++) | ||
206 | if (!strcmp(name, viafb_gpio_config.active_gpios[i]->vg_name)) | ||
207 | return viafb_gpio_config.gpio_chip.base + i; | ||
208 | return -1; | ||
209 | } | ||
210 | EXPORT_SYMBOL_GPL(viafb_gpio_lookup); | ||
211 | |||
212 | /* | ||
213 | * Platform device stuff. | ||
214 | */ | ||
215 | static int viafb_gpio_probe(struct platform_device *platdev) | ||
216 | { | ||
217 | struct viafb_dev *vdev = platdev->dev.platform_data; | ||
218 | struct via_port_cfg *port_cfg = vdev->port_cfg; | ||
219 | int i, ngpio = 0, ret; | ||
220 | struct viafb_gpio *gpio; | ||
221 | unsigned long flags; | ||
222 | |||
223 | /* | ||
224 | * Set up entries for all GPIOs which have been configured to | ||
225 | * operate as such (as opposed to as i2c ports). | ||
226 | */ | ||
227 | for (i = 0; i < VIAFB_NUM_PORTS; i++) { | ||
228 | if (port_cfg[i].mode != VIA_MODE_GPIO) | ||
229 | continue; | ||
230 | for (gpio = viafb_all_gpios; | ||
231 | gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++) | ||
232 | if (gpio->vg_port_index == port_cfg[i].ioport_index) { | ||
233 | viafb_gpio_config.active_gpios[ngpio] = gpio; | ||
234 | viafb_gpio_config.gpio_names[ngpio] = | ||
235 | gpio->vg_name; | ||
236 | ngpio++; | ||
237 | } | ||
238 | } | ||
239 | viafb_gpio_config.gpio_chip.ngpio = ngpio; | ||
240 | viafb_gpio_config.gpio_chip.names = viafb_gpio_config.gpio_names; | ||
241 | viafb_gpio_config.vdev = vdev; | ||
242 | if (ngpio == 0) { | ||
243 | printk(KERN_INFO "viafb: no GPIOs configured\n"); | ||
244 | return 0; | ||
245 | } | ||
246 | /* | ||
247 | * Enable the ports. They come in pairs, with a single | ||
248 | * enable bit for both. | ||
249 | */ | ||
250 | spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags); | ||
251 | for (i = 0; i < ngpio; i += 2) | ||
252 | viafb_gpio_enable(viafb_gpio_config.active_gpios[i]); | ||
253 | spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags); | ||
254 | /* | ||
255 | * Get registered. | ||
256 | */ | ||
257 | viafb_gpio_config.gpio_chip.base = -1; /* Dynamic */ | ||
258 | ret = gpiochip_add(&viafb_gpio_config.gpio_chip); | ||
259 | if (ret) { | ||
260 | printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret); | ||
261 | viafb_gpio_config.gpio_chip.ngpio = 0; | ||
262 | } | ||
263 | #ifdef CONFIG_PM | ||
264 | viafb_pm_register(&viafb_gpio_pm_hooks); | ||
265 | #endif | ||
266 | return ret; | ||
267 | } | ||
268 | |||
269 | |||
270 | static int viafb_gpio_remove(struct platform_device *platdev) | ||
271 | { | ||
272 | unsigned long flags; | ||
273 | int ret = 0, i; | ||
274 | |||
275 | #ifdef CONFIG_PM | ||
276 | viafb_pm_unregister(&viafb_gpio_pm_hooks); | ||
277 | #endif | ||
278 | |||
279 | /* | ||
280 | * Get unregistered. | ||
281 | */ | ||
282 | if (viafb_gpio_config.gpio_chip.ngpio > 0) { | ||
283 | ret = gpiochip_remove(&viafb_gpio_config.gpio_chip); | ||
284 | if (ret) { /* Somebody still using it? */ | ||
285 | printk(KERN_ERR "Viafb: GPIO remove failed\n"); | ||
286 | return ret; | ||
287 | } | ||
288 | } | ||
289 | /* | ||
290 | * Disable the ports. | ||
291 | */ | ||
292 | spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags); | ||
293 | for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2) | ||
294 | viafb_gpio_disable(viafb_gpio_config.active_gpios[i]); | ||
295 | viafb_gpio_config.gpio_chip.ngpio = 0; | ||
296 | spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags); | ||
297 | return ret; | ||
298 | } | ||
299 | |||
300 | static struct platform_driver via_gpio_driver = { | ||
301 | .driver = { | ||
302 | .name = "viafb-gpio", | ||
303 | }, | ||
304 | .probe = viafb_gpio_probe, | ||
305 | .remove = viafb_gpio_remove, | ||
306 | }; | ||
307 | |||
308 | int viafb_gpio_init(void) | ||
309 | { | ||
310 | return platform_driver_register(&via_gpio_driver); | ||
311 | } | ||
312 | |||
313 | void viafb_gpio_exit(void) | ||
314 | { | ||
315 | platform_driver_unregister(&via_gpio_driver); | ||
316 | } | ||
diff --git a/drivers/video/fbdev/via/via_aux.c b/drivers/video/fbdev/via/via_aux.c new file mode 100644 index 000000000000..4a0a55cdac3d --- /dev/null +++ b/drivers/video/fbdev/via/via_aux.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * infrastructure for devices connected via I2C | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | struct via_aux_bus *via_aux_probe(struct i2c_adapter *adap) | ||
29 | { | ||
30 | struct via_aux_bus *bus; | ||
31 | |||
32 | if (!adap) | ||
33 | return NULL; | ||
34 | |||
35 | bus = kmalloc(sizeof(*bus), GFP_KERNEL); | ||
36 | if (!bus) | ||
37 | return NULL; | ||
38 | |||
39 | bus->adap = adap; | ||
40 | INIT_LIST_HEAD(&bus->drivers); | ||
41 | |||
42 | via_aux_edid_probe(bus); | ||
43 | via_aux_vt1636_probe(bus); | ||
44 | via_aux_vt1632_probe(bus); | ||
45 | via_aux_vt1631_probe(bus); | ||
46 | via_aux_vt1625_probe(bus); | ||
47 | via_aux_vt1622_probe(bus); | ||
48 | via_aux_vt1621_probe(bus); | ||
49 | via_aux_sii164_probe(bus); | ||
50 | via_aux_ch7301_probe(bus); | ||
51 | |||
52 | return bus; | ||
53 | } | ||
54 | |||
55 | void via_aux_free(struct via_aux_bus *bus) | ||
56 | { | ||
57 | struct via_aux_drv *pos, *n; | ||
58 | |||
59 | if (!bus) | ||
60 | return; | ||
61 | |||
62 | list_for_each_entry_safe(pos, n, &bus->drivers, chain) { | ||
63 | if (pos->cleanup) | ||
64 | pos->cleanup(pos); | ||
65 | |||
66 | list_del(&pos->chain); | ||
67 | kfree(pos->data); | ||
68 | kfree(pos); | ||
69 | } | ||
70 | |||
71 | kfree(bus); | ||
72 | } | ||
73 | |||
74 | const struct fb_videomode *via_aux_get_preferred_mode(struct via_aux_bus *bus) | ||
75 | { | ||
76 | struct via_aux_drv *pos; | ||
77 | const struct fb_videomode *mode = NULL; | ||
78 | |||
79 | if (!bus) | ||
80 | return NULL; | ||
81 | |||
82 | list_for_each_entry(pos, &bus->drivers, chain) { | ||
83 | if (pos->get_preferred_mode) | ||
84 | mode = pos->get_preferred_mode(pos); | ||
85 | } | ||
86 | |||
87 | return mode; | ||
88 | } | ||
diff --git a/drivers/video/fbdev/via/via_aux.h b/drivers/video/fbdev/via/via_aux.h new file mode 100644 index 000000000000..a8de3f038cea --- /dev/null +++ b/drivers/video/fbdev/via/via_aux.h | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * infrastructure for devices connected via I2C | ||
22 | */ | ||
23 | |||
24 | #ifndef __VIA_AUX_H__ | ||
25 | #define __VIA_AUX_H__ | ||
26 | |||
27 | |||
28 | #include <linux/list.h> | ||
29 | #include <linux/i2c.h> | ||
30 | #include <linux/fb.h> | ||
31 | |||
32 | |||
33 | struct via_aux_bus { | ||
34 | struct i2c_adapter *adap; /* the I2C device to access the bus */ | ||
35 | struct list_head drivers; /* drivers for devices on this bus */ | ||
36 | }; | ||
37 | |||
38 | struct via_aux_drv { | ||
39 | struct list_head chain; /* chain to support multiple drivers */ | ||
40 | |||
41 | struct via_aux_bus *bus; /* the I2C bus used */ | ||
42 | u8 addr; /* the I2C slave address */ | ||
43 | |||
44 | const char *name; /* human readable name of the driver */ | ||
45 | void *data; /* private data of this driver */ | ||
46 | |||
47 | void (*cleanup)(struct via_aux_drv *drv); | ||
48 | const struct fb_videomode* (*get_preferred_mode) | ||
49 | (struct via_aux_drv *drv); | ||
50 | }; | ||
51 | |||
52 | |||
53 | struct via_aux_bus *via_aux_probe(struct i2c_adapter *adap); | ||
54 | void via_aux_free(struct via_aux_bus *bus); | ||
55 | const struct fb_videomode *via_aux_get_preferred_mode(struct via_aux_bus *bus); | ||
56 | |||
57 | |||
58 | static inline bool via_aux_add(struct via_aux_drv *drv) | ||
59 | { | ||
60 | struct via_aux_drv *data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
61 | |||
62 | if (!data) | ||
63 | return false; | ||
64 | |||
65 | *data = *drv; | ||
66 | list_add_tail(&data->chain, &data->bus->drivers); | ||
67 | return true; | ||
68 | } | ||
69 | |||
70 | static inline bool via_aux_read(struct via_aux_drv *drv, u8 start, u8 *buf, | ||
71 | u8 len) | ||
72 | { | ||
73 | struct i2c_msg msg[2] = { | ||
74 | {.addr = drv->addr, .flags = 0, .len = 1, .buf = &start}, | ||
75 | {.addr = drv->addr, .flags = I2C_M_RD, .len = len, .buf = buf} }; | ||
76 | |||
77 | return i2c_transfer(drv->bus->adap, msg, 2) == 2; | ||
78 | } | ||
79 | |||
80 | |||
81 | /* probe functions of existing drivers - should only be called in via_aux.c */ | ||
82 | void via_aux_ch7301_probe(struct via_aux_bus *bus); | ||
83 | void via_aux_edid_probe(struct via_aux_bus *bus); | ||
84 | void via_aux_sii164_probe(struct via_aux_bus *bus); | ||
85 | void via_aux_vt1636_probe(struct via_aux_bus *bus); | ||
86 | void via_aux_vt1632_probe(struct via_aux_bus *bus); | ||
87 | void via_aux_vt1631_probe(struct via_aux_bus *bus); | ||
88 | void via_aux_vt1625_probe(struct via_aux_bus *bus); | ||
89 | void via_aux_vt1622_probe(struct via_aux_bus *bus); | ||
90 | void via_aux_vt1621_probe(struct via_aux_bus *bus); | ||
91 | |||
92 | |||
93 | #endif /* __VIA_AUX_H__ */ | ||
diff --git a/drivers/video/fbdev/via/via_aux_ch7301.c b/drivers/video/fbdev/via/via_aux_ch7301.c new file mode 100644 index 000000000000..1cbe5037a6b0 --- /dev/null +++ b/drivers/video/fbdev/via/via_aux_ch7301.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for Chrontel CH7301 DVI Transmitter | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "CH7301 DVI Transmitter"; | ||
29 | |||
30 | |||
31 | static void probe(struct via_aux_bus *bus, u8 addr) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = addr, | ||
36 | .name = name}; | ||
37 | u8 tmp; | ||
38 | |||
39 | if (!via_aux_read(&drv, 0x4B, &tmp, 1) || tmp != 0x17) | ||
40 | return; | ||
41 | |||
42 | printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr); | ||
43 | via_aux_add(&drv); | ||
44 | } | ||
45 | |||
46 | void via_aux_ch7301_probe(struct via_aux_bus *bus) | ||
47 | { | ||
48 | probe(bus, 0x75); | ||
49 | probe(bus, 0x76); | ||
50 | } | ||
diff --git a/drivers/video/fbdev/via/via_aux_edid.c b/drivers/video/fbdev/via/via_aux_edid.c new file mode 100644 index 000000000000..754d4509033f --- /dev/null +++ b/drivers/video/fbdev/via/via_aux_edid.c | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * generic EDID driver | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include <linux/fb.h> | ||
26 | #include "via_aux.h" | ||
27 | #include "../edid.h" | ||
28 | |||
29 | |||
30 | static const char *name = "EDID"; | ||
31 | |||
32 | |||
33 | static void query_edid(struct via_aux_drv *drv) | ||
34 | { | ||
35 | struct fb_monspecs *spec = drv->data; | ||
36 | unsigned char edid[EDID_LENGTH]; | ||
37 | bool valid = false; | ||
38 | |||
39 | if (spec) { | ||
40 | fb_destroy_modedb(spec->modedb); | ||
41 | } else { | ||
42 | spec = kmalloc(sizeof(*spec), GFP_KERNEL); | ||
43 | if (!spec) | ||
44 | return; | ||
45 | } | ||
46 | |||
47 | spec->version = spec->revision = 0; | ||
48 | if (via_aux_read(drv, 0x00, edid, EDID_LENGTH)) { | ||
49 | fb_edid_to_monspecs(edid, spec); | ||
50 | valid = spec->version || spec->revision; | ||
51 | } | ||
52 | |||
53 | if (!valid) { | ||
54 | kfree(spec); | ||
55 | spec = NULL; | ||
56 | } else | ||
57 | printk(KERN_DEBUG "EDID: %s %s\n", spec->manufacturer, spec->monitor); | ||
58 | |||
59 | drv->data = spec; | ||
60 | } | ||
61 | |||
62 | static const struct fb_videomode *get_preferred_mode(struct via_aux_drv *drv) | ||
63 | { | ||
64 | struct fb_monspecs *spec = drv->data; | ||
65 | int i; | ||
66 | |||
67 | if (!spec || !spec->modedb || !(spec->misc & FB_MISC_1ST_DETAIL)) | ||
68 | return NULL; | ||
69 | |||
70 | for (i = 0; i < spec->modedb_len; i++) { | ||
71 | if (spec->modedb[i].flag & FB_MODE_IS_FIRST && | ||
72 | spec->modedb[i].flag & FB_MODE_IS_DETAILED) | ||
73 | return &spec->modedb[i]; | ||
74 | } | ||
75 | |||
76 | return NULL; | ||
77 | } | ||
78 | |||
79 | static void cleanup(struct via_aux_drv *drv) | ||
80 | { | ||
81 | struct fb_monspecs *spec = drv->data; | ||
82 | |||
83 | if (spec) | ||
84 | fb_destroy_modedb(spec->modedb); | ||
85 | } | ||
86 | |||
87 | void via_aux_edid_probe(struct via_aux_bus *bus) | ||
88 | { | ||
89 | struct via_aux_drv drv = { | ||
90 | .bus = bus, | ||
91 | .addr = 0x50, | ||
92 | .name = name, | ||
93 | .cleanup = cleanup, | ||
94 | .get_preferred_mode = get_preferred_mode}; | ||
95 | |||
96 | query_edid(&drv); | ||
97 | |||
98 | /* as EDID devices can be connected/disconnected just add the driver */ | ||
99 | via_aux_add(&drv); | ||
100 | } | ||
diff --git a/drivers/video/fbdev/via/via_aux_sii164.c b/drivers/video/fbdev/via/via_aux_sii164.c new file mode 100644 index 000000000000..ca1b35f033b1 --- /dev/null +++ b/drivers/video/fbdev/via/via_aux_sii164.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for Silicon Image SiI 164 PanelLink Transmitter | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "SiI 164 PanelLink Transmitter"; | ||
29 | |||
30 | |||
31 | static void probe(struct via_aux_bus *bus, u8 addr) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = addr, | ||
36 | .name = name}; | ||
37 | /* check vendor id and device id */ | ||
38 | const u8 id[] = {0x01, 0x00, 0x06, 0x00}, len = ARRAY_SIZE(id); | ||
39 | u8 tmp[len]; | ||
40 | |||
41 | if (!via_aux_read(&drv, 0x00, tmp, len) || memcmp(id, tmp, len)) | ||
42 | return; | ||
43 | |||
44 | printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr); | ||
45 | via_aux_add(&drv); | ||
46 | } | ||
47 | |||
48 | void via_aux_sii164_probe(struct via_aux_bus *bus) | ||
49 | { | ||
50 | u8 i; | ||
51 | |||
52 | for (i = 0x38; i <= 0x3F; i++) | ||
53 | probe(bus, i); | ||
54 | } | ||
diff --git a/drivers/video/fbdev/via/via_aux_vt1621.c b/drivers/video/fbdev/via/via_aux_vt1621.c new file mode 100644 index 000000000000..38eca8479898 --- /dev/null +++ b/drivers/video/fbdev/via/via_aux_vt1621.c | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for VIA VT1621(M) TV Encoder | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "VT1621(M) TV Encoder"; | ||
29 | |||
30 | |||
31 | void via_aux_vt1621_probe(struct via_aux_bus *bus) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = 0x20, | ||
36 | .name = name}; | ||
37 | u8 tmp; | ||
38 | |||
39 | if (!via_aux_read(&drv, 0x1B, &tmp, 1) || tmp != 0x02) | ||
40 | return; | ||
41 | |||
42 | printk(KERN_INFO "viafb: Found %s\n", name); | ||
43 | via_aux_add(&drv); | ||
44 | } | ||
diff --git a/drivers/video/fbdev/via/via_aux_vt1622.c b/drivers/video/fbdev/via/via_aux_vt1622.c new file mode 100644 index 000000000000..8c79c68ba683 --- /dev/null +++ b/drivers/video/fbdev/via/via_aux_vt1622.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for VIA VT1622(M) Digital TV Encoder | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "VT1622(M) Digital TV Encoder"; | ||
29 | |||
30 | |||
31 | static void probe(struct via_aux_bus *bus, u8 addr) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = addr, | ||
36 | .name = name}; | ||
37 | u8 tmp; | ||
38 | |||
39 | if (!via_aux_read(&drv, 0x1B, &tmp, 1) || tmp != 0x03) | ||
40 | return; | ||
41 | |||
42 | printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr); | ||
43 | via_aux_add(&drv); | ||
44 | } | ||
45 | |||
46 | void via_aux_vt1622_probe(struct via_aux_bus *bus) | ||
47 | { | ||
48 | probe(bus, 0x20); | ||
49 | probe(bus, 0x21); | ||
50 | } | ||
diff --git a/drivers/video/fbdev/via/via_aux_vt1625.c b/drivers/video/fbdev/via/via_aux_vt1625.c new file mode 100644 index 000000000000..03eb30165d36 --- /dev/null +++ b/drivers/video/fbdev/via/via_aux_vt1625.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for VIA VT1625(M) HDTV Encoder | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "VT1625(M) HDTV Encoder"; | ||
29 | |||
30 | |||
31 | static void probe(struct via_aux_bus *bus, u8 addr) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = addr, | ||
36 | .name = name}; | ||
37 | u8 tmp; | ||
38 | |||
39 | if (!via_aux_read(&drv, 0x1B, &tmp, 1) || tmp != 0x50) | ||
40 | return; | ||
41 | |||
42 | printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr); | ||
43 | via_aux_add(&drv); | ||
44 | } | ||
45 | |||
46 | void via_aux_vt1625_probe(struct via_aux_bus *bus) | ||
47 | { | ||
48 | probe(bus, 0x20); | ||
49 | probe(bus, 0x21); | ||
50 | } | ||
diff --git a/drivers/video/fbdev/via/via_aux_vt1631.c b/drivers/video/fbdev/via/via_aux_vt1631.c new file mode 100644 index 000000000000..06e742f1f723 --- /dev/null +++ b/drivers/video/fbdev/via/via_aux_vt1631.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for VIA VT1631 LVDS Transmitter | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "VT1631 LVDS Transmitter"; | ||
29 | |||
30 | |||
31 | void via_aux_vt1631_probe(struct via_aux_bus *bus) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = 0x38, | ||
36 | .name = name}; | ||
37 | /* check vendor id and device id */ | ||
38 | const u8 id[] = {0x06, 0x11, 0x91, 0x31}, len = ARRAY_SIZE(id); | ||
39 | u8 tmp[len]; | ||
40 | |||
41 | if (!via_aux_read(&drv, 0x00, tmp, len) || memcmp(id, tmp, len)) | ||
42 | return; | ||
43 | |||
44 | printk(KERN_INFO "viafb: Found %s\n", name); | ||
45 | via_aux_add(&drv); | ||
46 | } | ||
diff --git a/drivers/video/fbdev/via/via_aux_vt1632.c b/drivers/video/fbdev/via/via_aux_vt1632.c new file mode 100644 index 000000000000..d24f4cd97401 --- /dev/null +++ b/drivers/video/fbdev/via/via_aux_vt1632.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for VIA VT1632 DVI Transmitter | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "VT1632 DVI Transmitter"; | ||
29 | |||
30 | |||
31 | static void probe(struct via_aux_bus *bus, u8 addr) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = addr, | ||
36 | .name = name}; | ||
37 | /* check vendor id and device id */ | ||
38 | const u8 id[] = {0x06, 0x11, 0x92, 0x31}, len = ARRAY_SIZE(id); | ||
39 | u8 tmp[len]; | ||
40 | |||
41 | if (!via_aux_read(&drv, 0x00, tmp, len) || memcmp(id, tmp, len)) | ||
42 | return; | ||
43 | |||
44 | printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr); | ||
45 | via_aux_add(&drv); | ||
46 | } | ||
47 | |||
48 | void via_aux_vt1632_probe(struct via_aux_bus *bus) | ||
49 | { | ||
50 | u8 i; | ||
51 | |||
52 | for (i = 0x08; i <= 0x0F; i++) | ||
53 | probe(bus, i); | ||
54 | } | ||
diff --git a/drivers/video/fbdev/via/via_aux_vt1636.c b/drivers/video/fbdev/via/via_aux_vt1636.c new file mode 100644 index 000000000000..9e015c101d4d --- /dev/null +++ b/drivers/video/fbdev/via/via_aux_vt1636.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for VIA VT1636 LVDS Transmitter | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "VT1636 LVDS Transmitter"; | ||
29 | |||
30 | |||
31 | void via_aux_vt1636_probe(struct via_aux_bus *bus) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = 0x40, | ||
36 | .name = name}; | ||
37 | /* check vendor id and device id */ | ||
38 | const u8 id[] = {0x06, 0x11, 0x45, 0x33}, len = ARRAY_SIZE(id); | ||
39 | u8 tmp[len]; | ||
40 | |||
41 | if (!via_aux_read(&drv, 0x00, tmp, len) || memcmp(id, tmp, len)) | ||
42 | return; | ||
43 | |||
44 | printk(KERN_INFO "viafb: Found %s\n", name); | ||
45 | via_aux_add(&drv); | ||
46 | } | ||
diff --git a/drivers/video/fbdev/via/via_clock.c b/drivers/video/fbdev/via/via_clock.c new file mode 100644 index 000000000000..db1e39277e32 --- /dev/null +++ b/drivers/video/fbdev/via/via_clock.c | |||
@@ -0,0 +1,368 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public | ||
8 | * License as published by the Free Software Foundation; | ||
9 | * either version 2, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
14 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
15 | * for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., | ||
20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | /* | ||
23 | * clock and PLL management functions | ||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/via-core.h> | ||
28 | #include <asm/olpc.h> | ||
29 | #include "via_clock.h" | ||
30 | #include "global.h" | ||
31 | #include "debug.h" | ||
32 | |||
33 | const char *via_slap = "Please slap VIA Technologies to motivate them " | ||
34 | "releasing full documentation for your platform!\n"; | ||
35 | |||
36 | static inline u32 cle266_encode_pll(struct via_pll_config pll) | ||
37 | { | ||
38 | return (pll.multiplier << 8) | ||
39 | | (pll.rshift << 6) | ||
40 | | pll.divisor; | ||
41 | } | ||
42 | |||
43 | static inline u32 k800_encode_pll(struct via_pll_config pll) | ||
44 | { | ||
45 | return ((pll.divisor - 2) << 16) | ||
46 | | (pll.rshift << 10) | ||
47 | | (pll.multiplier - 2); | ||
48 | } | ||
49 | |||
50 | static inline u32 vx855_encode_pll(struct via_pll_config pll) | ||
51 | { | ||
52 | return (pll.divisor << 16) | ||
53 | | (pll.rshift << 10) | ||
54 | | pll.multiplier; | ||
55 | } | ||
56 | |||
57 | static inline void cle266_set_primary_pll_encoded(u32 data) | ||
58 | { | ||
59 | via_write_reg_mask(VIASR, 0x40, 0x02, 0x02); /* enable reset */ | ||
60 | via_write_reg(VIASR, 0x46, data & 0xFF); | ||
61 | via_write_reg(VIASR, 0x47, (data >> 8) & 0xFF); | ||
62 | via_write_reg_mask(VIASR, 0x40, 0x00, 0x02); /* disable reset */ | ||
63 | } | ||
64 | |||
65 | static inline void k800_set_primary_pll_encoded(u32 data) | ||
66 | { | ||
67 | via_write_reg_mask(VIASR, 0x40, 0x02, 0x02); /* enable reset */ | ||
68 | via_write_reg(VIASR, 0x44, data & 0xFF); | ||
69 | via_write_reg(VIASR, 0x45, (data >> 8) & 0xFF); | ||
70 | via_write_reg(VIASR, 0x46, (data >> 16) & 0xFF); | ||
71 | via_write_reg_mask(VIASR, 0x40, 0x00, 0x02); /* disable reset */ | ||
72 | } | ||
73 | |||
74 | static inline void cle266_set_secondary_pll_encoded(u32 data) | ||
75 | { | ||
76 | via_write_reg_mask(VIASR, 0x40, 0x04, 0x04); /* enable reset */ | ||
77 | via_write_reg(VIASR, 0x44, data & 0xFF); | ||
78 | via_write_reg(VIASR, 0x45, (data >> 8) & 0xFF); | ||
79 | via_write_reg_mask(VIASR, 0x40, 0x00, 0x04); /* disable reset */ | ||
80 | } | ||
81 | |||
82 | static inline void k800_set_secondary_pll_encoded(u32 data) | ||
83 | { | ||
84 | via_write_reg_mask(VIASR, 0x40, 0x04, 0x04); /* enable reset */ | ||
85 | via_write_reg(VIASR, 0x4A, data & 0xFF); | ||
86 | via_write_reg(VIASR, 0x4B, (data >> 8) & 0xFF); | ||
87 | via_write_reg(VIASR, 0x4C, (data >> 16) & 0xFF); | ||
88 | via_write_reg_mask(VIASR, 0x40, 0x00, 0x04); /* disable reset */ | ||
89 | } | ||
90 | |||
91 | static inline void set_engine_pll_encoded(u32 data) | ||
92 | { | ||
93 | via_write_reg_mask(VIASR, 0x40, 0x01, 0x01); /* enable reset */ | ||
94 | via_write_reg(VIASR, 0x47, data & 0xFF); | ||
95 | via_write_reg(VIASR, 0x48, (data >> 8) & 0xFF); | ||
96 | via_write_reg(VIASR, 0x49, (data >> 16) & 0xFF); | ||
97 | via_write_reg_mask(VIASR, 0x40, 0x00, 0x01); /* disable reset */ | ||
98 | } | ||
99 | |||
100 | static void cle266_set_primary_pll(struct via_pll_config config) | ||
101 | { | ||
102 | cle266_set_primary_pll_encoded(cle266_encode_pll(config)); | ||
103 | } | ||
104 | |||
105 | static void k800_set_primary_pll(struct via_pll_config config) | ||
106 | { | ||
107 | k800_set_primary_pll_encoded(k800_encode_pll(config)); | ||
108 | } | ||
109 | |||
110 | static void vx855_set_primary_pll(struct via_pll_config config) | ||
111 | { | ||
112 | k800_set_primary_pll_encoded(vx855_encode_pll(config)); | ||
113 | } | ||
114 | |||
115 | static void cle266_set_secondary_pll(struct via_pll_config config) | ||
116 | { | ||
117 | cle266_set_secondary_pll_encoded(cle266_encode_pll(config)); | ||
118 | } | ||
119 | |||
120 | static void k800_set_secondary_pll(struct via_pll_config config) | ||
121 | { | ||
122 | k800_set_secondary_pll_encoded(k800_encode_pll(config)); | ||
123 | } | ||
124 | |||
125 | static void vx855_set_secondary_pll(struct via_pll_config config) | ||
126 | { | ||
127 | k800_set_secondary_pll_encoded(vx855_encode_pll(config)); | ||
128 | } | ||
129 | |||
130 | static void k800_set_engine_pll(struct via_pll_config config) | ||
131 | { | ||
132 | set_engine_pll_encoded(k800_encode_pll(config)); | ||
133 | } | ||
134 | |||
135 | static void vx855_set_engine_pll(struct via_pll_config config) | ||
136 | { | ||
137 | set_engine_pll_encoded(vx855_encode_pll(config)); | ||
138 | } | ||
139 | |||
140 | static void set_primary_pll_state(u8 state) | ||
141 | { | ||
142 | u8 value; | ||
143 | |||
144 | switch (state) { | ||
145 | case VIA_STATE_ON: | ||
146 | value = 0x20; | ||
147 | break; | ||
148 | case VIA_STATE_OFF: | ||
149 | value = 0x00; | ||
150 | break; | ||
151 | default: | ||
152 | return; | ||
153 | } | ||
154 | |||
155 | via_write_reg_mask(VIASR, 0x2D, value, 0x30); | ||
156 | } | ||
157 | |||
158 | static void set_secondary_pll_state(u8 state) | ||
159 | { | ||
160 | u8 value; | ||
161 | |||
162 | switch (state) { | ||
163 | case VIA_STATE_ON: | ||
164 | value = 0x08; | ||
165 | break; | ||
166 | case VIA_STATE_OFF: | ||
167 | value = 0x00; | ||
168 | break; | ||
169 | default: | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | via_write_reg_mask(VIASR, 0x2D, value, 0x0C); | ||
174 | } | ||
175 | |||
176 | static void set_engine_pll_state(u8 state) | ||
177 | { | ||
178 | u8 value; | ||
179 | |||
180 | switch (state) { | ||
181 | case VIA_STATE_ON: | ||
182 | value = 0x02; | ||
183 | break; | ||
184 | case VIA_STATE_OFF: | ||
185 | value = 0x00; | ||
186 | break; | ||
187 | default: | ||
188 | return; | ||
189 | } | ||
190 | |||
191 | via_write_reg_mask(VIASR, 0x2D, value, 0x03); | ||
192 | } | ||
193 | |||
194 | static void set_primary_clock_state(u8 state) | ||
195 | { | ||
196 | u8 value; | ||
197 | |||
198 | switch (state) { | ||
199 | case VIA_STATE_ON: | ||
200 | value = 0x20; | ||
201 | break; | ||
202 | case VIA_STATE_OFF: | ||
203 | value = 0x00; | ||
204 | break; | ||
205 | default: | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | via_write_reg_mask(VIASR, 0x1B, value, 0x30); | ||
210 | } | ||
211 | |||
212 | static void set_secondary_clock_state(u8 state) | ||
213 | { | ||
214 | u8 value; | ||
215 | |||
216 | switch (state) { | ||
217 | case VIA_STATE_ON: | ||
218 | value = 0x80; | ||
219 | break; | ||
220 | case VIA_STATE_OFF: | ||
221 | value = 0x00; | ||
222 | break; | ||
223 | default: | ||
224 | return; | ||
225 | } | ||
226 | |||
227 | via_write_reg_mask(VIASR, 0x1B, value, 0xC0); | ||
228 | } | ||
229 | |||
230 | static inline u8 set_clock_source_common(enum via_clksrc source, bool use_pll) | ||
231 | { | ||
232 | u8 data = 0; | ||
233 | |||
234 | switch (source) { | ||
235 | case VIA_CLKSRC_X1: | ||
236 | data = 0x00; | ||
237 | break; | ||
238 | case VIA_CLKSRC_TVX1: | ||
239 | data = 0x02; | ||
240 | break; | ||
241 | case VIA_CLKSRC_TVPLL: | ||
242 | data = 0x04; /* 0x06 should be the same */ | ||
243 | break; | ||
244 | case VIA_CLKSRC_DVP1TVCLKR: | ||
245 | data = 0x0A; | ||
246 | break; | ||
247 | case VIA_CLKSRC_CAP0: | ||
248 | data = 0xC; | ||
249 | break; | ||
250 | case VIA_CLKSRC_CAP1: | ||
251 | data = 0x0E; | ||
252 | break; | ||
253 | } | ||
254 | |||
255 | if (!use_pll) | ||
256 | data |= 1; | ||
257 | |||
258 | return data; | ||
259 | } | ||
260 | |||
261 | static void set_primary_clock_source(enum via_clksrc source, bool use_pll) | ||
262 | { | ||
263 | u8 data = set_clock_source_common(source, use_pll) << 4; | ||
264 | via_write_reg_mask(VIACR, 0x6C, data, 0xF0); | ||
265 | } | ||
266 | |||
267 | static void set_secondary_clock_source(enum via_clksrc source, bool use_pll) | ||
268 | { | ||
269 | u8 data = set_clock_source_common(source, use_pll); | ||
270 | via_write_reg_mask(VIACR, 0x6C, data, 0x0F); | ||
271 | } | ||
272 | |||
273 | static void dummy_set_clock_state(u8 state) | ||
274 | { | ||
275 | printk(KERN_INFO "Using undocumented set clock state.\n%s", via_slap); | ||
276 | } | ||
277 | |||
278 | static void dummy_set_clock_source(enum via_clksrc source, bool use_pll) | ||
279 | { | ||
280 | printk(KERN_INFO "Using undocumented set clock source.\n%s", via_slap); | ||
281 | } | ||
282 | |||
283 | static void dummy_set_pll_state(u8 state) | ||
284 | { | ||
285 | printk(KERN_INFO "Using undocumented set PLL state.\n%s", via_slap); | ||
286 | } | ||
287 | |||
288 | static void dummy_set_pll(struct via_pll_config config) | ||
289 | { | ||
290 | printk(KERN_INFO "Using undocumented set PLL.\n%s", via_slap); | ||
291 | } | ||
292 | |||
293 | static void noop_set_clock_state(u8 state) | ||
294 | { | ||
295 | } | ||
296 | |||
297 | void via_clock_init(struct via_clock *clock, int gfx_chip) | ||
298 | { | ||
299 | switch (gfx_chip) { | ||
300 | case UNICHROME_CLE266: | ||
301 | case UNICHROME_K400: | ||
302 | clock->set_primary_clock_state = dummy_set_clock_state; | ||
303 | clock->set_primary_clock_source = dummy_set_clock_source; | ||
304 | clock->set_primary_pll_state = dummy_set_pll_state; | ||
305 | clock->set_primary_pll = cle266_set_primary_pll; | ||
306 | |||
307 | clock->set_secondary_clock_state = dummy_set_clock_state; | ||
308 | clock->set_secondary_clock_source = dummy_set_clock_source; | ||
309 | clock->set_secondary_pll_state = dummy_set_pll_state; | ||
310 | clock->set_secondary_pll = cle266_set_secondary_pll; | ||
311 | |||
312 | clock->set_engine_pll_state = dummy_set_pll_state; | ||
313 | clock->set_engine_pll = dummy_set_pll; | ||
314 | break; | ||
315 | case UNICHROME_K800: | ||
316 | case UNICHROME_PM800: | ||
317 | case UNICHROME_CN700: | ||
318 | case UNICHROME_CX700: | ||
319 | case UNICHROME_CN750: | ||
320 | case UNICHROME_K8M890: | ||
321 | case UNICHROME_P4M890: | ||
322 | case UNICHROME_P4M900: | ||
323 | case UNICHROME_VX800: | ||
324 | clock->set_primary_clock_state = set_primary_clock_state; | ||
325 | clock->set_primary_clock_source = set_primary_clock_source; | ||
326 | clock->set_primary_pll_state = set_primary_pll_state; | ||
327 | clock->set_primary_pll = k800_set_primary_pll; | ||
328 | |||
329 | clock->set_secondary_clock_state = set_secondary_clock_state; | ||
330 | clock->set_secondary_clock_source = set_secondary_clock_source; | ||
331 | clock->set_secondary_pll_state = set_secondary_pll_state; | ||
332 | clock->set_secondary_pll = k800_set_secondary_pll; | ||
333 | |||
334 | clock->set_engine_pll_state = set_engine_pll_state; | ||
335 | clock->set_engine_pll = k800_set_engine_pll; | ||
336 | break; | ||
337 | case UNICHROME_VX855: | ||
338 | case UNICHROME_VX900: | ||
339 | clock->set_primary_clock_state = set_primary_clock_state; | ||
340 | clock->set_primary_clock_source = set_primary_clock_source; | ||
341 | clock->set_primary_pll_state = set_primary_pll_state; | ||
342 | clock->set_primary_pll = vx855_set_primary_pll; | ||
343 | |||
344 | clock->set_secondary_clock_state = set_secondary_clock_state; | ||
345 | clock->set_secondary_clock_source = set_secondary_clock_source; | ||
346 | clock->set_secondary_pll_state = set_secondary_pll_state; | ||
347 | clock->set_secondary_pll = vx855_set_secondary_pll; | ||
348 | |||
349 | clock->set_engine_pll_state = set_engine_pll_state; | ||
350 | clock->set_engine_pll = vx855_set_engine_pll; | ||
351 | break; | ||
352 | |||
353 | } | ||
354 | |||
355 | if (machine_is_olpc()) { | ||
356 | /* The OLPC XO-1.5 cannot suspend/resume reliably if the | ||
357 | * IGA1/IGA2 clocks are set as on or off (memory rot | ||
358 | * occasionally happens during suspend under such | ||
359 | * configurations). | ||
360 | * | ||
361 | * The only known stable scenario is to leave this bits as-is, | ||
362 | * which in their default states are documented to enable the | ||
363 | * clock only when it is needed. | ||
364 | */ | ||
365 | clock->set_primary_clock_state = noop_set_clock_state; | ||
366 | clock->set_secondary_clock_state = noop_set_clock_state; | ||
367 | } | ||
368 | } | ||
diff --git a/drivers/video/fbdev/via/via_clock.h b/drivers/video/fbdev/via/via_clock.h new file mode 100644 index 000000000000..88714ae0d157 --- /dev/null +++ b/drivers/video/fbdev/via/via_clock.h | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public | ||
8 | * License as published by the Free Software Foundation; | ||
9 | * either version 2, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
14 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
15 | * for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., | ||
20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | /* | ||
23 | * clock and PLL management functions | ||
24 | */ | ||
25 | |||
26 | #ifndef __VIA_CLOCK_H__ | ||
27 | #define __VIA_CLOCK_H__ | ||
28 | |||
29 | #include <linux/types.h> | ||
30 | |||
31 | enum via_clksrc { | ||
32 | VIA_CLKSRC_X1 = 0, | ||
33 | VIA_CLKSRC_TVX1, | ||
34 | VIA_CLKSRC_TVPLL, | ||
35 | VIA_CLKSRC_DVP1TVCLKR, | ||
36 | VIA_CLKSRC_CAP0, | ||
37 | VIA_CLKSRC_CAP1, | ||
38 | }; | ||
39 | |||
40 | struct via_pll_config { | ||
41 | u16 multiplier; | ||
42 | u8 divisor; | ||
43 | u8 rshift; | ||
44 | }; | ||
45 | |||
46 | struct via_clock { | ||
47 | void (*set_primary_clock_state)(u8 state); | ||
48 | void (*set_primary_clock_source)(enum via_clksrc src, bool use_pll); | ||
49 | void (*set_primary_pll_state)(u8 state); | ||
50 | void (*set_primary_pll)(struct via_pll_config config); | ||
51 | |||
52 | void (*set_secondary_clock_state)(u8 state); | ||
53 | void (*set_secondary_clock_source)(enum via_clksrc src, bool use_pll); | ||
54 | void (*set_secondary_pll_state)(u8 state); | ||
55 | void (*set_secondary_pll)(struct via_pll_config config); | ||
56 | |||
57 | void (*set_engine_pll_state)(u8 state); | ||
58 | void (*set_engine_pll)(struct via_pll_config config); | ||
59 | }; | ||
60 | |||
61 | |||
62 | static inline u32 get_pll_internal_frequency(u32 ref_freq, | ||
63 | struct via_pll_config pll) | ||
64 | { | ||
65 | return ref_freq / pll.divisor * pll.multiplier; | ||
66 | } | ||
67 | |||
68 | static inline u32 get_pll_output_frequency(u32 ref_freq, | ||
69 | struct via_pll_config pll) | ||
70 | { | ||
71 | return get_pll_internal_frequency(ref_freq, pll) >> pll.rshift; | ||
72 | } | ||
73 | |||
74 | void via_clock_init(struct via_clock *clock, int gfx_chip); | ||
75 | |||
76 | #endif /* __VIA_CLOCK_H__ */ | ||
diff --git a/drivers/video/fbdev/via/via_i2c.c b/drivers/video/fbdev/via/via_i2c.c new file mode 100644 index 000000000000..dd53058bbbb7 --- /dev/null +++ b/drivers/video/fbdev/via/via_i2c.c | |||
@@ -0,0 +1,295 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/spinlock.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/via-core.h> | ||
27 | #include <linux/via_i2c.h> | ||
28 | |||
29 | /* | ||
30 | * There can only be one set of these, so there's no point in having | ||
31 | * them be dynamically allocated... | ||
32 | */ | ||
33 | #define VIAFB_NUM_I2C 5 | ||
34 | static struct via_i2c_stuff via_i2c_par[VIAFB_NUM_I2C]; | ||
35 | static struct viafb_dev *i2c_vdev; /* Passed in from core */ | ||
36 | |||
37 | static void via_i2c_setscl(void *data, int state) | ||
38 | { | ||
39 | u8 val; | ||
40 | struct via_port_cfg *adap_data = data; | ||
41 | unsigned long flags; | ||
42 | |||
43 | spin_lock_irqsave(&i2c_vdev->reg_lock, flags); | ||
44 | val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0; | ||
45 | if (state) | ||
46 | val |= 0x20; | ||
47 | else | ||
48 | val &= ~0x20; | ||
49 | switch (adap_data->type) { | ||
50 | case VIA_PORT_I2C: | ||
51 | val |= 0x01; | ||
52 | break; | ||
53 | case VIA_PORT_GPIO: | ||
54 | val |= 0x82; | ||
55 | break; | ||
56 | default: | ||
57 | printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n"); | ||
58 | } | ||
59 | via_write_reg(adap_data->io_port, adap_data->ioport_index, val); | ||
60 | spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); | ||
61 | } | ||
62 | |||
63 | static int via_i2c_getscl(void *data) | ||
64 | { | ||
65 | struct via_port_cfg *adap_data = data; | ||
66 | unsigned long flags; | ||
67 | int ret = 0; | ||
68 | |||
69 | spin_lock_irqsave(&i2c_vdev->reg_lock, flags); | ||
70 | if (adap_data->type == VIA_PORT_GPIO) | ||
71 | via_write_reg_mask(adap_data->io_port, adap_data->ioport_index, | ||
72 | 0, 0x80); | ||
73 | if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08) | ||
74 | ret = 1; | ||
75 | spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); | ||
76 | return ret; | ||
77 | } | ||
78 | |||
79 | static int via_i2c_getsda(void *data) | ||
80 | { | ||
81 | struct via_port_cfg *adap_data = data; | ||
82 | unsigned long flags; | ||
83 | int ret = 0; | ||
84 | |||
85 | spin_lock_irqsave(&i2c_vdev->reg_lock, flags); | ||
86 | if (adap_data->type == VIA_PORT_GPIO) | ||
87 | via_write_reg_mask(adap_data->io_port, adap_data->ioport_index, | ||
88 | 0, 0x40); | ||
89 | if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04) | ||
90 | ret = 1; | ||
91 | spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); | ||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | static void via_i2c_setsda(void *data, int state) | ||
96 | { | ||
97 | u8 val; | ||
98 | struct via_port_cfg *adap_data = data; | ||
99 | unsigned long flags; | ||
100 | |||
101 | spin_lock_irqsave(&i2c_vdev->reg_lock, flags); | ||
102 | val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0; | ||
103 | if (state) | ||
104 | val |= 0x10; | ||
105 | else | ||
106 | val &= ~0x10; | ||
107 | switch (adap_data->type) { | ||
108 | case VIA_PORT_I2C: | ||
109 | val |= 0x01; | ||
110 | break; | ||
111 | case VIA_PORT_GPIO: | ||
112 | val |= 0x42; | ||
113 | break; | ||
114 | default: | ||
115 | printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n"); | ||
116 | } | ||
117 | via_write_reg(adap_data->io_port, adap_data->ioport_index, val); | ||
118 | spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); | ||
119 | } | ||
120 | |||
121 | int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata) | ||
122 | { | ||
123 | int ret; | ||
124 | u8 mm1[] = {0x00}; | ||
125 | struct i2c_msg msgs[2]; | ||
126 | |||
127 | if (!via_i2c_par[adap].is_active) | ||
128 | return -ENODEV; | ||
129 | *pdata = 0; | ||
130 | msgs[0].flags = 0; | ||
131 | msgs[1].flags = I2C_M_RD; | ||
132 | msgs[0].addr = msgs[1].addr = slave_addr / 2; | ||
133 | mm1[0] = index; | ||
134 | msgs[0].len = 1; msgs[1].len = 1; | ||
135 | msgs[0].buf = mm1; msgs[1].buf = pdata; | ||
136 | ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); | ||
137 | if (ret == 2) | ||
138 | ret = 0; | ||
139 | else if (ret >= 0) | ||
140 | ret = -EIO; | ||
141 | |||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data) | ||
146 | { | ||
147 | int ret; | ||
148 | u8 msg[2] = { index, data }; | ||
149 | struct i2c_msg msgs; | ||
150 | |||
151 | if (!via_i2c_par[adap].is_active) | ||
152 | return -ENODEV; | ||
153 | msgs.flags = 0; | ||
154 | msgs.addr = slave_addr / 2; | ||
155 | msgs.len = 2; | ||
156 | msgs.buf = msg; | ||
157 | ret = i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1); | ||
158 | if (ret == 1) | ||
159 | ret = 0; | ||
160 | else if (ret >= 0) | ||
161 | ret = -EIO; | ||
162 | |||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len) | ||
167 | { | ||
168 | int ret; | ||
169 | u8 mm1[] = {0x00}; | ||
170 | struct i2c_msg msgs[2]; | ||
171 | |||
172 | if (!via_i2c_par[adap].is_active) | ||
173 | return -ENODEV; | ||
174 | msgs[0].flags = 0; | ||
175 | msgs[1].flags = I2C_M_RD; | ||
176 | msgs[0].addr = msgs[1].addr = slave_addr / 2; | ||
177 | mm1[0] = index; | ||
178 | msgs[0].len = 1; msgs[1].len = buff_len; | ||
179 | msgs[0].buf = mm1; msgs[1].buf = buff; | ||
180 | ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); | ||
181 | if (ret == 2) | ||
182 | ret = 0; | ||
183 | else if (ret >= 0) | ||
184 | ret = -EIO; | ||
185 | |||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * Allow other viafb subdevices to look up a specific adapter | ||
191 | * by port name. | ||
192 | */ | ||
193 | struct i2c_adapter *viafb_find_i2c_adapter(enum viafb_i2c_adap which) | ||
194 | { | ||
195 | struct via_i2c_stuff *stuff = &via_i2c_par[which]; | ||
196 | |||
197 | return &stuff->adapter; | ||
198 | } | ||
199 | EXPORT_SYMBOL_GPL(viafb_find_i2c_adapter); | ||
200 | |||
201 | |||
202 | static int create_i2c_bus(struct i2c_adapter *adapter, | ||
203 | struct i2c_algo_bit_data *algo, | ||
204 | struct via_port_cfg *adap_cfg, | ||
205 | struct pci_dev *pdev) | ||
206 | { | ||
207 | algo->setsda = via_i2c_setsda; | ||
208 | algo->setscl = via_i2c_setscl; | ||
209 | algo->getsda = via_i2c_getsda; | ||
210 | algo->getscl = via_i2c_getscl; | ||
211 | algo->udelay = 10; | ||
212 | algo->timeout = 2; | ||
213 | algo->data = adap_cfg; | ||
214 | |||
215 | sprintf(adapter->name, "viafb i2c io_port idx 0x%02x", | ||
216 | adap_cfg->ioport_index); | ||
217 | adapter->owner = THIS_MODULE; | ||
218 | adapter->class = I2C_CLASS_DDC; | ||
219 | adapter->algo_data = algo; | ||
220 | if (pdev) | ||
221 | adapter->dev.parent = &pdev->dev; | ||
222 | else | ||
223 | adapter->dev.parent = NULL; | ||
224 | /* i2c_set_adapdata(adapter, adap_cfg); */ | ||
225 | |||
226 | /* Raise SCL and SDA */ | ||
227 | via_i2c_setsda(adap_cfg, 1); | ||
228 | via_i2c_setscl(adap_cfg, 1); | ||
229 | udelay(20); | ||
230 | |||
231 | return i2c_bit_add_bus(adapter); | ||
232 | } | ||
233 | |||
234 | static int viafb_i2c_probe(struct platform_device *platdev) | ||
235 | { | ||
236 | int i, ret; | ||
237 | struct via_port_cfg *configs; | ||
238 | |||
239 | i2c_vdev = platdev->dev.platform_data; | ||
240 | configs = i2c_vdev->port_cfg; | ||
241 | |||
242 | for (i = 0; i < VIAFB_NUM_PORTS; i++) { | ||
243 | struct via_port_cfg *adap_cfg = configs++; | ||
244 | struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i]; | ||
245 | |||
246 | i2c_stuff->is_active = 0; | ||
247 | if (adap_cfg->type == 0 || adap_cfg->mode != VIA_MODE_I2C) | ||
248 | continue; | ||
249 | ret = create_i2c_bus(&i2c_stuff->adapter, | ||
250 | &i2c_stuff->algo, adap_cfg, | ||
251 | NULL); /* FIXME: PCIDEV */ | ||
252 | if (ret < 0) { | ||
253 | printk(KERN_ERR "viafb: cannot create i2c bus %u:%d\n", | ||
254 | i, ret); | ||
255 | continue; /* Still try to make the rest */ | ||
256 | } | ||
257 | i2c_stuff->is_active = 1; | ||
258 | } | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int viafb_i2c_remove(struct platform_device *platdev) | ||
264 | { | ||
265 | int i; | ||
266 | |||
267 | for (i = 0; i < VIAFB_NUM_PORTS; i++) { | ||
268 | struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i]; | ||
269 | /* | ||
270 | * Only remove those entries in the array that we've | ||
271 | * actually used (and thus initialized algo_data) | ||
272 | */ | ||
273 | if (i2c_stuff->is_active) | ||
274 | i2c_del_adapter(&i2c_stuff->adapter); | ||
275 | } | ||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static struct platform_driver via_i2c_driver = { | ||
280 | .driver = { | ||
281 | .name = "viafb-i2c", | ||
282 | }, | ||
283 | .probe = viafb_i2c_probe, | ||
284 | .remove = viafb_i2c_remove, | ||
285 | }; | ||
286 | |||
287 | int viafb_i2c_init(void) | ||
288 | { | ||
289 | return platform_driver_register(&via_i2c_driver); | ||
290 | } | ||
291 | |||
292 | void viafb_i2c_exit(void) | ||
293 | { | ||
294 | platform_driver_unregister(&via_i2c_driver); | ||
295 | } | ||
diff --git a/drivers/video/fbdev/via/via_modesetting.c b/drivers/video/fbdev/via/via_modesetting.c new file mode 100644 index 000000000000..0b414b09b9b4 --- /dev/null +++ b/drivers/video/fbdev/via/via_modesetting.c | |||
@@ -0,0 +1,230 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | * Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public | ||
8 | * License as published by the Free Software Foundation; | ||
9 | * either version 2, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
14 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
15 | * for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., | ||
20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | /* | ||
23 | * basic modesetting functions | ||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/via-core.h> | ||
28 | #include "via_modesetting.h" | ||
29 | #include "share.h" | ||
30 | #include "debug.h" | ||
31 | |||
32 | |||
33 | void via_set_primary_timing(const struct via_display_timing *timing) | ||
34 | { | ||
35 | struct via_display_timing raw; | ||
36 | |||
37 | raw.hor_total = timing->hor_total / 8 - 5; | ||
38 | raw.hor_addr = timing->hor_addr / 8 - 1; | ||
39 | raw.hor_blank_start = timing->hor_blank_start / 8 - 1; | ||
40 | raw.hor_blank_end = timing->hor_blank_end / 8 - 1; | ||
41 | raw.hor_sync_start = timing->hor_sync_start / 8; | ||
42 | raw.hor_sync_end = timing->hor_sync_end / 8; | ||
43 | raw.ver_total = timing->ver_total - 2; | ||
44 | raw.ver_addr = timing->ver_addr - 1; | ||
45 | raw.ver_blank_start = timing->ver_blank_start - 1; | ||
46 | raw.ver_blank_end = timing->ver_blank_end - 1; | ||
47 | raw.ver_sync_start = timing->ver_sync_start - 1; | ||
48 | raw.ver_sync_end = timing->ver_sync_end - 1; | ||
49 | |||
50 | /* unlock timing registers */ | ||
51 | via_write_reg_mask(VIACR, 0x11, 0x00, 0x80); | ||
52 | |||
53 | via_write_reg(VIACR, 0x00, raw.hor_total & 0xFF); | ||
54 | via_write_reg(VIACR, 0x01, raw.hor_addr & 0xFF); | ||
55 | via_write_reg(VIACR, 0x02, raw.hor_blank_start & 0xFF); | ||
56 | via_write_reg_mask(VIACR, 0x03, raw.hor_blank_end & 0x1F, 0x1F); | ||
57 | via_write_reg(VIACR, 0x04, raw.hor_sync_start & 0xFF); | ||
58 | via_write_reg_mask(VIACR, 0x05, (raw.hor_sync_end & 0x1F) | ||
59 | | (raw.hor_blank_end << (7 - 5) & 0x80), 0x9F); | ||
60 | via_write_reg(VIACR, 0x06, raw.ver_total & 0xFF); | ||
61 | via_write_reg_mask(VIACR, 0x07, (raw.ver_total >> 8 & 0x01) | ||
62 | | (raw.ver_addr >> (8 - 1) & 0x02) | ||
63 | | (raw.ver_sync_start >> (8 - 2) & 0x04) | ||
64 | | (raw.ver_blank_start >> (8 - 3) & 0x08) | ||
65 | | (raw.ver_total >> (9 - 5) & 0x20) | ||
66 | | (raw.ver_addr >> (9 - 6) & 0x40) | ||
67 | | (raw.ver_sync_start >> (9 - 7) & 0x80), 0xEF); | ||
68 | via_write_reg_mask(VIACR, 0x09, raw.ver_blank_start >> (9 - 5) & 0x20, | ||
69 | 0x20); | ||
70 | via_write_reg(VIACR, 0x10, raw.ver_sync_start & 0xFF); | ||
71 | via_write_reg_mask(VIACR, 0x11, raw.ver_sync_end & 0x0F, 0x0F); | ||
72 | via_write_reg(VIACR, 0x12, raw.ver_addr & 0xFF); | ||
73 | via_write_reg(VIACR, 0x15, raw.ver_blank_start & 0xFF); | ||
74 | via_write_reg(VIACR, 0x16, raw.ver_blank_end & 0xFF); | ||
75 | via_write_reg_mask(VIACR, 0x33, (raw.hor_sync_start >> (8 - 4) & 0x10) | ||
76 | | (raw.hor_blank_end >> (6 - 5) & 0x20), 0x30); | ||
77 | via_write_reg_mask(VIACR, 0x35, (raw.ver_total >> 10 & 0x01) | ||
78 | | (raw.ver_sync_start >> (10 - 1) & 0x02) | ||
79 | | (raw.ver_addr >> (10 - 2) & 0x04) | ||
80 | | (raw.ver_blank_start >> (10 - 3) & 0x08), 0x0F); | ||
81 | via_write_reg_mask(VIACR, 0x36, raw.hor_total >> (8 - 3) & 0x08, 0x08); | ||
82 | |||
83 | /* lock timing registers */ | ||
84 | via_write_reg_mask(VIACR, 0x11, 0x80, 0x80); | ||
85 | |||
86 | /* reset timing control */ | ||
87 | via_write_reg_mask(VIACR, 0x17, 0x00, 0x80); | ||
88 | via_write_reg_mask(VIACR, 0x17, 0x80, 0x80); | ||
89 | } | ||
90 | |||
91 | void via_set_secondary_timing(const struct via_display_timing *timing) | ||
92 | { | ||
93 | struct via_display_timing raw; | ||
94 | |||
95 | raw.hor_total = timing->hor_total - 1; | ||
96 | raw.hor_addr = timing->hor_addr - 1; | ||
97 | raw.hor_blank_start = timing->hor_blank_start - 1; | ||
98 | raw.hor_blank_end = timing->hor_blank_end - 1; | ||
99 | raw.hor_sync_start = timing->hor_sync_start - 1; | ||
100 | raw.hor_sync_end = timing->hor_sync_end - 1; | ||
101 | raw.ver_total = timing->ver_total - 1; | ||
102 | raw.ver_addr = timing->ver_addr - 1; | ||
103 | raw.ver_blank_start = timing->ver_blank_start - 1; | ||
104 | raw.ver_blank_end = timing->ver_blank_end - 1; | ||
105 | raw.ver_sync_start = timing->ver_sync_start - 1; | ||
106 | raw.ver_sync_end = timing->ver_sync_end - 1; | ||
107 | |||
108 | via_write_reg(VIACR, 0x50, raw.hor_total & 0xFF); | ||
109 | via_write_reg(VIACR, 0x51, raw.hor_addr & 0xFF); | ||
110 | via_write_reg(VIACR, 0x52, raw.hor_blank_start & 0xFF); | ||
111 | via_write_reg(VIACR, 0x53, raw.hor_blank_end & 0xFF); | ||
112 | via_write_reg(VIACR, 0x54, (raw.hor_blank_start >> 8 & 0x07) | ||
113 | | (raw.hor_blank_end >> (8 - 3) & 0x38) | ||
114 | | (raw.hor_sync_start >> (8 - 6) & 0xC0)); | ||
115 | via_write_reg_mask(VIACR, 0x55, (raw.hor_total >> 8 & 0x0F) | ||
116 | | (raw.hor_addr >> (8 - 4) & 0x70), 0x7F); | ||
117 | via_write_reg(VIACR, 0x56, raw.hor_sync_start & 0xFF); | ||
118 | via_write_reg(VIACR, 0x57, raw.hor_sync_end & 0xFF); | ||
119 | via_write_reg(VIACR, 0x58, raw.ver_total & 0xFF); | ||
120 | via_write_reg(VIACR, 0x59, raw.ver_addr & 0xFF); | ||
121 | via_write_reg(VIACR, 0x5A, raw.ver_blank_start & 0xFF); | ||
122 | via_write_reg(VIACR, 0x5B, raw.ver_blank_end & 0xFF); | ||
123 | via_write_reg(VIACR, 0x5C, (raw.ver_blank_start >> 8 & 0x07) | ||
124 | | (raw.ver_blank_end >> (8 - 3) & 0x38) | ||
125 | | (raw.hor_sync_end >> (8 - 6) & 0x40) | ||
126 | | (raw.hor_sync_start >> (10 - 7) & 0x80)); | ||
127 | via_write_reg(VIACR, 0x5D, (raw.ver_total >> 8 & 0x07) | ||
128 | | (raw.ver_addr >> (8 - 3) & 0x38) | ||
129 | | (raw.hor_blank_end >> (11 - 6) & 0x40) | ||
130 | | (raw.hor_sync_start >> (11 - 7) & 0x80)); | ||
131 | via_write_reg(VIACR, 0x5E, raw.ver_sync_start & 0xFF); | ||
132 | via_write_reg(VIACR, 0x5F, (raw.ver_sync_end & 0x1F) | ||
133 | | (raw.ver_sync_start >> (8 - 5) & 0xE0)); | ||
134 | } | ||
135 | |||
136 | void via_set_primary_address(u32 addr) | ||
137 | { | ||
138 | DEBUG_MSG(KERN_DEBUG "via_set_primary_address(0x%08X)\n", addr); | ||
139 | via_write_reg(VIACR, 0x0D, addr & 0xFF); | ||
140 | via_write_reg(VIACR, 0x0C, (addr >> 8) & 0xFF); | ||
141 | via_write_reg(VIACR, 0x34, (addr >> 16) & 0xFF); | ||
142 | via_write_reg_mask(VIACR, 0x48, (addr >> 24) & 0x1F, 0x1F); | ||
143 | } | ||
144 | |||
145 | void via_set_secondary_address(u32 addr) | ||
146 | { | ||
147 | DEBUG_MSG(KERN_DEBUG "via_set_secondary_address(0x%08X)\n", addr); | ||
148 | /* secondary display supports only quadword aligned memory */ | ||
149 | via_write_reg_mask(VIACR, 0x62, (addr >> 2) & 0xFE, 0xFE); | ||
150 | via_write_reg(VIACR, 0x63, (addr >> 10) & 0xFF); | ||
151 | via_write_reg(VIACR, 0x64, (addr >> 18) & 0xFF); | ||
152 | via_write_reg_mask(VIACR, 0xA3, (addr >> 26) & 0x07, 0x07); | ||
153 | } | ||
154 | |||
155 | void via_set_primary_pitch(u32 pitch) | ||
156 | { | ||
157 | DEBUG_MSG(KERN_DEBUG "via_set_primary_pitch(0x%08X)\n", pitch); | ||
158 | /* spec does not say that first adapter skips 3 bits but old | ||
159 | * code did it and seems to be reasonable in analogy to 2nd adapter | ||
160 | */ | ||
161 | pitch = pitch >> 3; | ||
162 | via_write_reg(VIACR, 0x13, pitch & 0xFF); | ||
163 | via_write_reg_mask(VIACR, 0x35, (pitch >> (8 - 5)) & 0xE0, 0xE0); | ||
164 | } | ||
165 | |||
166 | void via_set_secondary_pitch(u32 pitch) | ||
167 | { | ||
168 | DEBUG_MSG(KERN_DEBUG "via_set_secondary_pitch(0x%08X)\n", pitch); | ||
169 | pitch = pitch >> 3; | ||
170 | via_write_reg(VIACR, 0x66, pitch & 0xFF); | ||
171 | via_write_reg_mask(VIACR, 0x67, (pitch >> 8) & 0x03, 0x03); | ||
172 | via_write_reg_mask(VIACR, 0x71, (pitch >> (10 - 7)) & 0x80, 0x80); | ||
173 | } | ||
174 | |||
175 | void via_set_primary_color_depth(u8 depth) | ||
176 | { | ||
177 | u8 value; | ||
178 | |||
179 | DEBUG_MSG(KERN_DEBUG "via_set_primary_color_depth(%d)\n", depth); | ||
180 | switch (depth) { | ||
181 | case 8: | ||
182 | value = 0x00; | ||
183 | break; | ||
184 | case 15: | ||
185 | value = 0x04; | ||
186 | break; | ||
187 | case 16: | ||
188 | value = 0x14; | ||
189 | break; | ||
190 | case 24: | ||
191 | value = 0x0C; | ||
192 | break; | ||
193 | case 30: | ||
194 | value = 0x08; | ||
195 | break; | ||
196 | default: | ||
197 | printk(KERN_WARNING "via_set_primary_color_depth: " | ||
198 | "Unsupported depth: %d\n", depth); | ||
199 | return; | ||
200 | } | ||
201 | |||
202 | via_write_reg_mask(VIASR, 0x15, value, 0x1C); | ||
203 | } | ||
204 | |||
205 | void via_set_secondary_color_depth(u8 depth) | ||
206 | { | ||
207 | u8 value; | ||
208 | |||
209 | DEBUG_MSG(KERN_DEBUG "via_set_secondary_color_depth(%d)\n", depth); | ||
210 | switch (depth) { | ||
211 | case 8: | ||
212 | value = 0x00; | ||
213 | break; | ||
214 | case 16: | ||
215 | value = 0x40; | ||
216 | break; | ||
217 | case 24: | ||
218 | value = 0xC0; | ||
219 | break; | ||
220 | case 30: | ||
221 | value = 0x80; | ||
222 | break; | ||
223 | default: | ||
224 | printk(KERN_WARNING "via_set_secondary_color_depth: " | ||
225 | "Unsupported depth: %d\n", depth); | ||
226 | return; | ||
227 | } | ||
228 | |||
229 | via_write_reg_mask(VIACR, 0x67, value, 0xC0); | ||
230 | } | ||
diff --git a/drivers/video/fbdev/via/via_modesetting.h b/drivers/video/fbdev/via/via_modesetting.h new file mode 100644 index 000000000000..f6a6503da3b3 --- /dev/null +++ b/drivers/video/fbdev/via/via_modesetting.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | * Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public | ||
8 | * License as published by the Free Software Foundation; | ||
9 | * either version 2, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
14 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
15 | * for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., | ||
20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | /* | ||
23 | * basic modesetting functions | ||
24 | */ | ||
25 | |||
26 | #ifndef __VIA_MODESETTING_H__ | ||
27 | #define __VIA_MODESETTING_H__ | ||
28 | |||
29 | #include <linux/types.h> | ||
30 | |||
31 | |||
32 | #define VIA_PITCH_SIZE (1<<3) | ||
33 | #define VIA_PITCH_MAX 0x3FF8 | ||
34 | |||
35 | |||
36 | struct via_display_timing { | ||
37 | u16 hor_total; | ||
38 | u16 hor_addr; | ||
39 | u16 hor_blank_start; | ||
40 | u16 hor_blank_end; | ||
41 | u16 hor_sync_start; | ||
42 | u16 hor_sync_end; | ||
43 | u16 ver_total; | ||
44 | u16 ver_addr; | ||
45 | u16 ver_blank_start; | ||
46 | u16 ver_blank_end; | ||
47 | u16 ver_sync_start; | ||
48 | u16 ver_sync_end; | ||
49 | }; | ||
50 | |||
51 | |||
52 | void via_set_primary_timing(const struct via_display_timing *timing); | ||
53 | void via_set_secondary_timing(const struct via_display_timing *timing); | ||
54 | void via_set_primary_address(u32 addr); | ||
55 | void via_set_secondary_address(u32 addr); | ||
56 | void via_set_primary_pitch(u32 pitch); | ||
57 | void via_set_secondary_pitch(u32 pitch); | ||
58 | void via_set_primary_color_depth(u8 depth); | ||
59 | void via_set_secondary_color_depth(u8 depth); | ||
60 | |||
61 | #endif /* __VIA_MODESETTING_H__ */ | ||
diff --git a/drivers/video/fbdev/via/via_utility.c b/drivers/video/fbdev/via/via_utility.c new file mode 100644 index 000000000000..35458a5eadc8 --- /dev/null +++ b/drivers/video/fbdev/via/via_utility.c | |||
@@ -0,0 +1,242 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/via-core.h> | ||
23 | #include "global.h" | ||
24 | |||
25 | void viafb_get_device_support_state(u32 *support_state) | ||
26 | { | ||
27 | *support_state = CRT_Device; | ||
28 | |||
29 | if (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name == VT1632_TMDS) | ||
30 | *support_state |= DVI_Device; | ||
31 | |||
32 | if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name == VT1631_LVDS) | ||
33 | *support_state |= LCD_Device; | ||
34 | } | ||
35 | |||
36 | void viafb_get_device_connect_state(u32 *connect_state) | ||
37 | { | ||
38 | bool mobile = false; | ||
39 | |||
40 | *connect_state = CRT_Device; | ||
41 | |||
42 | if (viafb_dvi_sense()) | ||
43 | *connect_state |= DVI_Device; | ||
44 | |||
45 | viafb_lcd_get_mobile_state(&mobile); | ||
46 | if (mobile) | ||
47 | *connect_state |= LCD_Device; | ||
48 | } | ||
49 | |||
50 | bool viafb_lcd_get_support_expand_state(u32 xres, u32 yres) | ||
51 | { | ||
52 | unsigned int support_state = 0; | ||
53 | |||
54 | switch (viafb_lcd_panel_id) { | ||
55 | case LCD_PANEL_ID0_640X480: | ||
56 | if ((xres < 640) && (yres < 480)) | ||
57 | support_state = true; | ||
58 | break; | ||
59 | |||
60 | case LCD_PANEL_ID1_800X600: | ||
61 | if ((xres < 800) && (yres < 600)) | ||
62 | support_state = true; | ||
63 | break; | ||
64 | |||
65 | case LCD_PANEL_ID2_1024X768: | ||
66 | if ((xres < 1024) && (yres < 768)) | ||
67 | support_state = true; | ||
68 | break; | ||
69 | |||
70 | case LCD_PANEL_ID3_1280X768: | ||
71 | if ((xres < 1280) && (yres < 768)) | ||
72 | support_state = true; | ||
73 | break; | ||
74 | |||
75 | case LCD_PANEL_ID4_1280X1024: | ||
76 | if ((xres < 1280) && (yres < 1024)) | ||
77 | support_state = true; | ||
78 | break; | ||
79 | |||
80 | case LCD_PANEL_ID5_1400X1050: | ||
81 | if ((xres < 1400) && (yres < 1050)) | ||
82 | support_state = true; | ||
83 | break; | ||
84 | |||
85 | case LCD_PANEL_ID6_1600X1200: | ||
86 | if ((xres < 1600) && (yres < 1200)) | ||
87 | support_state = true; | ||
88 | break; | ||
89 | |||
90 | case LCD_PANEL_ID7_1366X768: | ||
91 | if ((xres < 1366) && (yres < 768)) | ||
92 | support_state = true; | ||
93 | break; | ||
94 | |||
95 | case LCD_PANEL_ID8_1024X600: | ||
96 | if ((xres < 1024) && (yres < 600)) | ||
97 | support_state = true; | ||
98 | break; | ||
99 | |||
100 | case LCD_PANEL_ID9_1280X800: | ||
101 | if ((xres < 1280) && (yres < 800)) | ||
102 | support_state = true; | ||
103 | break; | ||
104 | |||
105 | case LCD_PANEL_IDA_800X480: | ||
106 | if ((xres < 800) && (yres < 480)) | ||
107 | support_state = true; | ||
108 | break; | ||
109 | |||
110 | case LCD_PANEL_IDB_1360X768: | ||
111 | if ((xres < 1360) && (yres < 768)) | ||
112 | support_state = true; | ||
113 | break; | ||
114 | |||
115 | case LCD_PANEL_IDC_480X640: | ||
116 | if ((xres < 480) && (yres < 640)) | ||
117 | support_state = true; | ||
118 | break; | ||
119 | |||
120 | default: | ||
121 | support_state = false; | ||
122 | break; | ||
123 | } | ||
124 | |||
125 | return support_state; | ||
126 | } | ||
127 | |||
128 | /*====================================================================*/ | ||
129 | /* Gamma Function Implementation*/ | ||
130 | /*====================================================================*/ | ||
131 | |||
132 | void viafb_set_gamma_table(int bpp, unsigned int *gamma_table) | ||
133 | { | ||
134 | int i, sr1a; | ||
135 | int active_device_amount = 0; | ||
136 | int device_status = viafb_DeviceStatus; | ||
137 | |||
138 | for (i = 0; i < sizeof(viafb_DeviceStatus) * 8; i++) { | ||
139 | if (device_status & 1) | ||
140 | active_device_amount++; | ||
141 | device_status >>= 1; | ||
142 | } | ||
143 | |||
144 | /* 8 bpp mode can't adjust gamma */ | ||
145 | if (bpp == 8) | ||
146 | return ; | ||
147 | |||
148 | /* Enable Gamma */ | ||
149 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
150 | case UNICHROME_CLE266: | ||
151 | case UNICHROME_K400: | ||
152 | viafb_write_reg_mask(SR16, VIASR, 0x80, BIT7); | ||
153 | break; | ||
154 | |||
155 | case UNICHROME_K800: | ||
156 | case UNICHROME_PM800: | ||
157 | case UNICHROME_CN700: | ||
158 | case UNICHROME_CX700: | ||
159 | case UNICHROME_K8M890: | ||
160 | case UNICHROME_P4M890: | ||
161 | case UNICHROME_P4M900: | ||
162 | viafb_write_reg_mask(CR33, VIACR, 0x80, BIT7); | ||
163 | break; | ||
164 | } | ||
165 | sr1a = (unsigned int)viafb_read_reg(VIASR, SR1A); | ||
166 | viafb_write_reg_mask(SR1A, VIASR, 0x0, BIT0); | ||
167 | |||
168 | /* Fill IGA1 Gamma Table */ | ||
169 | outb(0, LUT_INDEX_WRITE); | ||
170 | for (i = 0; i < 256; i++) { | ||
171 | outb(gamma_table[i] >> 16, LUT_DATA); | ||
172 | outb(gamma_table[i] >> 8 & 0xFF, LUT_DATA); | ||
173 | outb(gamma_table[i] & 0xFF, LUT_DATA); | ||
174 | } | ||
175 | |||
176 | /* If adjust Gamma value in SAMM, fill IGA1, | ||
177 | IGA2 Gamma table simultaneous. */ | ||
178 | /* Switch to IGA2 Gamma Table */ | ||
179 | if ((active_device_amount > 1) && | ||
180 | !((viaparinfo->chip_info->gfx_chip_name == | ||
181 | UNICHROME_CLE266) && | ||
182 | (viaparinfo->chip_info->gfx_chip_revision < 15))) { | ||
183 | viafb_write_reg_mask(SR1A, VIASR, 0x01, BIT0); | ||
184 | viafb_write_reg_mask(CR6A, VIACR, 0x02, BIT1); | ||
185 | |||
186 | /* Fill IGA2 Gamma Table */ | ||
187 | outb(0, LUT_INDEX_WRITE); | ||
188 | for (i = 0; i < 256; i++) { | ||
189 | outb(gamma_table[i] >> 16, LUT_DATA); | ||
190 | outb(gamma_table[i] >> 8 & 0xFF, LUT_DATA); | ||
191 | outb(gamma_table[i] & 0xFF, LUT_DATA); | ||
192 | } | ||
193 | } | ||
194 | viafb_write_reg(SR1A, VIASR, sr1a); | ||
195 | } | ||
196 | |||
197 | void viafb_get_gamma_table(unsigned int *gamma_table) | ||
198 | { | ||
199 | unsigned char color_r, color_g, color_b; | ||
200 | unsigned char sr1a = 0; | ||
201 | int i; | ||
202 | |||
203 | /* Enable Gamma */ | ||
204 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
205 | case UNICHROME_CLE266: | ||
206 | case UNICHROME_K400: | ||
207 | viafb_write_reg_mask(SR16, VIASR, 0x80, BIT7); | ||
208 | break; | ||
209 | |||
210 | case UNICHROME_K800: | ||
211 | case UNICHROME_PM800: | ||
212 | case UNICHROME_CN700: | ||
213 | case UNICHROME_CX700: | ||
214 | case UNICHROME_K8M890: | ||
215 | case UNICHROME_P4M890: | ||
216 | case UNICHROME_P4M900: | ||
217 | viafb_write_reg_mask(CR33, VIACR, 0x80, BIT7); | ||
218 | break; | ||
219 | } | ||
220 | sr1a = viafb_read_reg(VIASR, SR1A); | ||
221 | viafb_write_reg_mask(SR1A, VIASR, 0x0, BIT0); | ||
222 | |||
223 | /* Reading gamma table to get color value */ | ||
224 | outb(0, LUT_INDEX_READ); | ||
225 | for (i = 0; i < 256; i++) { | ||
226 | color_r = inb(LUT_DATA); | ||
227 | color_g = inb(LUT_DATA); | ||
228 | color_b = inb(LUT_DATA); | ||
229 | gamma_table[i] = | ||
230 | ((((u32) color_r) << 16) | | ||
231 | (((u16) color_g) << 8)) | color_b; | ||
232 | } | ||
233 | viafb_write_reg(SR1A, VIASR, sr1a); | ||
234 | } | ||
235 | |||
236 | void viafb_get_gamma_support_state(int bpp, unsigned int *support_state) | ||
237 | { | ||
238 | if (bpp == 8) | ||
239 | *support_state = None_Device; | ||
240 | else | ||
241 | *support_state = CRT_Device | DVI_Device | LCD_Device; | ||
242 | } | ||
diff --git a/drivers/video/fbdev/via/via_utility.h b/drivers/video/fbdev/via/via_utility.h new file mode 100644 index 000000000000..f23be1708c14 --- /dev/null +++ b/drivers/video/fbdev/via/via_utility.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #ifndef __VIAUTILITY_H__ | ||
22 | #define __VIAUTILITY_H__ | ||
23 | |||
24 | /* These functions are used to get information about device's state */ | ||
25 | void viafb_get_device_support_state(u32 *support_state); | ||
26 | void viafb_get_device_connect_state(u32 *connect_state); | ||
27 | bool viafb_lcd_get_support_expand_state(u32 xres, u32 yres); | ||
28 | |||
29 | /* These function are used to access gamma table */ | ||
30 | void viafb_set_gamma_table(int bpp, unsigned int *gamma_table); | ||
31 | void viafb_get_gamma_table(unsigned int *gamma_table); | ||
32 | void viafb_get_gamma_support_state(int bpp, unsigned int *support_state); | ||
33 | |||
34 | #endif /* __VIAUTILITY_H__ */ | ||
diff --git a/drivers/video/fbdev/via/viafbdev.c b/drivers/video/fbdev/via/viafbdev.c new file mode 100644 index 000000000000..325c43c6ff97 --- /dev/null +++ b/drivers/video/fbdev/via/viafbdev.c | |||
@@ -0,0 +1,2176 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/seq_file.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/stat.h> | ||
26 | #include <linux/via-core.h> | ||
27 | #include <linux/via_i2c.h> | ||
28 | #include <asm/olpc.h> | ||
29 | |||
30 | #define _MASTER_FILE | ||
31 | #include "global.h" | ||
32 | |||
33 | static char *viafb_name = "Via"; | ||
34 | static u32 pseudo_pal[17]; | ||
35 | |||
36 | /* video mode */ | ||
37 | static char *viafb_mode; | ||
38 | static char *viafb_mode1; | ||
39 | static int viafb_bpp = 32; | ||
40 | static int viafb_bpp1 = 32; | ||
41 | |||
42 | static unsigned int viafb_second_offset; | ||
43 | static int viafb_second_size; | ||
44 | |||
45 | static int viafb_accel = 1; | ||
46 | |||
47 | /* Added for specifying active devices.*/ | ||
48 | static char *viafb_active_dev; | ||
49 | |||
50 | /*Added for specify lcd output port*/ | ||
51 | static char *viafb_lcd_port = ""; | ||
52 | static char *viafb_dvi_port = ""; | ||
53 | |||
54 | static void retrieve_device_setting(struct viafb_ioctl_setting | ||
55 | *setting_info); | ||
56 | static int viafb_pan_display(struct fb_var_screeninfo *var, | ||
57 | struct fb_info *info); | ||
58 | |||
59 | static struct fb_ops viafb_ops; | ||
60 | |||
61 | /* supported output devices on each IGP | ||
62 | * only CX700, VX800, VX855, VX900 were documented | ||
63 | * VIA_CRT should be everywhere | ||
64 | * VIA_6C can be onle pre-CX700 (probably only on CLE266) as 6C is used for PLL | ||
65 | * source selection on CX700 and later | ||
66 | * K400 seems to support VIA_96, VIA_DVP1, VIA_LVDS{1,2} as in viamode.c | ||
67 | */ | ||
68 | static const u32 supported_odev_map[] = { | ||
69 | [UNICHROME_CLE266] = VIA_CRT | VIA_LDVP0 | VIA_LDVP1, | ||
70 | [UNICHROME_K400] = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1 | ||
71 | | VIA_LVDS2, | ||
72 | [UNICHROME_K800] = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1 | ||
73 | | VIA_LVDS2, | ||
74 | [UNICHROME_PM800] = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1 | ||
75 | | VIA_LVDS2, | ||
76 | [UNICHROME_CN700] = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1 | ||
77 | | VIA_LVDS2, | ||
78 | [UNICHROME_CX700] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, | ||
79 | [UNICHROME_CN750] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, | ||
80 | [UNICHROME_K8M890] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, | ||
81 | [UNICHROME_P4M890] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, | ||
82 | [UNICHROME_P4M900] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, | ||
83 | [UNICHROME_VX800] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, | ||
84 | [UNICHROME_VX855] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, | ||
85 | [UNICHROME_VX900] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, | ||
86 | }; | ||
87 | |||
88 | static void viafb_fill_var_color_info(struct fb_var_screeninfo *var, u8 depth) | ||
89 | { | ||
90 | var->grayscale = 0; | ||
91 | var->red.msb_right = 0; | ||
92 | var->green.msb_right = 0; | ||
93 | var->blue.msb_right = 0; | ||
94 | var->transp.offset = 0; | ||
95 | var->transp.length = 0; | ||
96 | var->transp.msb_right = 0; | ||
97 | var->nonstd = 0; | ||
98 | switch (depth) { | ||
99 | case 8: | ||
100 | var->bits_per_pixel = 8; | ||
101 | var->red.offset = 0; | ||
102 | var->green.offset = 0; | ||
103 | var->blue.offset = 0; | ||
104 | var->red.length = 8; | ||
105 | var->green.length = 8; | ||
106 | var->blue.length = 8; | ||
107 | break; | ||
108 | case 15: | ||
109 | var->bits_per_pixel = 16; | ||
110 | var->red.offset = 10; | ||
111 | var->green.offset = 5; | ||
112 | var->blue.offset = 0; | ||
113 | var->red.length = 5; | ||
114 | var->green.length = 5; | ||
115 | var->blue.length = 5; | ||
116 | break; | ||
117 | case 16: | ||
118 | var->bits_per_pixel = 16; | ||
119 | var->red.offset = 11; | ||
120 | var->green.offset = 5; | ||
121 | var->blue.offset = 0; | ||
122 | var->red.length = 5; | ||
123 | var->green.length = 6; | ||
124 | var->blue.length = 5; | ||
125 | break; | ||
126 | case 24: | ||
127 | var->bits_per_pixel = 32; | ||
128 | var->red.offset = 16; | ||
129 | var->green.offset = 8; | ||
130 | var->blue.offset = 0; | ||
131 | var->red.length = 8; | ||
132 | var->green.length = 8; | ||
133 | var->blue.length = 8; | ||
134 | break; | ||
135 | case 30: | ||
136 | var->bits_per_pixel = 32; | ||
137 | var->red.offset = 20; | ||
138 | var->green.offset = 10; | ||
139 | var->blue.offset = 0; | ||
140 | var->red.length = 10; | ||
141 | var->green.length = 10; | ||
142 | var->blue.length = 10; | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | static void viafb_update_fix(struct fb_info *info) | ||
148 | { | ||
149 | u32 bpp = info->var.bits_per_pixel; | ||
150 | |||
151 | info->fix.visual = | ||
152 | bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; | ||
153 | info->fix.line_length = ALIGN(info->var.xres_virtual * bpp / 8, | ||
154 | VIA_PITCH_SIZE); | ||
155 | } | ||
156 | |||
157 | static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix, | ||
158 | struct viafb_par *viaparinfo) | ||
159 | { | ||
160 | memset(fix, 0, sizeof(struct fb_fix_screeninfo)); | ||
161 | strcpy(fix->id, viafb_name); | ||
162 | |||
163 | fix->smem_start = viaparinfo->fbmem; | ||
164 | fix->smem_len = viaparinfo->fbmem_free; | ||
165 | |||
166 | fix->type = FB_TYPE_PACKED_PIXELS; | ||
167 | fix->type_aux = 0; | ||
168 | fix->visual = FB_VISUAL_TRUECOLOR; | ||
169 | |||
170 | fix->xpanstep = fix->ywrapstep = 0; | ||
171 | fix->ypanstep = 1; | ||
172 | |||
173 | /* Just tell the accel name */ | ||
174 | viafbinfo->fix.accel = FB_ACCEL_VIA_UNICHROME; | ||
175 | } | ||
176 | static int viafb_open(struct fb_info *info, int user) | ||
177 | { | ||
178 | DEBUG_MSG(KERN_INFO "viafb_open!\n"); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int viafb_release(struct fb_info *info, int user) | ||
183 | { | ||
184 | DEBUG_MSG(KERN_INFO "viafb_release!\n"); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static inline int get_var_refresh(struct fb_var_screeninfo *var) | ||
189 | { | ||
190 | u32 htotal, vtotal; | ||
191 | |||
192 | htotal = var->left_margin + var->xres + var->right_margin | ||
193 | + var->hsync_len; | ||
194 | vtotal = var->upper_margin + var->yres + var->lower_margin | ||
195 | + var->vsync_len; | ||
196 | return PICOS2KHZ(var->pixclock) * 1000 / (htotal * vtotal); | ||
197 | } | ||
198 | |||
199 | static int viafb_check_var(struct fb_var_screeninfo *var, | ||
200 | struct fb_info *info) | ||
201 | { | ||
202 | int depth, refresh; | ||
203 | struct viafb_par *ppar = info->par; | ||
204 | u32 line; | ||
205 | |||
206 | DEBUG_MSG(KERN_INFO "viafb_check_var!\n"); | ||
207 | /* Sanity check */ | ||
208 | /* HW neither support interlacte nor double-scaned mode */ | ||
209 | if (var->vmode & FB_VMODE_INTERLACED || var->vmode & FB_VMODE_DOUBLE) | ||
210 | return -EINVAL; | ||
211 | |||
212 | /* the refresh rate is not important here, as we only want to know | ||
213 | * whether the resolution exists | ||
214 | */ | ||
215 | if (!viafb_get_best_mode(var->xres, var->yres, 60)) { | ||
216 | DEBUG_MSG(KERN_INFO | ||
217 | "viafb: Mode %dx%dx%d not supported!!\n", | ||
218 | var->xres, var->yres, var->bits_per_pixel); | ||
219 | return -EINVAL; | ||
220 | } | ||
221 | |||
222 | depth = fb_get_color_depth(var, &info->fix); | ||
223 | if (!depth) | ||
224 | depth = var->bits_per_pixel; | ||
225 | |||
226 | if (depth < 0 || depth > 32) | ||
227 | return -EINVAL; | ||
228 | else if (!depth) | ||
229 | depth = 24; | ||
230 | else if (depth == 15 && viafb_dual_fb && ppar->iga_path == IGA1) | ||
231 | depth = 15; | ||
232 | else if (depth == 30) | ||
233 | depth = 30; | ||
234 | else if (depth <= 8) | ||
235 | depth = 8; | ||
236 | else if (depth <= 16) | ||
237 | depth = 16; | ||
238 | else | ||
239 | depth = 24; | ||
240 | |||
241 | viafb_fill_var_color_info(var, depth); | ||
242 | if (var->xres_virtual < var->xres) | ||
243 | var->xres_virtual = var->xres; | ||
244 | |||
245 | line = ALIGN(var->xres_virtual * var->bits_per_pixel / 8, | ||
246 | VIA_PITCH_SIZE); | ||
247 | if (line > VIA_PITCH_MAX || line * var->yres_virtual > ppar->memsize) | ||
248 | return -EINVAL; | ||
249 | |||
250 | /* Based on var passed in to calculate the refresh, | ||
251 | * because our driver use some modes special. | ||
252 | */ | ||
253 | refresh = viafb_get_refresh(var->xres, var->yres, | ||
254 | get_var_refresh(var)); | ||
255 | |||
256 | /* Adjust var according to our driver's own table */ | ||
257 | viafb_fill_var_timing_info(var, | ||
258 | viafb_get_best_mode(var->xres, var->yres, refresh)); | ||
259 | if (var->accel_flags & FB_ACCELF_TEXT && | ||
260 | !ppar->shared->vdev->engine_mmio) | ||
261 | var->accel_flags = 0; | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int viafb_set_par(struct fb_info *info) | ||
267 | { | ||
268 | struct viafb_par *viapar = info->par; | ||
269 | int refresh; | ||
270 | DEBUG_MSG(KERN_INFO "viafb_set_par!\n"); | ||
271 | |||
272 | viafb_update_fix(info); | ||
273 | viapar->depth = fb_get_color_depth(&info->var, &info->fix); | ||
274 | viafb_update_device_setting(viafbinfo->var.xres, viafbinfo->var.yres, | ||
275 | viafbinfo->var.bits_per_pixel, 0); | ||
276 | |||
277 | if (viafb_dual_fb) { | ||
278 | viafb_update_device_setting(viafbinfo1->var.xres, | ||
279 | viafbinfo1->var.yres, viafbinfo1->var.bits_per_pixel, | ||
280 | 1); | ||
281 | } else if (viafb_SAMM_ON == 1) { | ||
282 | DEBUG_MSG(KERN_INFO | ||
283 | "viafb_second_xres = %d, viafb_second_yres = %d, bpp = %d\n", | ||
284 | viafb_second_xres, viafb_second_yres, viafb_bpp1); | ||
285 | |||
286 | viafb_update_device_setting(viafb_second_xres, | ||
287 | viafb_second_yres, viafb_bpp1, 1); | ||
288 | } | ||
289 | |||
290 | refresh = get_var_refresh(&info->var); | ||
291 | if (viafb_dual_fb && viapar->iga_path == IGA2) { | ||
292 | viafb_bpp1 = info->var.bits_per_pixel; | ||
293 | viafb_refresh1 = refresh; | ||
294 | } else { | ||
295 | viafb_bpp = info->var.bits_per_pixel; | ||
296 | viafb_refresh = refresh; | ||
297 | } | ||
298 | |||
299 | if (info->var.accel_flags & FB_ACCELF_TEXT) | ||
300 | info->flags &= ~FBINFO_HWACCEL_DISABLED; | ||
301 | else | ||
302 | info->flags |= FBINFO_HWACCEL_DISABLED; | ||
303 | viafb_setmode(); | ||
304 | viafb_pan_display(&info->var, info); | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | /* Set one color register */ | ||
310 | static int viafb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
311 | unsigned blue, unsigned transp, struct fb_info *info) | ||
312 | { | ||
313 | struct viafb_par *viapar = info->par; | ||
314 | u32 r, g, b; | ||
315 | |||
316 | if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { | ||
317 | if (regno > 255) | ||
318 | return -EINVAL; | ||
319 | |||
320 | if (!viafb_dual_fb || viapar->iga_path == IGA1) | ||
321 | viafb_set_primary_color_register(regno, red >> 8, | ||
322 | green >> 8, blue >> 8); | ||
323 | |||
324 | if (!viafb_dual_fb || viapar->iga_path == IGA2) | ||
325 | viafb_set_secondary_color_register(regno, red >> 8, | ||
326 | green >> 8, blue >> 8); | ||
327 | } else { | ||
328 | if (regno > 15) | ||
329 | return -EINVAL; | ||
330 | |||
331 | r = (red >> (16 - info->var.red.length)) | ||
332 | << info->var.red.offset; | ||
333 | b = (blue >> (16 - info->var.blue.length)) | ||
334 | << info->var.blue.offset; | ||
335 | g = (green >> (16 - info->var.green.length)) | ||
336 | << info->var.green.offset; | ||
337 | ((u32 *) info->pseudo_palette)[regno] = r | g | b; | ||
338 | } | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static int viafb_pan_display(struct fb_var_screeninfo *var, | ||
344 | struct fb_info *info) | ||
345 | { | ||
346 | struct viafb_par *viapar = info->par; | ||
347 | u32 vram_addr = viapar->vram_addr | ||
348 | + var->yoffset * info->fix.line_length | ||
349 | + var->xoffset * info->var.bits_per_pixel / 8; | ||
350 | |||
351 | DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr); | ||
352 | if (!viafb_dual_fb) { | ||
353 | via_set_primary_address(vram_addr); | ||
354 | via_set_secondary_address(vram_addr); | ||
355 | } else if (viapar->iga_path == IGA1) | ||
356 | via_set_primary_address(vram_addr); | ||
357 | else | ||
358 | via_set_secondary_address(vram_addr); | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static int viafb_blank(int blank_mode, struct fb_info *info) | ||
364 | { | ||
365 | DEBUG_MSG(KERN_INFO "viafb_blank!\n"); | ||
366 | /* clear DPMS setting */ | ||
367 | |||
368 | switch (blank_mode) { | ||
369 | case FB_BLANK_UNBLANK: | ||
370 | /* Screen: On, HSync: On, VSync: On */ | ||
371 | /* control CRT monitor power management */ | ||
372 | via_set_state(VIA_CRT, VIA_STATE_ON); | ||
373 | break; | ||
374 | case FB_BLANK_HSYNC_SUSPEND: | ||
375 | /* Screen: Off, HSync: Off, VSync: On */ | ||
376 | /* control CRT monitor power management */ | ||
377 | via_set_state(VIA_CRT, VIA_STATE_STANDBY); | ||
378 | break; | ||
379 | case FB_BLANK_VSYNC_SUSPEND: | ||
380 | /* Screen: Off, HSync: On, VSync: Off */ | ||
381 | /* control CRT monitor power management */ | ||
382 | via_set_state(VIA_CRT, VIA_STATE_SUSPEND); | ||
383 | break; | ||
384 | case FB_BLANK_POWERDOWN: | ||
385 | /* Screen: Off, HSync: Off, VSync: Off */ | ||
386 | /* control CRT monitor power management */ | ||
387 | via_set_state(VIA_CRT, VIA_STATE_OFF); | ||
388 | break; | ||
389 | } | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) | ||
395 | { | ||
396 | union { | ||
397 | struct viafb_ioctl_mode viamode; | ||
398 | struct viafb_ioctl_samm viasamm; | ||
399 | struct viafb_driver_version driver_version; | ||
400 | struct fb_var_screeninfo sec_var; | ||
401 | struct _panel_size_pos_info panel_pos_size_para; | ||
402 | struct viafb_ioctl_setting viafb_setting; | ||
403 | struct device_t active_dev; | ||
404 | } u; | ||
405 | u32 state_info = 0; | ||
406 | u32 *viafb_gamma_table; | ||
407 | char driver_name[] = "viafb"; | ||
408 | |||
409 | u32 __user *argp = (u32 __user *) arg; | ||
410 | u32 gpu32; | ||
411 | |||
412 | DEBUG_MSG(KERN_INFO "viafb_ioctl: 0x%X !!\n", cmd); | ||
413 | printk(KERN_WARNING "viafb_ioctl: Please avoid this interface as it is unstable and might change or vanish at any time!\n"); | ||
414 | memset(&u, 0, sizeof(u)); | ||
415 | |||
416 | switch (cmd) { | ||
417 | case VIAFB_GET_CHIP_INFO: | ||
418 | if (copy_to_user(argp, viaparinfo->chip_info, | ||
419 | sizeof(struct chip_information))) | ||
420 | return -EFAULT; | ||
421 | break; | ||
422 | case VIAFB_GET_INFO_SIZE: | ||
423 | return put_user((u32)sizeof(struct viafb_ioctl_info), argp); | ||
424 | case VIAFB_GET_INFO: | ||
425 | return viafb_ioctl_get_viafb_info(arg); | ||
426 | case VIAFB_HOTPLUG: | ||
427 | return put_user(viafb_ioctl_hotplug(info->var.xres, | ||
428 | info->var.yres, | ||
429 | info->var.bits_per_pixel), argp); | ||
430 | case VIAFB_SET_HOTPLUG_FLAG: | ||
431 | if (copy_from_user(&gpu32, argp, sizeof(gpu32))) | ||
432 | return -EFAULT; | ||
433 | viafb_hotplug = (gpu32) ? 1 : 0; | ||
434 | break; | ||
435 | case VIAFB_GET_RESOLUTION: | ||
436 | u.viamode.xres = (u32) viafb_hotplug_Xres; | ||
437 | u.viamode.yres = (u32) viafb_hotplug_Yres; | ||
438 | u.viamode.refresh = (u32) viafb_hotplug_refresh; | ||
439 | u.viamode.bpp = (u32) viafb_hotplug_bpp; | ||
440 | if (viafb_SAMM_ON == 1) { | ||
441 | u.viamode.xres_sec = viafb_second_xres; | ||
442 | u.viamode.yres_sec = viafb_second_yres; | ||
443 | u.viamode.virtual_xres_sec = viafb_dual_fb ? viafbinfo1->var.xres_virtual : viafbinfo->var.xres_virtual; | ||
444 | u.viamode.virtual_yres_sec = viafb_dual_fb ? viafbinfo1->var.yres_virtual : viafbinfo->var.yres_virtual; | ||
445 | u.viamode.refresh_sec = viafb_refresh1; | ||
446 | u.viamode.bpp_sec = viafb_bpp1; | ||
447 | } else { | ||
448 | u.viamode.xres_sec = 0; | ||
449 | u.viamode.yres_sec = 0; | ||
450 | u.viamode.virtual_xres_sec = 0; | ||
451 | u.viamode.virtual_yres_sec = 0; | ||
452 | u.viamode.refresh_sec = 0; | ||
453 | u.viamode.bpp_sec = 0; | ||
454 | } | ||
455 | if (copy_to_user(argp, &u.viamode, sizeof(u.viamode))) | ||
456 | return -EFAULT; | ||
457 | break; | ||
458 | case VIAFB_GET_SAMM_INFO: | ||
459 | u.viasamm.samm_status = viafb_SAMM_ON; | ||
460 | |||
461 | if (viafb_SAMM_ON == 1) { | ||
462 | if (viafb_dual_fb) { | ||
463 | u.viasamm.size_prim = viaparinfo->fbmem_free; | ||
464 | u.viasamm.size_sec = viaparinfo1->fbmem_free; | ||
465 | } else { | ||
466 | if (viafb_second_size) { | ||
467 | u.viasamm.size_prim = | ||
468 | viaparinfo->fbmem_free - | ||
469 | viafb_second_size * 1024 * 1024; | ||
470 | u.viasamm.size_sec = | ||
471 | viafb_second_size * 1024 * 1024; | ||
472 | } else { | ||
473 | u.viasamm.size_prim = | ||
474 | viaparinfo->fbmem_free >> 1; | ||
475 | u.viasamm.size_sec = | ||
476 | (viaparinfo->fbmem_free >> 1); | ||
477 | } | ||
478 | } | ||
479 | u.viasamm.mem_base = viaparinfo->fbmem; | ||
480 | u.viasamm.offset_sec = viafb_second_offset; | ||
481 | } else { | ||
482 | u.viasamm.size_prim = | ||
483 | viaparinfo->memsize - viaparinfo->fbmem_used; | ||
484 | u.viasamm.size_sec = 0; | ||
485 | u.viasamm.mem_base = viaparinfo->fbmem; | ||
486 | u.viasamm.offset_sec = 0; | ||
487 | } | ||
488 | |||
489 | if (copy_to_user(argp, &u.viasamm, sizeof(u.viasamm))) | ||
490 | return -EFAULT; | ||
491 | |||
492 | break; | ||
493 | case VIAFB_TURN_ON_OUTPUT_DEVICE: | ||
494 | if (copy_from_user(&gpu32, argp, sizeof(gpu32))) | ||
495 | return -EFAULT; | ||
496 | if (gpu32 & CRT_Device) | ||
497 | via_set_state(VIA_CRT, VIA_STATE_ON); | ||
498 | if (gpu32 & DVI_Device) | ||
499 | viafb_dvi_enable(); | ||
500 | if (gpu32 & LCD_Device) | ||
501 | viafb_lcd_enable(); | ||
502 | break; | ||
503 | case VIAFB_TURN_OFF_OUTPUT_DEVICE: | ||
504 | if (copy_from_user(&gpu32, argp, sizeof(gpu32))) | ||
505 | return -EFAULT; | ||
506 | if (gpu32 & CRT_Device) | ||
507 | via_set_state(VIA_CRT, VIA_STATE_OFF); | ||
508 | if (gpu32 & DVI_Device) | ||
509 | viafb_dvi_disable(); | ||
510 | if (gpu32 & LCD_Device) | ||
511 | viafb_lcd_disable(); | ||
512 | break; | ||
513 | case VIAFB_GET_DEVICE: | ||
514 | u.active_dev.crt = viafb_CRT_ON; | ||
515 | u.active_dev.dvi = viafb_DVI_ON; | ||
516 | u.active_dev.lcd = viafb_LCD_ON; | ||
517 | u.active_dev.samm = viafb_SAMM_ON; | ||
518 | u.active_dev.primary_dev = viafb_primary_dev; | ||
519 | |||
520 | u.active_dev.lcd_dsp_cent = viafb_lcd_dsp_method; | ||
521 | u.active_dev.lcd_panel_id = viafb_lcd_panel_id; | ||
522 | u.active_dev.lcd_mode = viafb_lcd_mode; | ||
523 | |||
524 | u.active_dev.xres = viafb_hotplug_Xres; | ||
525 | u.active_dev.yres = viafb_hotplug_Yres; | ||
526 | |||
527 | u.active_dev.xres1 = viafb_second_xres; | ||
528 | u.active_dev.yres1 = viafb_second_yres; | ||
529 | |||
530 | u.active_dev.bpp = viafb_bpp; | ||
531 | u.active_dev.bpp1 = viafb_bpp1; | ||
532 | u.active_dev.refresh = viafb_refresh; | ||
533 | u.active_dev.refresh1 = viafb_refresh1; | ||
534 | |||
535 | u.active_dev.epia_dvi = viafb_platform_epia_dvi; | ||
536 | u.active_dev.lcd_dual_edge = viafb_device_lcd_dualedge; | ||
537 | u.active_dev.bus_width = viafb_bus_width; | ||
538 | |||
539 | if (copy_to_user(argp, &u.active_dev, sizeof(u.active_dev))) | ||
540 | return -EFAULT; | ||
541 | break; | ||
542 | |||
543 | case VIAFB_GET_DRIVER_VERSION: | ||
544 | u.driver_version.iMajorNum = VERSION_MAJOR; | ||
545 | u.driver_version.iKernelNum = VERSION_KERNEL; | ||
546 | u.driver_version.iOSNum = VERSION_OS; | ||
547 | u.driver_version.iMinorNum = VERSION_MINOR; | ||
548 | |||
549 | if (copy_to_user(argp, &u.driver_version, | ||
550 | sizeof(u.driver_version))) | ||
551 | return -EFAULT; | ||
552 | |||
553 | break; | ||
554 | |||
555 | case VIAFB_GET_DEVICE_INFO: | ||
556 | |||
557 | retrieve_device_setting(&u.viafb_setting); | ||
558 | |||
559 | if (copy_to_user(argp, &u.viafb_setting, | ||
560 | sizeof(u.viafb_setting))) | ||
561 | return -EFAULT; | ||
562 | |||
563 | break; | ||
564 | |||
565 | case VIAFB_GET_DEVICE_SUPPORT: | ||
566 | viafb_get_device_support_state(&state_info); | ||
567 | if (put_user(state_info, argp)) | ||
568 | return -EFAULT; | ||
569 | break; | ||
570 | |||
571 | case VIAFB_GET_DEVICE_CONNECT: | ||
572 | viafb_get_device_connect_state(&state_info); | ||
573 | if (put_user(state_info, argp)) | ||
574 | return -EFAULT; | ||
575 | break; | ||
576 | |||
577 | case VIAFB_GET_PANEL_SUPPORT_EXPAND: | ||
578 | state_info = | ||
579 | viafb_lcd_get_support_expand_state(info->var.xres, | ||
580 | info->var.yres); | ||
581 | if (put_user(state_info, argp)) | ||
582 | return -EFAULT; | ||
583 | break; | ||
584 | |||
585 | case VIAFB_GET_DRIVER_NAME: | ||
586 | if (copy_to_user(argp, driver_name, sizeof(driver_name))) | ||
587 | return -EFAULT; | ||
588 | break; | ||
589 | |||
590 | case VIAFB_SET_GAMMA_LUT: | ||
591 | viafb_gamma_table = memdup_user(argp, 256 * sizeof(u32)); | ||
592 | if (IS_ERR(viafb_gamma_table)) | ||
593 | return PTR_ERR(viafb_gamma_table); | ||
594 | viafb_set_gamma_table(viafb_bpp, viafb_gamma_table); | ||
595 | kfree(viafb_gamma_table); | ||
596 | break; | ||
597 | |||
598 | case VIAFB_GET_GAMMA_LUT: | ||
599 | viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL); | ||
600 | if (!viafb_gamma_table) | ||
601 | return -ENOMEM; | ||
602 | viafb_get_gamma_table(viafb_gamma_table); | ||
603 | if (copy_to_user(argp, viafb_gamma_table, | ||
604 | 256 * sizeof(u32))) { | ||
605 | kfree(viafb_gamma_table); | ||
606 | return -EFAULT; | ||
607 | } | ||
608 | kfree(viafb_gamma_table); | ||
609 | break; | ||
610 | |||
611 | case VIAFB_GET_GAMMA_SUPPORT_STATE: | ||
612 | viafb_get_gamma_support_state(viafb_bpp, &state_info); | ||
613 | if (put_user(state_info, argp)) | ||
614 | return -EFAULT; | ||
615 | break; | ||
616 | case VIAFB_SYNC_SURFACE: | ||
617 | DEBUG_MSG(KERN_INFO "lobo VIAFB_SYNC_SURFACE\n"); | ||
618 | break; | ||
619 | case VIAFB_GET_DRIVER_CAPS: | ||
620 | break; | ||
621 | |||
622 | case VIAFB_GET_PANEL_MAX_SIZE: | ||
623 | if (copy_from_user(&u.panel_pos_size_para, argp, | ||
624 | sizeof(u.panel_pos_size_para))) | ||
625 | return -EFAULT; | ||
626 | u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0; | ||
627 | if (copy_to_user(argp, &u.panel_pos_size_para, | ||
628 | sizeof(u.panel_pos_size_para))) | ||
629 | return -EFAULT; | ||
630 | break; | ||
631 | case VIAFB_GET_PANEL_MAX_POSITION: | ||
632 | if (copy_from_user(&u.panel_pos_size_para, argp, | ||
633 | sizeof(u.panel_pos_size_para))) | ||
634 | return -EFAULT; | ||
635 | u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0; | ||
636 | if (copy_to_user(argp, &u.panel_pos_size_para, | ||
637 | sizeof(u.panel_pos_size_para))) | ||
638 | return -EFAULT; | ||
639 | break; | ||
640 | |||
641 | case VIAFB_GET_PANEL_POSITION: | ||
642 | if (copy_from_user(&u.panel_pos_size_para, argp, | ||
643 | sizeof(u.panel_pos_size_para))) | ||
644 | return -EFAULT; | ||
645 | u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0; | ||
646 | if (copy_to_user(argp, &u.panel_pos_size_para, | ||
647 | sizeof(u.panel_pos_size_para))) | ||
648 | return -EFAULT; | ||
649 | break; | ||
650 | case VIAFB_GET_PANEL_SIZE: | ||
651 | if (copy_from_user(&u.panel_pos_size_para, argp, | ||
652 | sizeof(u.panel_pos_size_para))) | ||
653 | return -EFAULT; | ||
654 | u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0; | ||
655 | if (copy_to_user(argp, &u.panel_pos_size_para, | ||
656 | sizeof(u.panel_pos_size_para))) | ||
657 | return -EFAULT; | ||
658 | break; | ||
659 | |||
660 | case VIAFB_SET_PANEL_POSITION: | ||
661 | if (copy_from_user(&u.panel_pos_size_para, argp, | ||
662 | sizeof(u.panel_pos_size_para))) | ||
663 | return -EFAULT; | ||
664 | break; | ||
665 | case VIAFB_SET_PANEL_SIZE: | ||
666 | if (copy_from_user(&u.panel_pos_size_para, argp, | ||
667 | sizeof(u.panel_pos_size_para))) | ||
668 | return -EFAULT; | ||
669 | break; | ||
670 | |||
671 | default: | ||
672 | return -EINVAL; | ||
673 | } | ||
674 | |||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static void viafb_fillrect(struct fb_info *info, | ||
679 | const struct fb_fillrect *rect) | ||
680 | { | ||
681 | struct viafb_par *viapar = info->par; | ||
682 | struct viafb_shared *shared = viapar->shared; | ||
683 | u32 fg_color; | ||
684 | u8 rop; | ||
685 | |||
686 | if (info->flags & FBINFO_HWACCEL_DISABLED || !shared->hw_bitblt) { | ||
687 | cfb_fillrect(info, rect); | ||
688 | return; | ||
689 | } | ||
690 | |||
691 | if (!rect->width || !rect->height) | ||
692 | return; | ||
693 | |||
694 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) | ||
695 | fg_color = ((u32 *)info->pseudo_palette)[rect->color]; | ||
696 | else | ||
697 | fg_color = rect->color; | ||
698 | |||
699 | if (rect->rop == ROP_XOR) | ||
700 | rop = 0x5A; | ||
701 | else | ||
702 | rop = 0xF0; | ||
703 | |||
704 | DEBUG_MSG(KERN_DEBUG "viafb 2D engine: fillrect\n"); | ||
705 | if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_FILL, | ||
706 | rect->width, rect->height, info->var.bits_per_pixel, | ||
707 | viapar->vram_addr, info->fix.line_length, rect->dx, rect->dy, | ||
708 | NULL, 0, 0, 0, 0, fg_color, 0, rop)) | ||
709 | cfb_fillrect(info, rect); | ||
710 | } | ||
711 | |||
712 | static void viafb_copyarea(struct fb_info *info, | ||
713 | const struct fb_copyarea *area) | ||
714 | { | ||
715 | struct viafb_par *viapar = info->par; | ||
716 | struct viafb_shared *shared = viapar->shared; | ||
717 | |||
718 | if (info->flags & FBINFO_HWACCEL_DISABLED || !shared->hw_bitblt) { | ||
719 | cfb_copyarea(info, area); | ||
720 | return; | ||
721 | } | ||
722 | |||
723 | if (!area->width || !area->height) | ||
724 | return; | ||
725 | |||
726 | DEBUG_MSG(KERN_DEBUG "viafb 2D engine: copyarea\n"); | ||
727 | if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_COLOR, | ||
728 | area->width, area->height, info->var.bits_per_pixel, | ||
729 | viapar->vram_addr, info->fix.line_length, area->dx, area->dy, | ||
730 | NULL, viapar->vram_addr, info->fix.line_length, | ||
731 | area->sx, area->sy, 0, 0, 0)) | ||
732 | cfb_copyarea(info, area); | ||
733 | } | ||
734 | |||
735 | static void viafb_imageblit(struct fb_info *info, | ||
736 | const struct fb_image *image) | ||
737 | { | ||
738 | struct viafb_par *viapar = info->par; | ||
739 | struct viafb_shared *shared = viapar->shared; | ||
740 | u32 fg_color = 0, bg_color = 0; | ||
741 | u8 op; | ||
742 | |||
743 | if (info->flags & FBINFO_HWACCEL_DISABLED || !shared->hw_bitblt || | ||
744 | (image->depth != 1 && image->depth != viapar->depth)) { | ||
745 | cfb_imageblit(info, image); | ||
746 | return; | ||
747 | } | ||
748 | |||
749 | if (image->depth == 1) { | ||
750 | op = VIA_BITBLT_MONO; | ||
751 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) { | ||
752 | fg_color = | ||
753 | ((u32 *)info->pseudo_palette)[image->fg_color]; | ||
754 | bg_color = | ||
755 | ((u32 *)info->pseudo_palette)[image->bg_color]; | ||
756 | } else { | ||
757 | fg_color = image->fg_color; | ||
758 | bg_color = image->bg_color; | ||
759 | } | ||
760 | } else | ||
761 | op = VIA_BITBLT_COLOR; | ||
762 | |||
763 | DEBUG_MSG(KERN_DEBUG "viafb 2D engine: imageblit\n"); | ||
764 | if (shared->hw_bitblt(shared->vdev->engine_mmio, op, | ||
765 | image->width, image->height, info->var.bits_per_pixel, | ||
766 | viapar->vram_addr, info->fix.line_length, image->dx, image->dy, | ||
767 | (u32 *)image->data, 0, 0, 0, 0, fg_color, bg_color, 0)) | ||
768 | cfb_imageblit(info, image); | ||
769 | } | ||
770 | |||
771 | static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor) | ||
772 | { | ||
773 | struct viafb_par *viapar = info->par; | ||
774 | void __iomem *engine = viapar->shared->vdev->engine_mmio; | ||
775 | u32 temp, xx, yy, bg_color = 0, fg_color = 0, | ||
776 | chip_name = viapar->shared->chip_info.gfx_chip_name; | ||
777 | int i, j = 0, cur_size = 64; | ||
778 | |||
779 | if (info->flags & FBINFO_HWACCEL_DISABLED || info != viafbinfo) | ||
780 | return -ENODEV; | ||
781 | |||
782 | /* LCD ouput does not support hw cursors (at least on VN896) */ | ||
783 | if ((chip_name == UNICHROME_CLE266 && viapar->iga_path == IGA2) || | ||
784 | viafb_LCD_ON) | ||
785 | return -ENODEV; | ||
786 | |||
787 | viafb_show_hw_cursor(info, HW_Cursor_OFF); | ||
788 | |||
789 | if (cursor->set & FB_CUR_SETHOT) { | ||
790 | temp = (cursor->hot.x << 16) + cursor->hot.y; | ||
791 | writel(temp, engine + VIA_REG_CURSOR_ORG); | ||
792 | } | ||
793 | |||
794 | if (cursor->set & FB_CUR_SETPOS) { | ||
795 | yy = cursor->image.dy - info->var.yoffset; | ||
796 | xx = cursor->image.dx - info->var.xoffset; | ||
797 | temp = yy & 0xFFFF; | ||
798 | temp |= (xx << 16); | ||
799 | writel(temp, engine + VIA_REG_CURSOR_POS); | ||
800 | } | ||
801 | |||
802 | if (cursor->image.width <= 32 && cursor->image.height <= 32) | ||
803 | cur_size = 32; | ||
804 | else if (cursor->image.width <= 64 && cursor->image.height <= 64) | ||
805 | cur_size = 64; | ||
806 | else { | ||
807 | printk(KERN_WARNING "viafb_cursor: The cursor is too large " | ||
808 | "%dx%d", cursor->image.width, cursor->image.height); | ||
809 | return -ENXIO; | ||
810 | } | ||
811 | |||
812 | if (cursor->set & FB_CUR_SETSIZE) { | ||
813 | temp = readl(engine + VIA_REG_CURSOR_MODE); | ||
814 | if (cur_size == 32) | ||
815 | temp |= 0x2; | ||
816 | else | ||
817 | temp &= ~0x2; | ||
818 | |||
819 | writel(temp, engine + VIA_REG_CURSOR_MODE); | ||
820 | } | ||
821 | |||
822 | if (cursor->set & FB_CUR_SETCMAP) { | ||
823 | fg_color = cursor->image.fg_color; | ||
824 | bg_color = cursor->image.bg_color; | ||
825 | if (chip_name == UNICHROME_CX700 || | ||
826 | chip_name == UNICHROME_VX800 || | ||
827 | chip_name == UNICHROME_VX855 || | ||
828 | chip_name == UNICHROME_VX900) { | ||
829 | fg_color = | ||
830 | ((info->cmap.red[fg_color] & 0xFFC0) << 14) | | ||
831 | ((info->cmap.green[fg_color] & 0xFFC0) << 4) | | ||
832 | ((info->cmap.blue[fg_color] & 0xFFC0) >> 6); | ||
833 | bg_color = | ||
834 | ((info->cmap.red[bg_color] & 0xFFC0) << 14) | | ||
835 | ((info->cmap.green[bg_color] & 0xFFC0) << 4) | | ||
836 | ((info->cmap.blue[bg_color] & 0xFFC0) >> 6); | ||
837 | } else { | ||
838 | fg_color = | ||
839 | ((info->cmap.red[fg_color] & 0xFF00) << 8) | | ||
840 | (info->cmap.green[fg_color] & 0xFF00) | | ||
841 | ((info->cmap.blue[fg_color] & 0xFF00) >> 8); | ||
842 | bg_color = | ||
843 | ((info->cmap.red[bg_color] & 0xFF00) << 8) | | ||
844 | (info->cmap.green[bg_color] & 0xFF00) | | ||
845 | ((info->cmap.blue[bg_color] & 0xFF00) >> 8); | ||
846 | } | ||
847 | |||
848 | writel(bg_color, engine + VIA_REG_CURSOR_BG); | ||
849 | writel(fg_color, engine + VIA_REG_CURSOR_FG); | ||
850 | } | ||
851 | |||
852 | if (cursor->set & FB_CUR_SETSHAPE) { | ||
853 | struct { | ||
854 | u8 data[CURSOR_SIZE]; | ||
855 | u32 bak[CURSOR_SIZE / 4]; | ||
856 | } *cr_data = kzalloc(sizeof(*cr_data), GFP_ATOMIC); | ||
857 | int size = ((cursor->image.width + 7) >> 3) * | ||
858 | cursor->image.height; | ||
859 | |||
860 | if (!cr_data) | ||
861 | return -ENOMEM; | ||
862 | |||
863 | if (cur_size == 32) { | ||
864 | for (i = 0; i < (CURSOR_SIZE / 4); i++) { | ||
865 | cr_data->bak[i] = 0x0; | ||
866 | cr_data->bak[i + 1] = 0xFFFFFFFF; | ||
867 | i += 1; | ||
868 | } | ||
869 | } else { | ||
870 | for (i = 0; i < (CURSOR_SIZE / 4); i++) { | ||
871 | cr_data->bak[i] = 0x0; | ||
872 | cr_data->bak[i + 1] = 0x0; | ||
873 | cr_data->bak[i + 2] = 0xFFFFFFFF; | ||
874 | cr_data->bak[i + 3] = 0xFFFFFFFF; | ||
875 | i += 3; | ||
876 | } | ||
877 | } | ||
878 | |||
879 | switch (cursor->rop) { | ||
880 | case ROP_XOR: | ||
881 | for (i = 0; i < size; i++) | ||
882 | cr_data->data[i] = cursor->mask[i]; | ||
883 | break; | ||
884 | case ROP_COPY: | ||
885 | |||
886 | for (i = 0; i < size; i++) | ||
887 | cr_data->data[i] = cursor->mask[i]; | ||
888 | break; | ||
889 | default: | ||
890 | break; | ||
891 | } | ||
892 | |||
893 | if (cur_size == 32) { | ||
894 | for (i = 0; i < size; i++) { | ||
895 | cr_data->bak[j] = (u32) cr_data->data[i]; | ||
896 | cr_data->bak[j + 1] = ~cr_data->bak[j]; | ||
897 | j += 2; | ||
898 | } | ||
899 | } else { | ||
900 | for (i = 0; i < size; i++) { | ||
901 | cr_data->bak[j] = (u32) cr_data->data[i]; | ||
902 | cr_data->bak[j + 1] = 0x0; | ||
903 | cr_data->bak[j + 2] = ~cr_data->bak[j]; | ||
904 | cr_data->bak[j + 3] = ~cr_data->bak[j + 1]; | ||
905 | j += 4; | ||
906 | } | ||
907 | } | ||
908 | |||
909 | memcpy_toio(viafbinfo->screen_base + viapar->shared-> | ||
910 | cursor_vram_addr, cr_data->bak, CURSOR_SIZE); | ||
911 | kfree(cr_data); | ||
912 | } | ||
913 | |||
914 | if (cursor->enable) | ||
915 | viafb_show_hw_cursor(info, HW_Cursor_ON); | ||
916 | |||
917 | return 0; | ||
918 | } | ||
919 | |||
920 | static int viafb_sync(struct fb_info *info) | ||
921 | { | ||
922 | if (!(info->flags & FBINFO_HWACCEL_DISABLED)) | ||
923 | viafb_wait_engine_idle(info); | ||
924 | return 0; | ||
925 | } | ||
926 | |||
927 | static int get_primary_device(void) | ||
928 | { | ||
929 | int primary_device = 0; | ||
930 | /* Rule: device on iga1 path are the primary device. */ | ||
931 | if (viafb_SAMM_ON) { | ||
932 | if (viafb_CRT_ON) { | ||
933 | if (viaparinfo->shared->iga1_devices & VIA_CRT) { | ||
934 | DEBUG_MSG(KERN_INFO "CRT IGA Path:%d\n", IGA1); | ||
935 | primary_device = CRT_Device; | ||
936 | } | ||
937 | } | ||
938 | if (viafb_DVI_ON) { | ||
939 | if (viaparinfo->tmds_setting_info->iga_path == IGA1) { | ||
940 | DEBUG_MSG(KERN_INFO "DVI IGA Path:%d\n", | ||
941 | viaparinfo-> | ||
942 | tmds_setting_info->iga_path); | ||
943 | primary_device = DVI_Device; | ||
944 | } | ||
945 | } | ||
946 | if (viafb_LCD_ON) { | ||
947 | if (viaparinfo->lvds_setting_info->iga_path == IGA1) { | ||
948 | DEBUG_MSG(KERN_INFO "LCD IGA Path:%d\n", | ||
949 | viaparinfo-> | ||
950 | lvds_setting_info->iga_path); | ||
951 | primary_device = LCD_Device; | ||
952 | } | ||
953 | } | ||
954 | if (viafb_LCD2_ON) { | ||
955 | if (viaparinfo->lvds_setting_info2->iga_path == IGA1) { | ||
956 | DEBUG_MSG(KERN_INFO "LCD2 IGA Path:%d\n", | ||
957 | viaparinfo-> | ||
958 | lvds_setting_info2->iga_path); | ||
959 | primary_device = LCD2_Device; | ||
960 | } | ||
961 | } | ||
962 | } | ||
963 | return primary_device; | ||
964 | } | ||
965 | |||
966 | static void retrieve_device_setting(struct viafb_ioctl_setting | ||
967 | *setting_info) | ||
968 | { | ||
969 | |||
970 | /* get device status */ | ||
971 | if (viafb_CRT_ON == 1) | ||
972 | setting_info->device_status = CRT_Device; | ||
973 | if (viafb_DVI_ON == 1) | ||
974 | setting_info->device_status |= DVI_Device; | ||
975 | if (viafb_LCD_ON == 1) | ||
976 | setting_info->device_status |= LCD_Device; | ||
977 | if (viafb_LCD2_ON == 1) | ||
978 | setting_info->device_status |= LCD2_Device; | ||
979 | |||
980 | setting_info->samm_status = viafb_SAMM_ON; | ||
981 | setting_info->primary_device = get_primary_device(); | ||
982 | |||
983 | setting_info->first_dev_bpp = viafb_bpp; | ||
984 | setting_info->second_dev_bpp = viafb_bpp1; | ||
985 | |||
986 | setting_info->first_dev_refresh = viafb_refresh; | ||
987 | setting_info->second_dev_refresh = viafb_refresh1; | ||
988 | |||
989 | setting_info->first_dev_hor_res = viafb_hotplug_Xres; | ||
990 | setting_info->first_dev_ver_res = viafb_hotplug_Yres; | ||
991 | setting_info->second_dev_hor_res = viafb_second_xres; | ||
992 | setting_info->second_dev_ver_res = viafb_second_yres; | ||
993 | |||
994 | /* Get lcd attributes */ | ||
995 | setting_info->lcd_attributes.display_center = viafb_lcd_dsp_method; | ||
996 | setting_info->lcd_attributes.panel_id = viafb_lcd_panel_id; | ||
997 | setting_info->lcd_attributes.lcd_mode = viafb_lcd_mode; | ||
998 | } | ||
999 | |||
1000 | static int __init parse_active_dev(void) | ||
1001 | { | ||
1002 | viafb_CRT_ON = STATE_OFF; | ||
1003 | viafb_DVI_ON = STATE_OFF; | ||
1004 | viafb_LCD_ON = STATE_OFF; | ||
1005 | viafb_LCD2_ON = STATE_OFF; | ||
1006 | /* 1. Modify the active status of devices. */ | ||
1007 | /* 2. Keep the order of devices, so we can set corresponding | ||
1008 | IGA path to devices in SAMM case. */ | ||
1009 | /* Note: The previous of active_dev is primary device, | ||
1010 | and the following is secondary device. */ | ||
1011 | if (!viafb_active_dev) { | ||
1012 | if (machine_is_olpc()) { /* LCD only */ | ||
1013 | viafb_LCD_ON = STATE_ON; | ||
1014 | viafb_SAMM_ON = STATE_OFF; | ||
1015 | } else { | ||
1016 | viafb_CRT_ON = STATE_ON; | ||
1017 | viafb_SAMM_ON = STATE_OFF; | ||
1018 | } | ||
1019 | } else if (!strcmp(viafb_active_dev, "CRT+DVI")) { | ||
1020 | /* CRT+DVI */ | ||
1021 | viafb_CRT_ON = STATE_ON; | ||
1022 | viafb_DVI_ON = STATE_ON; | ||
1023 | viafb_primary_dev = CRT_Device; | ||
1024 | } else if (!strcmp(viafb_active_dev, "DVI+CRT")) { | ||
1025 | /* DVI+CRT */ | ||
1026 | viafb_CRT_ON = STATE_ON; | ||
1027 | viafb_DVI_ON = STATE_ON; | ||
1028 | viafb_primary_dev = DVI_Device; | ||
1029 | } else if (!strcmp(viafb_active_dev, "CRT+LCD")) { | ||
1030 | /* CRT+LCD */ | ||
1031 | viafb_CRT_ON = STATE_ON; | ||
1032 | viafb_LCD_ON = STATE_ON; | ||
1033 | viafb_primary_dev = CRT_Device; | ||
1034 | } else if (!strcmp(viafb_active_dev, "LCD+CRT")) { | ||
1035 | /* LCD+CRT */ | ||
1036 | viafb_CRT_ON = STATE_ON; | ||
1037 | viafb_LCD_ON = STATE_ON; | ||
1038 | viafb_primary_dev = LCD_Device; | ||
1039 | } else if (!strcmp(viafb_active_dev, "DVI+LCD")) { | ||
1040 | /* DVI+LCD */ | ||
1041 | viafb_DVI_ON = STATE_ON; | ||
1042 | viafb_LCD_ON = STATE_ON; | ||
1043 | viafb_primary_dev = DVI_Device; | ||
1044 | } else if (!strcmp(viafb_active_dev, "LCD+DVI")) { | ||
1045 | /* LCD+DVI */ | ||
1046 | viafb_DVI_ON = STATE_ON; | ||
1047 | viafb_LCD_ON = STATE_ON; | ||
1048 | viafb_primary_dev = LCD_Device; | ||
1049 | } else if (!strcmp(viafb_active_dev, "LCD+LCD2")) { | ||
1050 | viafb_LCD_ON = STATE_ON; | ||
1051 | viafb_LCD2_ON = STATE_ON; | ||
1052 | viafb_primary_dev = LCD_Device; | ||
1053 | } else if (!strcmp(viafb_active_dev, "LCD2+LCD")) { | ||
1054 | viafb_LCD_ON = STATE_ON; | ||
1055 | viafb_LCD2_ON = STATE_ON; | ||
1056 | viafb_primary_dev = LCD2_Device; | ||
1057 | } else if (!strcmp(viafb_active_dev, "CRT")) { | ||
1058 | /* CRT only */ | ||
1059 | viafb_CRT_ON = STATE_ON; | ||
1060 | viafb_SAMM_ON = STATE_OFF; | ||
1061 | } else if (!strcmp(viafb_active_dev, "DVI")) { | ||
1062 | /* DVI only */ | ||
1063 | viafb_DVI_ON = STATE_ON; | ||
1064 | viafb_SAMM_ON = STATE_OFF; | ||
1065 | } else if (!strcmp(viafb_active_dev, "LCD")) { | ||
1066 | /* LCD only */ | ||
1067 | viafb_LCD_ON = STATE_ON; | ||
1068 | viafb_SAMM_ON = STATE_OFF; | ||
1069 | } else | ||
1070 | return -EINVAL; | ||
1071 | |||
1072 | return 0; | ||
1073 | } | ||
1074 | |||
1075 | static int parse_port(char *opt_str, int *output_interface) | ||
1076 | { | ||
1077 | if (!strncmp(opt_str, "DVP0", 4)) | ||
1078 | *output_interface = INTERFACE_DVP0; | ||
1079 | else if (!strncmp(opt_str, "DVP1", 4)) | ||
1080 | *output_interface = INTERFACE_DVP1; | ||
1081 | else if (!strncmp(opt_str, "DFP_HIGHLOW", 11)) | ||
1082 | *output_interface = INTERFACE_DFP; | ||
1083 | else if (!strncmp(opt_str, "DFP_HIGH", 8)) | ||
1084 | *output_interface = INTERFACE_DFP_HIGH; | ||
1085 | else if (!strncmp(opt_str, "DFP_LOW", 7)) | ||
1086 | *output_interface = INTERFACE_DFP_LOW; | ||
1087 | else | ||
1088 | *output_interface = INTERFACE_NONE; | ||
1089 | return 0; | ||
1090 | } | ||
1091 | |||
1092 | static void parse_lcd_port(void) | ||
1093 | { | ||
1094 | parse_port(viafb_lcd_port, &viaparinfo->chip_info->lvds_chip_info. | ||
1095 | output_interface); | ||
1096 | /*Initialize to avoid unexpected behavior */ | ||
1097 | viaparinfo->chip_info->lvds_chip_info2.output_interface = | ||
1098 | INTERFACE_NONE; | ||
1099 | |||
1100 | DEBUG_MSG(KERN_INFO "parse_lcd_port: viafb_lcd_port:%s,interface:%d\n", | ||
1101 | viafb_lcd_port, viaparinfo->chip_info->lvds_chip_info. | ||
1102 | output_interface); | ||
1103 | } | ||
1104 | |||
1105 | static void parse_dvi_port(void) | ||
1106 | { | ||
1107 | parse_port(viafb_dvi_port, &viaparinfo->chip_info->tmds_chip_info. | ||
1108 | output_interface); | ||
1109 | |||
1110 | DEBUG_MSG(KERN_INFO "parse_dvi_port: viafb_dvi_port:%s,interface:%d\n", | ||
1111 | viafb_dvi_port, viaparinfo->chip_info->tmds_chip_info. | ||
1112 | output_interface); | ||
1113 | } | ||
1114 | |||
1115 | #ifdef CONFIG_FB_VIA_DIRECT_PROCFS | ||
1116 | |||
1117 | /* | ||
1118 | * The proc filesystem read/write function, a simple proc implement to | ||
1119 | * get/set the value of DPA DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1, | ||
1120 | * DVP1Driving, DFPHigh, DFPLow CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], | ||
1121 | * CR9B, SR65, CR97, CR99 | ||
1122 | */ | ||
1123 | static int viafb_dvp0_proc_show(struct seq_file *m, void *v) | ||
1124 | { | ||
1125 | u8 dvp0_data_dri = 0, dvp0_clk_dri = 0, dvp0 = 0; | ||
1126 | dvp0_data_dri = | ||
1127 | (viafb_read_reg(VIASR, SR2A) & BIT5) >> 4 | | ||
1128 | (viafb_read_reg(VIASR, SR1B) & BIT1) >> 1; | ||
1129 | dvp0_clk_dri = | ||
1130 | (viafb_read_reg(VIASR, SR2A) & BIT4) >> 3 | | ||
1131 | (viafb_read_reg(VIASR, SR1E) & BIT2) >> 2; | ||
1132 | dvp0 = viafb_read_reg(VIACR, CR96) & 0x0f; | ||
1133 | seq_printf(m, "%x %x %x\n", dvp0, dvp0_data_dri, dvp0_clk_dri); | ||
1134 | return 0; | ||
1135 | } | ||
1136 | |||
1137 | static int viafb_dvp0_proc_open(struct inode *inode, struct file *file) | ||
1138 | { | ||
1139 | return single_open(file, viafb_dvp0_proc_show, NULL); | ||
1140 | } | ||
1141 | |||
1142 | static ssize_t viafb_dvp0_proc_write(struct file *file, | ||
1143 | const char __user *buffer, size_t count, loff_t *pos) | ||
1144 | { | ||
1145 | char buf[20], *value, *pbuf; | ||
1146 | u8 reg_val = 0; | ||
1147 | unsigned long length, i; | ||
1148 | if (count < 1) | ||
1149 | return -EINVAL; | ||
1150 | length = count > 20 ? 20 : count; | ||
1151 | if (copy_from_user(&buf[0], buffer, length)) | ||
1152 | return -EFAULT; | ||
1153 | buf[length - 1] = '\0'; /*Ensure end string */ | ||
1154 | pbuf = &buf[0]; | ||
1155 | for (i = 0; i < 3; i++) { | ||
1156 | value = strsep(&pbuf, " "); | ||
1157 | if (value != NULL) { | ||
1158 | if (kstrtou8(value, 0, ®_val) < 0) | ||
1159 | return -EINVAL; | ||
1160 | DEBUG_MSG(KERN_INFO "DVP0:reg_val[%l]=:%x\n", i, | ||
1161 | reg_val); | ||
1162 | switch (i) { | ||
1163 | case 0: | ||
1164 | viafb_write_reg_mask(CR96, VIACR, | ||
1165 | reg_val, 0x0f); | ||
1166 | break; | ||
1167 | case 1: | ||
1168 | viafb_write_reg_mask(SR2A, VIASR, | ||
1169 | reg_val << 4, BIT5); | ||
1170 | viafb_write_reg_mask(SR1B, VIASR, | ||
1171 | reg_val << 1, BIT1); | ||
1172 | break; | ||
1173 | case 2: | ||
1174 | viafb_write_reg_mask(SR2A, VIASR, | ||
1175 | reg_val << 3, BIT4); | ||
1176 | viafb_write_reg_mask(SR1E, VIASR, | ||
1177 | reg_val << 2, BIT2); | ||
1178 | break; | ||
1179 | default: | ||
1180 | break; | ||
1181 | } | ||
1182 | } else { | ||
1183 | break; | ||
1184 | } | ||
1185 | } | ||
1186 | return count; | ||
1187 | } | ||
1188 | |||
1189 | static const struct file_operations viafb_dvp0_proc_fops = { | ||
1190 | .owner = THIS_MODULE, | ||
1191 | .open = viafb_dvp0_proc_open, | ||
1192 | .read = seq_read, | ||
1193 | .llseek = seq_lseek, | ||
1194 | .release = single_release, | ||
1195 | .write = viafb_dvp0_proc_write, | ||
1196 | }; | ||
1197 | |||
1198 | static int viafb_dvp1_proc_show(struct seq_file *m, void *v) | ||
1199 | { | ||
1200 | u8 dvp1 = 0, dvp1_data_dri = 0, dvp1_clk_dri = 0; | ||
1201 | dvp1 = viafb_read_reg(VIACR, CR9B) & 0x0f; | ||
1202 | dvp1_data_dri = (viafb_read_reg(VIASR, SR65) & 0x0c) >> 2; | ||
1203 | dvp1_clk_dri = viafb_read_reg(VIASR, SR65) & 0x03; | ||
1204 | seq_printf(m, "%x %x %x\n", dvp1, dvp1_data_dri, dvp1_clk_dri); | ||
1205 | return 0; | ||
1206 | } | ||
1207 | |||
1208 | static int viafb_dvp1_proc_open(struct inode *inode, struct file *file) | ||
1209 | { | ||
1210 | return single_open(file, viafb_dvp1_proc_show, NULL); | ||
1211 | } | ||
1212 | |||
1213 | static ssize_t viafb_dvp1_proc_write(struct file *file, | ||
1214 | const char __user *buffer, size_t count, loff_t *pos) | ||
1215 | { | ||
1216 | char buf[20], *value, *pbuf; | ||
1217 | u8 reg_val = 0; | ||
1218 | unsigned long length, i; | ||
1219 | if (count < 1) | ||
1220 | return -EINVAL; | ||
1221 | length = count > 20 ? 20 : count; | ||
1222 | if (copy_from_user(&buf[0], buffer, length)) | ||
1223 | return -EFAULT; | ||
1224 | buf[length - 1] = '\0'; /*Ensure end string */ | ||
1225 | pbuf = &buf[0]; | ||
1226 | for (i = 0; i < 3; i++) { | ||
1227 | value = strsep(&pbuf, " "); | ||
1228 | if (value != NULL) { | ||
1229 | if (kstrtou8(value, 0, ®_val) < 0) | ||
1230 | return -EINVAL; | ||
1231 | switch (i) { | ||
1232 | case 0: | ||
1233 | viafb_write_reg_mask(CR9B, VIACR, | ||
1234 | reg_val, 0x0f); | ||
1235 | break; | ||
1236 | case 1: | ||
1237 | viafb_write_reg_mask(SR65, VIASR, | ||
1238 | reg_val << 2, 0x0c); | ||
1239 | break; | ||
1240 | case 2: | ||
1241 | viafb_write_reg_mask(SR65, VIASR, | ||
1242 | reg_val, 0x03); | ||
1243 | break; | ||
1244 | default: | ||
1245 | break; | ||
1246 | } | ||
1247 | } else { | ||
1248 | break; | ||
1249 | } | ||
1250 | } | ||
1251 | return count; | ||
1252 | } | ||
1253 | |||
1254 | static const struct file_operations viafb_dvp1_proc_fops = { | ||
1255 | .owner = THIS_MODULE, | ||
1256 | .open = viafb_dvp1_proc_open, | ||
1257 | .read = seq_read, | ||
1258 | .llseek = seq_lseek, | ||
1259 | .release = single_release, | ||
1260 | .write = viafb_dvp1_proc_write, | ||
1261 | }; | ||
1262 | |||
1263 | static int viafb_dfph_proc_show(struct seq_file *m, void *v) | ||
1264 | { | ||
1265 | u8 dfp_high = 0; | ||
1266 | dfp_high = viafb_read_reg(VIACR, CR97) & 0x0f; | ||
1267 | seq_printf(m, "%x\n", dfp_high); | ||
1268 | return 0; | ||
1269 | } | ||
1270 | |||
1271 | static int viafb_dfph_proc_open(struct inode *inode, struct file *file) | ||
1272 | { | ||
1273 | return single_open(file, viafb_dfph_proc_show, NULL); | ||
1274 | } | ||
1275 | |||
1276 | static ssize_t viafb_dfph_proc_write(struct file *file, | ||
1277 | const char __user *buffer, size_t count, loff_t *pos) | ||
1278 | { | ||
1279 | int err; | ||
1280 | u8 reg_val; | ||
1281 | err = kstrtou8_from_user(buffer, count, 0, ®_val); | ||
1282 | if (err) | ||
1283 | return err; | ||
1284 | |||
1285 | viafb_write_reg_mask(CR97, VIACR, reg_val, 0x0f); | ||
1286 | return count; | ||
1287 | } | ||
1288 | |||
1289 | static const struct file_operations viafb_dfph_proc_fops = { | ||
1290 | .owner = THIS_MODULE, | ||
1291 | .open = viafb_dfph_proc_open, | ||
1292 | .read = seq_read, | ||
1293 | .llseek = seq_lseek, | ||
1294 | .release = single_release, | ||
1295 | .write = viafb_dfph_proc_write, | ||
1296 | }; | ||
1297 | |||
1298 | static int viafb_dfpl_proc_show(struct seq_file *m, void *v) | ||
1299 | { | ||
1300 | u8 dfp_low = 0; | ||
1301 | dfp_low = viafb_read_reg(VIACR, CR99) & 0x0f; | ||
1302 | seq_printf(m, "%x\n", dfp_low); | ||
1303 | return 0; | ||
1304 | } | ||
1305 | |||
1306 | static int viafb_dfpl_proc_open(struct inode *inode, struct file *file) | ||
1307 | { | ||
1308 | return single_open(file, viafb_dfpl_proc_show, NULL); | ||
1309 | } | ||
1310 | |||
1311 | static ssize_t viafb_dfpl_proc_write(struct file *file, | ||
1312 | const char __user *buffer, size_t count, loff_t *pos) | ||
1313 | { | ||
1314 | int err; | ||
1315 | u8 reg_val; | ||
1316 | err = kstrtou8_from_user(buffer, count, 0, ®_val); | ||
1317 | if (err) | ||
1318 | return err; | ||
1319 | |||
1320 | viafb_write_reg_mask(CR99, VIACR, reg_val, 0x0f); | ||
1321 | return count; | ||
1322 | } | ||
1323 | |||
1324 | static const struct file_operations viafb_dfpl_proc_fops = { | ||
1325 | .owner = THIS_MODULE, | ||
1326 | .open = viafb_dfpl_proc_open, | ||
1327 | .read = seq_read, | ||
1328 | .llseek = seq_lseek, | ||
1329 | .release = single_release, | ||
1330 | .write = viafb_dfpl_proc_write, | ||
1331 | }; | ||
1332 | |||
1333 | static int viafb_vt1636_proc_show(struct seq_file *m, void *v) | ||
1334 | { | ||
1335 | u8 vt1636_08 = 0, vt1636_09 = 0; | ||
1336 | switch (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) { | ||
1337 | case VT1636_LVDS: | ||
1338 | vt1636_08 = | ||
1339 | viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info, | ||
1340 | &viaparinfo->chip_info->lvds_chip_info, 0x08) & 0x0f; | ||
1341 | vt1636_09 = | ||
1342 | viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info, | ||
1343 | &viaparinfo->chip_info->lvds_chip_info, 0x09) & 0x1f; | ||
1344 | seq_printf(m, "%x %x\n", vt1636_08, vt1636_09); | ||
1345 | break; | ||
1346 | default: | ||
1347 | break; | ||
1348 | } | ||
1349 | switch (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) { | ||
1350 | case VT1636_LVDS: | ||
1351 | vt1636_08 = | ||
1352 | viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info2, | ||
1353 | &viaparinfo->chip_info->lvds_chip_info2, 0x08) & 0x0f; | ||
1354 | vt1636_09 = | ||
1355 | viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info2, | ||
1356 | &viaparinfo->chip_info->lvds_chip_info2, 0x09) & 0x1f; | ||
1357 | seq_printf(m, " %x %x\n", vt1636_08, vt1636_09); | ||
1358 | break; | ||
1359 | default: | ||
1360 | break; | ||
1361 | } | ||
1362 | return 0; | ||
1363 | } | ||
1364 | |||
1365 | static int viafb_vt1636_proc_open(struct inode *inode, struct file *file) | ||
1366 | { | ||
1367 | return single_open(file, viafb_vt1636_proc_show, NULL); | ||
1368 | } | ||
1369 | |||
1370 | static ssize_t viafb_vt1636_proc_write(struct file *file, | ||
1371 | const char __user *buffer, size_t count, loff_t *pos) | ||
1372 | { | ||
1373 | char buf[30], *value, *pbuf; | ||
1374 | struct IODATA reg_val; | ||
1375 | unsigned long length, i; | ||
1376 | if (count < 1) | ||
1377 | return -EINVAL; | ||
1378 | length = count > 30 ? 30 : count; | ||
1379 | if (copy_from_user(&buf[0], buffer, length)) | ||
1380 | return -EFAULT; | ||
1381 | buf[length - 1] = '\0'; /*Ensure end string */ | ||
1382 | pbuf = &buf[0]; | ||
1383 | switch (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) { | ||
1384 | case VT1636_LVDS: | ||
1385 | for (i = 0; i < 2; i++) { | ||
1386 | value = strsep(&pbuf, " "); | ||
1387 | if (value != NULL) { | ||
1388 | if (kstrtou8(value, 0, ®_val.Data) < 0) | ||
1389 | return -EINVAL; | ||
1390 | switch (i) { | ||
1391 | case 0: | ||
1392 | reg_val.Index = 0x08; | ||
1393 | reg_val.Mask = 0x0f; | ||
1394 | viafb_gpio_i2c_write_mask_lvds | ||
1395 | (viaparinfo->lvds_setting_info, | ||
1396 | &viaparinfo-> | ||
1397 | chip_info->lvds_chip_info, | ||
1398 | reg_val); | ||
1399 | break; | ||
1400 | case 1: | ||
1401 | reg_val.Index = 0x09; | ||
1402 | reg_val.Mask = 0x1f; | ||
1403 | viafb_gpio_i2c_write_mask_lvds | ||
1404 | (viaparinfo->lvds_setting_info, | ||
1405 | &viaparinfo-> | ||
1406 | chip_info->lvds_chip_info, | ||
1407 | reg_val); | ||
1408 | break; | ||
1409 | default: | ||
1410 | break; | ||
1411 | } | ||
1412 | } else { | ||
1413 | break; | ||
1414 | } | ||
1415 | } | ||
1416 | break; | ||
1417 | default: | ||
1418 | break; | ||
1419 | } | ||
1420 | switch (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) { | ||
1421 | case VT1636_LVDS: | ||
1422 | for (i = 0; i < 2; i++) { | ||
1423 | value = strsep(&pbuf, " "); | ||
1424 | if (value != NULL) { | ||
1425 | if (kstrtou8(value, 0, ®_val.Data) < 0) | ||
1426 | return -EINVAL; | ||
1427 | switch (i) { | ||
1428 | case 0: | ||
1429 | reg_val.Index = 0x08; | ||
1430 | reg_val.Mask = 0x0f; | ||
1431 | viafb_gpio_i2c_write_mask_lvds | ||
1432 | (viaparinfo->lvds_setting_info2, | ||
1433 | &viaparinfo-> | ||
1434 | chip_info->lvds_chip_info2, | ||
1435 | reg_val); | ||
1436 | break; | ||
1437 | case 1: | ||
1438 | reg_val.Index = 0x09; | ||
1439 | reg_val.Mask = 0x1f; | ||
1440 | viafb_gpio_i2c_write_mask_lvds | ||
1441 | (viaparinfo->lvds_setting_info2, | ||
1442 | &viaparinfo-> | ||
1443 | chip_info->lvds_chip_info2, | ||
1444 | reg_val); | ||
1445 | break; | ||
1446 | default: | ||
1447 | break; | ||
1448 | } | ||
1449 | } else { | ||
1450 | break; | ||
1451 | } | ||
1452 | } | ||
1453 | break; | ||
1454 | default: | ||
1455 | break; | ||
1456 | } | ||
1457 | return count; | ||
1458 | } | ||
1459 | |||
1460 | static const struct file_operations viafb_vt1636_proc_fops = { | ||
1461 | .owner = THIS_MODULE, | ||
1462 | .open = viafb_vt1636_proc_open, | ||
1463 | .read = seq_read, | ||
1464 | .llseek = seq_lseek, | ||
1465 | .release = single_release, | ||
1466 | .write = viafb_vt1636_proc_write, | ||
1467 | }; | ||
1468 | |||
1469 | #endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ | ||
1470 | |||
1471 | static int viafb_sup_odev_proc_show(struct seq_file *m, void *v) | ||
1472 | { | ||
1473 | via_odev_to_seq(m, supported_odev_map[ | ||
1474 | viaparinfo->shared->chip_info.gfx_chip_name]); | ||
1475 | return 0; | ||
1476 | } | ||
1477 | |||
1478 | static int viafb_sup_odev_proc_open(struct inode *inode, struct file *file) | ||
1479 | { | ||
1480 | return single_open(file, viafb_sup_odev_proc_show, NULL); | ||
1481 | } | ||
1482 | |||
1483 | static const struct file_operations viafb_sup_odev_proc_fops = { | ||
1484 | .owner = THIS_MODULE, | ||
1485 | .open = viafb_sup_odev_proc_open, | ||
1486 | .read = seq_read, | ||
1487 | .llseek = seq_lseek, | ||
1488 | .release = single_release, | ||
1489 | }; | ||
1490 | |||
1491 | static ssize_t odev_update(const char __user *buffer, size_t count, u32 *odev) | ||
1492 | { | ||
1493 | char buf[64], *ptr = buf; | ||
1494 | u32 devices; | ||
1495 | bool add, sub; | ||
1496 | |||
1497 | if (count < 1 || count > 63) | ||
1498 | return -EINVAL; | ||
1499 | if (copy_from_user(&buf[0], buffer, count)) | ||
1500 | return -EFAULT; | ||
1501 | buf[count] = '\0'; | ||
1502 | add = buf[0] == '+'; | ||
1503 | sub = buf[0] == '-'; | ||
1504 | if (add || sub) | ||
1505 | ptr++; | ||
1506 | devices = via_parse_odev(ptr, &ptr); | ||
1507 | if (*ptr == '\n') | ||
1508 | ptr++; | ||
1509 | if (*ptr != 0) | ||
1510 | return -EINVAL; | ||
1511 | if (add) | ||
1512 | *odev |= devices; | ||
1513 | else if (sub) | ||
1514 | *odev &= ~devices; | ||
1515 | else | ||
1516 | *odev = devices; | ||
1517 | return count; | ||
1518 | } | ||
1519 | |||
1520 | static int viafb_iga1_odev_proc_show(struct seq_file *m, void *v) | ||
1521 | { | ||
1522 | via_odev_to_seq(m, viaparinfo->shared->iga1_devices); | ||
1523 | return 0; | ||
1524 | } | ||
1525 | |||
1526 | static int viafb_iga1_odev_proc_open(struct inode *inode, struct file *file) | ||
1527 | { | ||
1528 | return single_open(file, viafb_iga1_odev_proc_show, NULL); | ||
1529 | } | ||
1530 | |||
1531 | static ssize_t viafb_iga1_odev_proc_write(struct file *file, | ||
1532 | const char __user *buffer, size_t count, loff_t *pos) | ||
1533 | { | ||
1534 | u32 dev_on, dev_off, dev_old, dev_new; | ||
1535 | ssize_t res; | ||
1536 | |||
1537 | dev_old = dev_new = viaparinfo->shared->iga1_devices; | ||
1538 | res = odev_update(buffer, count, &dev_new); | ||
1539 | if (res != count) | ||
1540 | return res; | ||
1541 | dev_off = dev_old & ~dev_new; | ||
1542 | dev_on = dev_new & ~dev_old; | ||
1543 | viaparinfo->shared->iga1_devices = dev_new; | ||
1544 | viaparinfo->shared->iga2_devices &= ~dev_new; | ||
1545 | via_set_state(dev_off, VIA_STATE_OFF); | ||
1546 | via_set_source(dev_new, IGA1); | ||
1547 | via_set_state(dev_on, VIA_STATE_ON); | ||
1548 | return res; | ||
1549 | } | ||
1550 | |||
1551 | static const struct file_operations viafb_iga1_odev_proc_fops = { | ||
1552 | .owner = THIS_MODULE, | ||
1553 | .open = viafb_iga1_odev_proc_open, | ||
1554 | .read = seq_read, | ||
1555 | .llseek = seq_lseek, | ||
1556 | .release = single_release, | ||
1557 | .write = viafb_iga1_odev_proc_write, | ||
1558 | }; | ||
1559 | |||
1560 | static int viafb_iga2_odev_proc_show(struct seq_file *m, void *v) | ||
1561 | { | ||
1562 | via_odev_to_seq(m, viaparinfo->shared->iga2_devices); | ||
1563 | return 0; | ||
1564 | } | ||
1565 | |||
1566 | static int viafb_iga2_odev_proc_open(struct inode *inode, struct file *file) | ||
1567 | { | ||
1568 | return single_open(file, viafb_iga2_odev_proc_show, NULL); | ||
1569 | } | ||
1570 | |||
1571 | static ssize_t viafb_iga2_odev_proc_write(struct file *file, | ||
1572 | const char __user *buffer, size_t count, loff_t *pos) | ||
1573 | { | ||
1574 | u32 dev_on, dev_off, dev_old, dev_new; | ||
1575 | ssize_t res; | ||
1576 | |||
1577 | dev_old = dev_new = viaparinfo->shared->iga2_devices; | ||
1578 | res = odev_update(buffer, count, &dev_new); | ||
1579 | if (res != count) | ||
1580 | return res; | ||
1581 | dev_off = dev_old & ~dev_new; | ||
1582 | dev_on = dev_new & ~dev_old; | ||
1583 | viaparinfo->shared->iga2_devices = dev_new; | ||
1584 | viaparinfo->shared->iga1_devices &= ~dev_new; | ||
1585 | via_set_state(dev_off, VIA_STATE_OFF); | ||
1586 | via_set_source(dev_new, IGA2); | ||
1587 | via_set_state(dev_on, VIA_STATE_ON); | ||
1588 | return res; | ||
1589 | } | ||
1590 | |||
1591 | static const struct file_operations viafb_iga2_odev_proc_fops = { | ||
1592 | .owner = THIS_MODULE, | ||
1593 | .open = viafb_iga2_odev_proc_open, | ||
1594 | .read = seq_read, | ||
1595 | .llseek = seq_lseek, | ||
1596 | .release = single_release, | ||
1597 | .write = viafb_iga2_odev_proc_write, | ||
1598 | }; | ||
1599 | |||
1600 | #define IS_VT1636(lvds_chip) ((lvds_chip).lvds_chip_name == VT1636_LVDS) | ||
1601 | static void viafb_init_proc(struct viafb_shared *shared) | ||
1602 | { | ||
1603 | struct proc_dir_entry *iga1_entry, *iga2_entry, | ||
1604 | *viafb_entry = proc_mkdir("viafb", NULL); | ||
1605 | |||
1606 | shared->proc_entry = viafb_entry; | ||
1607 | if (viafb_entry) { | ||
1608 | #ifdef CONFIG_FB_VIA_DIRECT_PROCFS | ||
1609 | proc_create("dvp0", 0, viafb_entry, &viafb_dvp0_proc_fops); | ||
1610 | proc_create("dvp1", 0, viafb_entry, &viafb_dvp1_proc_fops); | ||
1611 | proc_create("dfph", 0, viafb_entry, &viafb_dfph_proc_fops); | ||
1612 | proc_create("dfpl", 0, viafb_entry, &viafb_dfpl_proc_fops); | ||
1613 | if (IS_VT1636(shared->chip_info.lvds_chip_info) | ||
1614 | || IS_VT1636(shared->chip_info.lvds_chip_info2)) | ||
1615 | proc_create("vt1636", 0, viafb_entry, | ||
1616 | &viafb_vt1636_proc_fops); | ||
1617 | #endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ | ||
1618 | |||
1619 | proc_create("supported_output_devices", 0, viafb_entry, | ||
1620 | &viafb_sup_odev_proc_fops); | ||
1621 | iga1_entry = proc_mkdir("iga1", viafb_entry); | ||
1622 | shared->iga1_proc_entry = iga1_entry; | ||
1623 | proc_create("output_devices", 0, iga1_entry, | ||
1624 | &viafb_iga1_odev_proc_fops); | ||
1625 | iga2_entry = proc_mkdir("iga2", viafb_entry); | ||
1626 | shared->iga2_proc_entry = iga2_entry; | ||
1627 | proc_create("output_devices", 0, iga2_entry, | ||
1628 | &viafb_iga2_odev_proc_fops); | ||
1629 | } | ||
1630 | } | ||
1631 | static void viafb_remove_proc(struct viafb_shared *shared) | ||
1632 | { | ||
1633 | struct proc_dir_entry *viafb_entry = shared->proc_entry, | ||
1634 | *iga1_entry = shared->iga1_proc_entry, | ||
1635 | *iga2_entry = shared->iga2_proc_entry; | ||
1636 | |||
1637 | if (!viafb_entry) | ||
1638 | return; | ||
1639 | |||
1640 | remove_proc_entry("output_devices", iga2_entry); | ||
1641 | remove_proc_entry("iga2", viafb_entry); | ||
1642 | remove_proc_entry("output_devices", iga1_entry); | ||
1643 | remove_proc_entry("iga1", viafb_entry); | ||
1644 | remove_proc_entry("supported_output_devices", viafb_entry); | ||
1645 | |||
1646 | #ifdef CONFIG_FB_VIA_DIRECT_PROCFS | ||
1647 | remove_proc_entry("dvp0", viafb_entry);/* parent dir */ | ||
1648 | remove_proc_entry("dvp1", viafb_entry); | ||
1649 | remove_proc_entry("dfph", viafb_entry); | ||
1650 | remove_proc_entry("dfpl", viafb_entry); | ||
1651 | if (IS_VT1636(shared->chip_info.lvds_chip_info) | ||
1652 | || IS_VT1636(shared->chip_info.lvds_chip_info2)) | ||
1653 | remove_proc_entry("vt1636", viafb_entry); | ||
1654 | #endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ | ||
1655 | |||
1656 | remove_proc_entry("viafb", NULL); | ||
1657 | } | ||
1658 | #undef IS_VT1636 | ||
1659 | |||
1660 | static int parse_mode(const char *str, u32 devices, u32 *xres, u32 *yres) | ||
1661 | { | ||
1662 | const struct fb_videomode *mode = NULL; | ||
1663 | char *ptr; | ||
1664 | |||
1665 | if (!str) { | ||
1666 | if (devices == VIA_CRT) | ||
1667 | mode = via_aux_get_preferred_mode( | ||
1668 | viaparinfo->shared->i2c_26); | ||
1669 | else if (devices == VIA_DVP1) | ||
1670 | mode = via_aux_get_preferred_mode( | ||
1671 | viaparinfo->shared->i2c_31); | ||
1672 | |||
1673 | if (mode) { | ||
1674 | *xres = mode->xres; | ||
1675 | *yres = mode->yres; | ||
1676 | } else if (machine_is_olpc()) { | ||
1677 | *xres = 1200; | ||
1678 | *yres = 900; | ||
1679 | } else { | ||
1680 | *xres = 640; | ||
1681 | *yres = 480; | ||
1682 | } | ||
1683 | return 0; | ||
1684 | } | ||
1685 | |||
1686 | *xres = simple_strtoul(str, &ptr, 10); | ||
1687 | if (ptr[0] != 'x') | ||
1688 | return -EINVAL; | ||
1689 | |||
1690 | *yres = simple_strtoul(&ptr[1], &ptr, 10); | ||
1691 | if (ptr[0]) | ||
1692 | return -EINVAL; | ||
1693 | |||
1694 | return 0; | ||
1695 | } | ||
1696 | |||
1697 | |||
1698 | #ifdef CONFIG_PM | ||
1699 | static int viafb_suspend(void *unused) | ||
1700 | { | ||
1701 | console_lock(); | ||
1702 | fb_set_suspend(viafbinfo, 1); | ||
1703 | viafb_sync(viafbinfo); | ||
1704 | console_unlock(); | ||
1705 | |||
1706 | return 0; | ||
1707 | } | ||
1708 | |||
1709 | static int viafb_resume(void *unused) | ||
1710 | { | ||
1711 | console_lock(); | ||
1712 | if (viaparinfo->shared->vdev->engine_mmio) | ||
1713 | viafb_reset_engine(viaparinfo); | ||
1714 | viafb_set_par(viafbinfo); | ||
1715 | if (viafb_dual_fb) | ||
1716 | viafb_set_par(viafbinfo1); | ||
1717 | fb_set_suspend(viafbinfo, 0); | ||
1718 | |||
1719 | console_unlock(); | ||
1720 | return 0; | ||
1721 | } | ||
1722 | |||
1723 | static struct viafb_pm_hooks viafb_fb_pm_hooks = { | ||
1724 | .suspend = viafb_suspend, | ||
1725 | .resume = viafb_resume | ||
1726 | }; | ||
1727 | |||
1728 | #endif | ||
1729 | |||
1730 | static void i2c_bus_probe(struct viafb_shared *shared) | ||
1731 | { | ||
1732 | /* should be always CRT */ | ||
1733 | printk(KERN_INFO "viafb: Probing I2C bus 0x26\n"); | ||
1734 | shared->i2c_26 = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_26)); | ||
1735 | |||
1736 | /* seems to be usually DVP1 */ | ||
1737 | printk(KERN_INFO "viafb: Probing I2C bus 0x31\n"); | ||
1738 | shared->i2c_31 = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_31)); | ||
1739 | |||
1740 | /* FIXME: what is this? */ | ||
1741 | if (!machine_is_olpc()) { | ||
1742 | printk(KERN_INFO "viafb: Probing I2C bus 0x2C\n"); | ||
1743 | shared->i2c_2C = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_2C)); | ||
1744 | } | ||
1745 | |||
1746 | printk(KERN_INFO "viafb: Finished I2C bus probing"); | ||
1747 | } | ||
1748 | |||
1749 | static void i2c_bus_free(struct viafb_shared *shared) | ||
1750 | { | ||
1751 | via_aux_free(shared->i2c_26); | ||
1752 | via_aux_free(shared->i2c_31); | ||
1753 | via_aux_free(shared->i2c_2C); | ||
1754 | } | ||
1755 | |||
1756 | int via_fb_pci_probe(struct viafb_dev *vdev) | ||
1757 | { | ||
1758 | u32 default_xres, default_yres; | ||
1759 | struct fb_var_screeninfo default_var; | ||
1760 | int rc; | ||
1761 | u32 viafb_par_length; | ||
1762 | |||
1763 | DEBUG_MSG(KERN_INFO "VIAFB PCI Probe!!\n"); | ||
1764 | memset(&default_var, 0, sizeof(default_var)); | ||
1765 | viafb_par_length = ALIGN(sizeof(struct viafb_par), BITS_PER_LONG/8); | ||
1766 | |||
1767 | /* Allocate fb_info and ***_par here, also including some other needed | ||
1768 | * variables | ||
1769 | */ | ||
1770 | viafbinfo = framebuffer_alloc(viafb_par_length + | ||
1771 | ALIGN(sizeof(struct viafb_shared), BITS_PER_LONG/8), | ||
1772 | &vdev->pdev->dev); | ||
1773 | if (!viafbinfo) { | ||
1774 | printk(KERN_ERR"Could not allocate memory for viafb_info.\n"); | ||
1775 | return -ENOMEM; | ||
1776 | } | ||
1777 | |||
1778 | viaparinfo = (struct viafb_par *)viafbinfo->par; | ||
1779 | viaparinfo->shared = viafbinfo->par + viafb_par_length; | ||
1780 | viaparinfo->shared->vdev = vdev; | ||
1781 | viaparinfo->vram_addr = 0; | ||
1782 | viaparinfo->tmds_setting_info = &viaparinfo->shared->tmds_setting_info; | ||
1783 | viaparinfo->lvds_setting_info = &viaparinfo->shared->lvds_setting_info; | ||
1784 | viaparinfo->lvds_setting_info2 = | ||
1785 | &viaparinfo->shared->lvds_setting_info2; | ||
1786 | viaparinfo->chip_info = &viaparinfo->shared->chip_info; | ||
1787 | |||
1788 | i2c_bus_probe(viaparinfo->shared); | ||
1789 | if (viafb_dual_fb) | ||
1790 | viafb_SAMM_ON = 1; | ||
1791 | parse_lcd_port(); | ||
1792 | parse_dvi_port(); | ||
1793 | |||
1794 | viafb_init_chip_info(vdev->chip_type); | ||
1795 | /* | ||
1796 | * The framebuffer will have been successfully mapped by | ||
1797 | * the core (or we'd not be here), but we still need to | ||
1798 | * set up our own accounting. | ||
1799 | */ | ||
1800 | viaparinfo->fbmem = vdev->fbmem_start; | ||
1801 | viaparinfo->memsize = vdev->fbmem_len; | ||
1802 | viaparinfo->fbmem_free = viaparinfo->memsize; | ||
1803 | viaparinfo->fbmem_used = 0; | ||
1804 | viafbinfo->screen_base = vdev->fbmem; | ||
1805 | |||
1806 | viafbinfo->fix.mmio_start = vdev->engine_start; | ||
1807 | viafbinfo->fix.mmio_len = vdev->engine_len; | ||
1808 | viafbinfo->node = 0; | ||
1809 | viafbinfo->fbops = &viafb_ops; | ||
1810 | viafbinfo->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; | ||
1811 | |||
1812 | viafbinfo->pseudo_palette = pseudo_pal; | ||
1813 | if (viafb_accel && !viafb_setup_engine(viafbinfo)) { | ||
1814 | viafbinfo->flags |= FBINFO_HWACCEL_COPYAREA | | ||
1815 | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_IMAGEBLIT; | ||
1816 | default_var.accel_flags = FB_ACCELF_TEXT; | ||
1817 | } else { | ||
1818 | viafbinfo->flags |= FBINFO_HWACCEL_DISABLED; | ||
1819 | default_var.accel_flags = 0; | ||
1820 | } | ||
1821 | |||
1822 | if (viafb_second_size && (viafb_second_size < 8)) { | ||
1823 | viafb_second_offset = viaparinfo->fbmem_free - | ||
1824 | viafb_second_size * 1024 * 1024; | ||
1825 | } else { | ||
1826 | viafb_second_size = 8; | ||
1827 | viafb_second_offset = viaparinfo->fbmem_free - | ||
1828 | viafb_second_size * 1024 * 1024; | ||
1829 | } | ||
1830 | |||
1831 | parse_mode(viafb_mode, viaparinfo->shared->iga1_devices, | ||
1832 | &default_xres, &default_yres); | ||
1833 | if (viafb_SAMM_ON == 1) | ||
1834 | parse_mode(viafb_mode1, viaparinfo->shared->iga2_devices, | ||
1835 | &viafb_second_xres, &viafb_second_yres); | ||
1836 | |||
1837 | default_var.xres = default_xres; | ||
1838 | default_var.yres = default_yres; | ||
1839 | default_var.xres_virtual = default_xres; | ||
1840 | default_var.yres_virtual = default_yres; | ||
1841 | default_var.bits_per_pixel = viafb_bpp; | ||
1842 | viafb_fill_var_timing_info(&default_var, viafb_get_best_mode( | ||
1843 | default_var.xres, default_var.yres, viafb_refresh)); | ||
1844 | viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo); | ||
1845 | viafbinfo->var = default_var; | ||
1846 | |||
1847 | if (viafb_dual_fb) { | ||
1848 | viafbinfo1 = framebuffer_alloc(viafb_par_length, | ||
1849 | &vdev->pdev->dev); | ||
1850 | if (!viafbinfo1) { | ||
1851 | printk(KERN_ERR | ||
1852 | "allocate the second framebuffer struct error\n"); | ||
1853 | rc = -ENOMEM; | ||
1854 | goto out_fb_release; | ||
1855 | } | ||
1856 | viaparinfo1 = viafbinfo1->par; | ||
1857 | memcpy(viaparinfo1, viaparinfo, viafb_par_length); | ||
1858 | viaparinfo1->vram_addr = viafb_second_offset; | ||
1859 | viaparinfo1->memsize = viaparinfo->memsize - | ||
1860 | viafb_second_offset; | ||
1861 | viaparinfo->memsize = viafb_second_offset; | ||
1862 | viaparinfo1->fbmem = viaparinfo->fbmem + viafb_second_offset; | ||
1863 | |||
1864 | viaparinfo1->fbmem_used = viaparinfo->fbmem_used; | ||
1865 | viaparinfo1->fbmem_free = viaparinfo1->memsize - | ||
1866 | viaparinfo1->fbmem_used; | ||
1867 | viaparinfo->fbmem_free = viaparinfo->memsize; | ||
1868 | viaparinfo->fbmem_used = 0; | ||
1869 | |||
1870 | viaparinfo->iga_path = IGA1; | ||
1871 | viaparinfo1->iga_path = IGA2; | ||
1872 | memcpy(viafbinfo1, viafbinfo, sizeof(struct fb_info)); | ||
1873 | viafbinfo1->par = viaparinfo1; | ||
1874 | viafbinfo1->screen_base = viafbinfo->screen_base + | ||
1875 | viafb_second_offset; | ||
1876 | |||
1877 | default_var.xres = viafb_second_xres; | ||
1878 | default_var.yres = viafb_second_yres; | ||
1879 | default_var.xres_virtual = viafb_second_xres; | ||
1880 | default_var.yres_virtual = viafb_second_yres; | ||
1881 | default_var.bits_per_pixel = viafb_bpp1; | ||
1882 | viafb_fill_var_timing_info(&default_var, viafb_get_best_mode( | ||
1883 | default_var.xres, default_var.yres, viafb_refresh1)); | ||
1884 | |||
1885 | viafb_setup_fixinfo(&viafbinfo1->fix, viaparinfo1); | ||
1886 | viafb_check_var(&default_var, viafbinfo1); | ||
1887 | viafbinfo1->var = default_var; | ||
1888 | viafb_update_fix(viafbinfo1); | ||
1889 | viaparinfo1->depth = fb_get_color_depth(&viafbinfo1->var, | ||
1890 | &viafbinfo1->fix); | ||
1891 | } | ||
1892 | |||
1893 | viafb_check_var(&viafbinfo->var, viafbinfo); | ||
1894 | viafb_update_fix(viafbinfo); | ||
1895 | viaparinfo->depth = fb_get_color_depth(&viafbinfo->var, | ||
1896 | &viafbinfo->fix); | ||
1897 | default_var.activate = FB_ACTIVATE_NOW; | ||
1898 | rc = fb_alloc_cmap(&viafbinfo->cmap, 256, 0); | ||
1899 | if (rc) | ||
1900 | goto out_fb1_release; | ||
1901 | |||
1902 | if (viafb_dual_fb && (viafb_primary_dev == LCD_Device) | ||
1903 | && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) { | ||
1904 | rc = register_framebuffer(viafbinfo1); | ||
1905 | if (rc) | ||
1906 | goto out_dealloc_cmap; | ||
1907 | } | ||
1908 | rc = register_framebuffer(viafbinfo); | ||
1909 | if (rc) | ||
1910 | goto out_fb1_unreg_lcd_cle266; | ||
1911 | |||
1912 | if (viafb_dual_fb && ((viafb_primary_dev != LCD_Device) | ||
1913 | || (viaparinfo->chip_info->gfx_chip_name != | ||
1914 | UNICHROME_CLE266))) { | ||
1915 | rc = register_framebuffer(viafbinfo1); | ||
1916 | if (rc) | ||
1917 | goto out_fb_unreg; | ||
1918 | } | ||
1919 | DEBUG_MSG(KERN_INFO "fb%d: %s frame buffer device %dx%d-%dbpp\n", | ||
1920 | viafbinfo->node, viafbinfo->fix.id, default_var.xres, | ||
1921 | default_var.yres, default_var.bits_per_pixel); | ||
1922 | |||
1923 | viafb_init_proc(viaparinfo->shared); | ||
1924 | viafb_init_dac(IGA2); | ||
1925 | |||
1926 | #ifdef CONFIG_PM | ||
1927 | viafb_pm_register(&viafb_fb_pm_hooks); | ||
1928 | #endif | ||
1929 | return 0; | ||
1930 | |||
1931 | out_fb_unreg: | ||
1932 | unregister_framebuffer(viafbinfo); | ||
1933 | out_fb1_unreg_lcd_cle266: | ||
1934 | if (viafb_dual_fb && (viafb_primary_dev == LCD_Device) | ||
1935 | && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) | ||
1936 | unregister_framebuffer(viafbinfo1); | ||
1937 | out_dealloc_cmap: | ||
1938 | fb_dealloc_cmap(&viafbinfo->cmap); | ||
1939 | out_fb1_release: | ||
1940 | if (viafbinfo1) | ||
1941 | framebuffer_release(viafbinfo1); | ||
1942 | out_fb_release: | ||
1943 | i2c_bus_free(viaparinfo->shared); | ||
1944 | framebuffer_release(viafbinfo); | ||
1945 | return rc; | ||
1946 | } | ||
1947 | |||
1948 | void via_fb_pci_remove(struct pci_dev *pdev) | ||
1949 | { | ||
1950 | DEBUG_MSG(KERN_INFO "via_pci_remove!\n"); | ||
1951 | fb_dealloc_cmap(&viafbinfo->cmap); | ||
1952 | unregister_framebuffer(viafbinfo); | ||
1953 | if (viafb_dual_fb) | ||
1954 | unregister_framebuffer(viafbinfo1); | ||
1955 | viafb_remove_proc(viaparinfo->shared); | ||
1956 | i2c_bus_free(viaparinfo->shared); | ||
1957 | framebuffer_release(viafbinfo); | ||
1958 | if (viafb_dual_fb) | ||
1959 | framebuffer_release(viafbinfo1); | ||
1960 | } | ||
1961 | |||
1962 | #ifndef MODULE | ||
1963 | static int __init viafb_setup(void) | ||
1964 | { | ||
1965 | char *this_opt; | ||
1966 | char *options; | ||
1967 | |||
1968 | DEBUG_MSG(KERN_INFO "viafb_setup!\n"); | ||
1969 | |||
1970 | if (fb_get_options("viafb", &options)) | ||
1971 | return -ENODEV; | ||
1972 | |||
1973 | if (!options || !*options) | ||
1974 | return 0; | ||
1975 | |||
1976 | while ((this_opt = strsep(&options, ",")) != NULL) { | ||
1977 | if (!*this_opt) | ||
1978 | continue; | ||
1979 | |||
1980 | if (!strncmp(this_opt, "viafb_mode1=", 12)) { | ||
1981 | viafb_mode1 = kstrdup(this_opt + 12, GFP_KERNEL); | ||
1982 | } else if (!strncmp(this_opt, "viafb_mode=", 11)) { | ||
1983 | viafb_mode = kstrdup(this_opt + 11, GFP_KERNEL); | ||
1984 | } else if (!strncmp(this_opt, "viafb_bpp1=", 11)) { | ||
1985 | if (kstrtouint(this_opt + 11, 0, &viafb_bpp1) < 0) | ||
1986 | return -EINVAL; | ||
1987 | } else if (!strncmp(this_opt, "viafb_bpp=", 10)) { | ||
1988 | if (kstrtouint(this_opt + 10, 0, &viafb_bpp) < 0) | ||
1989 | return -EINVAL; | ||
1990 | } else if (!strncmp(this_opt, "viafb_refresh1=", 15)) { | ||
1991 | if (kstrtoint(this_opt + 15, 0, &viafb_refresh1) < 0) | ||
1992 | return -EINVAL; | ||
1993 | } else if (!strncmp(this_opt, "viafb_refresh=", 14)) { | ||
1994 | if (kstrtoint(this_opt + 14, 0, &viafb_refresh) < 0) | ||
1995 | return -EINVAL; | ||
1996 | } else if (!strncmp(this_opt, "viafb_lcd_dsp_method=", 21)) { | ||
1997 | if (kstrtoint(this_opt + 21, 0, | ||
1998 | &viafb_lcd_dsp_method) < 0) | ||
1999 | return -EINVAL; | ||
2000 | } else if (!strncmp(this_opt, "viafb_lcd_panel_id=", 19)) { | ||
2001 | if (kstrtoint(this_opt + 19, 0, | ||
2002 | &viafb_lcd_panel_id) < 0) | ||
2003 | return -EINVAL; | ||
2004 | } else if (!strncmp(this_opt, "viafb_accel=", 12)) { | ||
2005 | if (kstrtoint(this_opt + 12, 0, &viafb_accel) < 0) | ||
2006 | return -EINVAL; | ||
2007 | } else if (!strncmp(this_opt, "viafb_SAMM_ON=", 14)) { | ||
2008 | if (kstrtoint(this_opt + 14, 0, &viafb_SAMM_ON) < 0) | ||
2009 | return -EINVAL; | ||
2010 | } else if (!strncmp(this_opt, "viafb_active_dev=", 17)) { | ||
2011 | viafb_active_dev = kstrdup(this_opt + 17, GFP_KERNEL); | ||
2012 | } else if (!strncmp(this_opt, | ||
2013 | "viafb_display_hardware_layout=", 30)) { | ||
2014 | if (kstrtoint(this_opt + 30, 0, | ||
2015 | &viafb_display_hardware_layout) < 0) | ||
2016 | return -EINVAL; | ||
2017 | } else if (!strncmp(this_opt, "viafb_second_size=", 18)) { | ||
2018 | if (kstrtoint(this_opt + 18, 0, &viafb_second_size) < 0) | ||
2019 | return -EINVAL; | ||
2020 | } else if (!strncmp(this_opt, | ||
2021 | "viafb_platform_epia_dvi=", 24)) { | ||
2022 | if (kstrtoint(this_opt + 24, 0, | ||
2023 | &viafb_platform_epia_dvi) < 0) | ||
2024 | return -EINVAL; | ||
2025 | } else if (!strncmp(this_opt, | ||
2026 | "viafb_device_lcd_dualedge=", 26)) { | ||
2027 | if (kstrtoint(this_opt + 26, 0, | ||
2028 | &viafb_device_lcd_dualedge) < 0) | ||
2029 | return -EINVAL; | ||
2030 | } else if (!strncmp(this_opt, "viafb_bus_width=", 16)) { | ||
2031 | if (kstrtoint(this_opt + 16, 0, &viafb_bus_width) < 0) | ||
2032 | return -EINVAL; | ||
2033 | } else if (!strncmp(this_opt, "viafb_lcd_mode=", 15)) { | ||
2034 | if (kstrtoint(this_opt + 15, 0, &viafb_lcd_mode) < 0) | ||
2035 | return -EINVAL; | ||
2036 | } else if (!strncmp(this_opt, "viafb_lcd_port=", 15)) { | ||
2037 | viafb_lcd_port = kstrdup(this_opt + 15, GFP_KERNEL); | ||
2038 | } else if (!strncmp(this_opt, "viafb_dvi_port=", 15)) { | ||
2039 | viafb_dvi_port = kstrdup(this_opt + 15, GFP_KERNEL); | ||
2040 | } | ||
2041 | } | ||
2042 | return 0; | ||
2043 | } | ||
2044 | #endif | ||
2045 | |||
2046 | /* | ||
2047 | * These are called out of via-core for now. | ||
2048 | */ | ||
2049 | int __init viafb_init(void) | ||
2050 | { | ||
2051 | u32 dummy_x, dummy_y; | ||
2052 | int r = 0; | ||
2053 | |||
2054 | if (machine_is_olpc()) | ||
2055 | /* Apply XO-1.5-specific configuration. */ | ||
2056 | viafb_lcd_panel_id = 23; | ||
2057 | |||
2058 | #ifndef MODULE | ||
2059 | r = viafb_setup(); | ||
2060 | if (r < 0) | ||
2061 | return r; | ||
2062 | #endif | ||
2063 | if (parse_mode(viafb_mode, 0, &dummy_x, &dummy_y) | ||
2064 | || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh) | ||
2065 | || parse_mode(viafb_mode1, 0, &dummy_x, &dummy_y) | ||
2066 | || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh1) | ||
2067 | || viafb_bpp < 0 || viafb_bpp > 32 | ||
2068 | || viafb_bpp1 < 0 || viafb_bpp1 > 32 | ||
2069 | || parse_active_dev()) | ||
2070 | return -EINVAL; | ||
2071 | |||
2072 | printk(KERN_INFO | ||
2073 | "VIA Graphics Integration Chipset framebuffer %d.%d initializing\n", | ||
2074 | VERSION_MAJOR, VERSION_MINOR); | ||
2075 | return r; | ||
2076 | } | ||
2077 | |||
2078 | void __exit viafb_exit(void) | ||
2079 | { | ||
2080 | DEBUG_MSG(KERN_INFO "viafb_exit!\n"); | ||
2081 | } | ||
2082 | |||
2083 | static struct fb_ops viafb_ops = { | ||
2084 | .owner = THIS_MODULE, | ||
2085 | .fb_open = viafb_open, | ||
2086 | .fb_release = viafb_release, | ||
2087 | .fb_check_var = viafb_check_var, | ||
2088 | .fb_set_par = viafb_set_par, | ||
2089 | .fb_setcolreg = viafb_setcolreg, | ||
2090 | .fb_pan_display = viafb_pan_display, | ||
2091 | .fb_blank = viafb_blank, | ||
2092 | .fb_fillrect = viafb_fillrect, | ||
2093 | .fb_copyarea = viafb_copyarea, | ||
2094 | .fb_imageblit = viafb_imageblit, | ||
2095 | .fb_cursor = viafb_cursor, | ||
2096 | .fb_ioctl = viafb_ioctl, | ||
2097 | .fb_sync = viafb_sync, | ||
2098 | }; | ||
2099 | |||
2100 | |||
2101 | #ifdef MODULE | ||
2102 | module_param(viafb_mode, charp, S_IRUSR); | ||
2103 | MODULE_PARM_DESC(viafb_mode, "Set resolution (default=640x480)"); | ||
2104 | |||
2105 | module_param(viafb_mode1, charp, S_IRUSR); | ||
2106 | MODULE_PARM_DESC(viafb_mode1, "Set resolution (default=640x480)"); | ||
2107 | |||
2108 | module_param(viafb_bpp, int, S_IRUSR); | ||
2109 | MODULE_PARM_DESC(viafb_bpp, "Set color depth (default=32bpp)"); | ||
2110 | |||
2111 | module_param(viafb_bpp1, int, S_IRUSR); | ||
2112 | MODULE_PARM_DESC(viafb_bpp1, "Set color depth (default=32bpp)"); | ||
2113 | |||
2114 | module_param(viafb_refresh, int, S_IRUSR); | ||
2115 | MODULE_PARM_DESC(viafb_refresh, | ||
2116 | "Set CRT viafb_refresh rate (default = 60)"); | ||
2117 | |||
2118 | module_param(viafb_refresh1, int, S_IRUSR); | ||
2119 | MODULE_PARM_DESC(viafb_refresh1, | ||
2120 | "Set CRT refresh rate (default = 60)"); | ||
2121 | |||
2122 | module_param(viafb_lcd_panel_id, int, S_IRUSR); | ||
2123 | MODULE_PARM_DESC(viafb_lcd_panel_id, | ||
2124 | "Set Flat Panel type(Default=1024x768)"); | ||
2125 | |||
2126 | module_param(viafb_lcd_dsp_method, int, S_IRUSR); | ||
2127 | MODULE_PARM_DESC(viafb_lcd_dsp_method, | ||
2128 | "Set Flat Panel display scaling method.(Default=Expandsion)"); | ||
2129 | |||
2130 | module_param(viafb_SAMM_ON, int, S_IRUSR); | ||
2131 | MODULE_PARM_DESC(viafb_SAMM_ON, | ||
2132 | "Turn on/off flag of SAMM(Default=OFF)"); | ||
2133 | |||
2134 | module_param(viafb_accel, int, S_IRUSR); | ||
2135 | MODULE_PARM_DESC(viafb_accel, | ||
2136 | "Set 2D Hardware Acceleration: 0 = OFF, 1 = ON (default)"); | ||
2137 | |||
2138 | module_param(viafb_active_dev, charp, S_IRUSR); | ||
2139 | MODULE_PARM_DESC(viafb_active_dev, "Specify active devices."); | ||
2140 | |||
2141 | module_param(viafb_display_hardware_layout, int, S_IRUSR); | ||
2142 | MODULE_PARM_DESC(viafb_display_hardware_layout, | ||
2143 | "Display Hardware Layout (LCD Only, DVI Only...,etc)"); | ||
2144 | |||
2145 | module_param(viafb_second_size, int, S_IRUSR); | ||
2146 | MODULE_PARM_DESC(viafb_second_size, | ||
2147 | "Set secondary device memory size"); | ||
2148 | |||
2149 | module_param(viafb_dual_fb, int, S_IRUSR); | ||
2150 | MODULE_PARM_DESC(viafb_dual_fb, | ||
2151 | "Turn on/off flag of dual framebuffer devices.(Default = OFF)"); | ||
2152 | |||
2153 | module_param(viafb_platform_epia_dvi, int, S_IRUSR); | ||
2154 | MODULE_PARM_DESC(viafb_platform_epia_dvi, | ||
2155 | "Turn on/off flag of DVI devices on EPIA board.(Default = OFF)"); | ||
2156 | |||
2157 | module_param(viafb_device_lcd_dualedge, int, S_IRUSR); | ||
2158 | MODULE_PARM_DESC(viafb_device_lcd_dualedge, | ||
2159 | "Turn on/off flag of dual edge panel.(Default = OFF)"); | ||
2160 | |||
2161 | module_param(viafb_bus_width, int, S_IRUSR); | ||
2162 | MODULE_PARM_DESC(viafb_bus_width, | ||
2163 | "Set bus width of panel.(Default = 12)"); | ||
2164 | |||
2165 | module_param(viafb_lcd_mode, int, S_IRUSR); | ||
2166 | MODULE_PARM_DESC(viafb_lcd_mode, | ||
2167 | "Set Flat Panel mode(Default=OPENLDI)"); | ||
2168 | |||
2169 | module_param(viafb_lcd_port, charp, S_IRUSR); | ||
2170 | MODULE_PARM_DESC(viafb_lcd_port, "Specify LCD output port."); | ||
2171 | |||
2172 | module_param(viafb_dvi_port, charp, S_IRUSR); | ||
2173 | MODULE_PARM_DESC(viafb_dvi_port, "Specify DVI output port."); | ||
2174 | |||
2175 | MODULE_LICENSE("GPL"); | ||
2176 | #endif | ||
diff --git a/drivers/video/fbdev/via/viafbdev.h b/drivers/video/fbdev/via/viafbdev.h new file mode 100644 index 000000000000..f6b2ddf56e94 --- /dev/null +++ b/drivers/video/fbdev/via/viafbdev.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef __VIAFBDEV_H__ | ||
23 | #define __VIAFBDEV_H__ | ||
24 | |||
25 | #include <linux/proc_fs.h> | ||
26 | #include <linux/fb.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | |||
29 | #include "via_aux.h" | ||
30 | #include "ioctl.h" | ||
31 | #include "share.h" | ||
32 | #include "chip.h" | ||
33 | #include "hw.h" | ||
34 | |||
35 | #define VERSION_MAJOR 2 | ||
36 | #define VERSION_KERNEL 6 /* For kernel 2.6 */ | ||
37 | |||
38 | #define VERSION_OS 0 /* 0: for 32 bits OS, 1: for 64 bits OS */ | ||
39 | #define VERSION_MINOR 4 | ||
40 | |||
41 | #define VIAFB_NUM_I2C 5 | ||
42 | |||
43 | struct viafb_shared { | ||
44 | u32 iga1_devices; | ||
45 | u32 iga2_devices; | ||
46 | |||
47 | struct proc_dir_entry *proc_entry; /*viafb proc entry */ | ||
48 | struct proc_dir_entry *iga1_proc_entry; | ||
49 | struct proc_dir_entry *iga2_proc_entry; | ||
50 | struct viafb_dev *vdev; /* Global dev info */ | ||
51 | |||
52 | /* I2C busses that may have auxiliary devices */ | ||
53 | struct via_aux_bus *i2c_26; | ||
54 | struct via_aux_bus *i2c_31; | ||
55 | struct via_aux_bus *i2c_2C; | ||
56 | |||
57 | /* All the information will be needed to set engine */ | ||
58 | struct tmds_setting_information tmds_setting_info; | ||
59 | struct lvds_setting_information lvds_setting_info; | ||
60 | struct lvds_setting_information lvds_setting_info2; | ||
61 | struct chip_information chip_info; | ||
62 | |||
63 | /* hardware acceleration stuff */ | ||
64 | u32 cursor_vram_addr; | ||
65 | u32 vq_vram_addr; /* virtual queue address in video ram */ | ||
66 | int (*hw_bitblt)(void __iomem *engine, u8 op, u32 width, u32 height, | ||
67 | u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y, | ||
68 | u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y, | ||
69 | u32 fg_color, u32 bg_color, u8 fill_rop); | ||
70 | }; | ||
71 | |||
72 | struct viafb_par { | ||
73 | u8 depth; | ||
74 | u32 vram_addr; | ||
75 | |||
76 | unsigned int fbmem; /*framebuffer physical memory address */ | ||
77 | unsigned int memsize; /*size of fbmem */ | ||
78 | u32 fbmem_free; /* Free FB memory */ | ||
79 | u32 fbmem_used; /* Use FB memory size */ | ||
80 | u32 iga_path; | ||
81 | |||
82 | struct viafb_shared *shared; | ||
83 | |||
84 | /* All the information will be needed to set engine */ | ||
85 | /* depreciated, use the ones in shared directly */ | ||
86 | struct tmds_setting_information *tmds_setting_info; | ||
87 | struct lvds_setting_information *lvds_setting_info; | ||
88 | struct lvds_setting_information *lvds_setting_info2; | ||
89 | struct chip_information *chip_info; | ||
90 | }; | ||
91 | |||
92 | extern int viafb_SAMM_ON; | ||
93 | extern int viafb_dual_fb; | ||
94 | extern int viafb_LCD2_ON; | ||
95 | extern int viafb_LCD_ON; | ||
96 | extern int viafb_DVI_ON; | ||
97 | extern int viafb_hotplug; | ||
98 | |||
99 | u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information | ||
100 | *plvds_setting_info, struct lvds_chip_information | ||
101 | *plvds_chip_info, u8 index); | ||
102 | void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information | ||
103 | *plvds_setting_info, struct lvds_chip_information | ||
104 | *plvds_chip_info, struct IODATA io_data); | ||
105 | int via_fb_pci_probe(struct viafb_dev *vdev); | ||
106 | void via_fb_pci_remove(struct pci_dev *pdev); | ||
107 | /* Temporary */ | ||
108 | int viafb_init(void); | ||
109 | void viafb_exit(void); | ||
110 | #endif /* __VIAFBDEV_H__ */ | ||
diff --git a/drivers/video/fbdev/via/viamode.c b/drivers/video/fbdev/via/viamode.c new file mode 100644 index 000000000000..0666ab01cf4a --- /dev/null +++ b/drivers/video/fbdev/via/viamode.c | |||
@@ -0,0 +1,383 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/via-core.h> | ||
23 | #include "global.h" | ||
24 | |||
25 | struct io_reg CN400_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01}, | ||
26 | {VIASR, SR15, 0x02, 0x02}, | ||
27 | {VIASR, SR16, 0xBF, 0x08}, | ||
28 | {VIASR, SR17, 0xFF, 0x1F}, | ||
29 | {VIASR, SR18, 0xFF, 0x4E}, | ||
30 | {VIASR, SR1A, 0xFB, 0x08}, | ||
31 | {VIASR, SR1E, 0x0F, 0x01}, | ||
32 | {VIASR, SR2A, 0xFF, 0x00}, | ||
33 | {VIACR, CR32, 0xFF, 0x00}, | ||
34 | {VIACR, CR33, 0xFF, 0x00}, | ||
35 | {VIACR, CR35, 0xFF, 0x00}, | ||
36 | {VIACR, CR36, 0x08, 0x00}, | ||
37 | {VIACR, CR69, 0xFF, 0x00}, | ||
38 | {VIACR, CR6A, 0xFF, 0x40}, | ||
39 | {VIACR, CR6B, 0xFF, 0x00}, | ||
40 | {VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */ | ||
41 | {VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */ | ||
42 | {VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */ | ||
43 | {VIACR, CR8B, 0xFF, 0x69}, /* LCD Power Sequence Control 0 */ | ||
44 | {VIACR, CR8C, 0xFF, 0x57}, /* LCD Power Sequence Control 1 */ | ||
45 | {VIACR, CR8D, 0xFF, 0x00}, /* LCD Power Sequence Control 2 */ | ||
46 | {VIACR, CR8E, 0xFF, 0x7B}, /* LCD Power Sequence Control 3 */ | ||
47 | {VIACR, CR8F, 0xFF, 0x03}, /* LCD Power Sequence Control 4 */ | ||
48 | {VIACR, CR90, 0xFF, 0x30}, /* LCD Power Sequence Control 5 */ | ||
49 | {VIACR, CR91, 0xFF, 0xA0}, /* 24/12 bit LVDS Data off */ | ||
50 | {VIACR, CR96, 0xFF, 0x00}, | ||
51 | {VIACR, CR97, 0xFF, 0x00}, | ||
52 | {VIACR, CR99, 0xFF, 0x00}, | ||
53 | {VIACR, CR9B, 0xFF, 0x00} | ||
54 | }; | ||
55 | |||
56 | /* Video Mode Table for VT3314 chipset*/ | ||
57 | /* Common Setting for Video Mode */ | ||
58 | struct io_reg CN700_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01}, | ||
59 | {VIASR, SR15, 0x02, 0x02}, | ||
60 | {VIASR, SR16, 0xBF, 0x08}, | ||
61 | {VIASR, SR17, 0xFF, 0x1F}, | ||
62 | {VIASR, SR18, 0xFF, 0x4E}, | ||
63 | {VIASR, SR1A, 0xFB, 0x82}, | ||
64 | {VIASR, SR1B, 0xFF, 0xF0}, | ||
65 | {VIASR, SR1F, 0xFF, 0x00}, | ||
66 | {VIASR, SR1E, 0xFF, 0x01}, | ||
67 | {VIASR, SR22, 0xFF, 0x1F}, | ||
68 | {VIASR, SR2A, 0x0F, 0x00}, | ||
69 | {VIASR, SR2E, 0xFF, 0xFF}, | ||
70 | {VIASR, SR3F, 0xFF, 0xFF}, | ||
71 | {VIASR, SR40, 0xF7, 0x00}, | ||
72 | {VIASR, CR30, 0xFF, 0x04}, | ||
73 | {VIACR, CR32, 0xFF, 0x00}, | ||
74 | {VIACR, CR33, 0x7F, 0x00}, | ||
75 | {VIACR, CR35, 0xFF, 0x00}, | ||
76 | {VIACR, CR36, 0xFF, 0x31}, | ||
77 | {VIACR, CR41, 0xFF, 0x80}, | ||
78 | {VIACR, CR42, 0xFF, 0x00}, | ||
79 | {VIACR, CR55, 0x80, 0x00}, | ||
80 | {VIACR, CR5D, 0x80, 0x00}, /*Horizontal Retrace Start bit[11] should be 0*/ | ||
81 | {VIACR, CR68, 0xFF, 0x67}, /* Default FIFO For IGA2 */ | ||
82 | {VIACR, CR69, 0xFF, 0x00}, | ||
83 | {VIACR, CR6A, 0xFD, 0x40}, | ||
84 | {VIACR, CR6B, 0xFF, 0x00}, | ||
85 | {VIACR, CR77, 0xFF, 0x00}, /* LCD scaling Factor */ | ||
86 | {VIACR, CR78, 0xFF, 0x00}, /* LCD scaling Factor */ | ||
87 | {VIACR, CR79, 0xFF, 0x00}, /* LCD scaling Factor */ | ||
88 | {VIACR, CR9F, 0x03, 0x00}, /* LCD scaling Factor */ | ||
89 | {VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */ | ||
90 | {VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */ | ||
91 | {VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */ | ||
92 | {VIACR, CR8B, 0xFF, 0x5D}, /* LCD Power Sequence Control 0 */ | ||
93 | {VIACR, CR8C, 0xFF, 0x2B}, /* LCD Power Sequence Control 1 */ | ||
94 | {VIACR, CR8D, 0xFF, 0x6F}, /* LCD Power Sequence Control 2 */ | ||
95 | {VIACR, CR8E, 0xFF, 0x2B}, /* LCD Power Sequence Control 3 */ | ||
96 | {VIACR, CR8F, 0xFF, 0x01}, /* LCD Power Sequence Control 4 */ | ||
97 | {VIACR, CR90, 0xFF, 0x01}, /* LCD Power Sequence Control 5 */ | ||
98 | {VIACR, CR91, 0xFF, 0xA0}, /* 24/12 bit LVDS Data off */ | ||
99 | {VIACR, CR96, 0xFF, 0x00}, | ||
100 | {VIACR, CR97, 0xFF, 0x00}, | ||
101 | {VIACR, CR99, 0xFF, 0x00}, | ||
102 | {VIACR, CR9B, 0xFF, 0x00}, | ||
103 | {VIACR, CR9D, 0xFF, 0x80}, | ||
104 | {VIACR, CR9E, 0xFF, 0x80} | ||
105 | }; | ||
106 | |||
107 | struct io_reg KM400_ModeXregs[] = { | ||
108 | {VIASR, SR10, 0xFF, 0x01}, /* Unlock Register */ | ||
109 | {VIASR, SR16, 0xFF, 0x08}, /* Display FIFO threshold Control */ | ||
110 | {VIASR, SR17, 0xFF, 0x1F}, /* Display FIFO Control */ | ||
111 | {VIASR, SR18, 0xFF, 0x4E}, /* GFX PREQ threshold */ | ||
112 | {VIASR, SR1A, 0xFF, 0x0a}, /* GFX PREQ threshold */ | ||
113 | {VIASR, SR1F, 0xFF, 0x00}, /* Memory Control 0 */ | ||
114 | {VIASR, SR1B, 0xFF, 0xF0}, /* Power Management Control 0 */ | ||
115 | {VIASR, SR1E, 0xFF, 0x01}, /* Power Management Control */ | ||
116 | {VIASR, SR20, 0xFF, 0x00}, /* Sequencer Arbiter Control 0 */ | ||
117 | {VIASR, SR21, 0xFF, 0x00}, /* Sequencer Arbiter Control 1 */ | ||
118 | {VIASR, SR22, 0xFF, 0x1F}, /* Display Arbiter Control 1 */ | ||
119 | {VIASR, SR2A, 0xFF, 0x00}, /* Power Management Control 5 */ | ||
120 | {VIASR, SR2D, 0xFF, 0xFF}, /* Power Management Control 1 */ | ||
121 | {VIASR, SR2E, 0xFF, 0xFF}, /* Power Management Control 2 */ | ||
122 | {VIACR, CR33, 0xFF, 0x00}, | ||
123 | {VIACR, CR55, 0x80, 0x00}, | ||
124 | {VIACR, CR5D, 0x80, 0x00}, | ||
125 | {VIACR, CR36, 0xFF, 0x01}, /* Power Mangement 3 */ | ||
126 | {VIACR, CR68, 0xFF, 0x67}, /* Default FIFO For IGA2 */ | ||
127 | {VIACR, CR6A, 0x20, 0x20}, /* Extended FIFO On */ | ||
128 | {VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */ | ||
129 | {VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */ | ||
130 | {VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */ | ||
131 | {VIACR, CR8B, 0xFF, 0x2D}, /* LCD Power Sequence Control 0 */ | ||
132 | {VIACR, CR8C, 0xFF, 0x2D}, /* LCD Power Sequence Control 1 */ | ||
133 | {VIACR, CR8D, 0xFF, 0xC8}, /* LCD Power Sequence Control 2 */ | ||
134 | {VIACR, CR8E, 0xFF, 0x36}, /* LCD Power Sequence Control 3 */ | ||
135 | {VIACR, CR8F, 0xFF, 0x00}, /* LCD Power Sequence Control 4 */ | ||
136 | {VIACR, CR90, 0xFF, 0x10}, /* LCD Power Sequence Control 5 */ | ||
137 | {VIACR, CR91, 0xFF, 0xA0}, /* 24/12 bit LVDS Data off */ | ||
138 | {VIACR, CR96, 0xFF, 0x03}, /* DVP0 ; DVP0 Clock Skew */ | ||
139 | {VIACR, CR97, 0xFF, 0x03}, /* DFP high ; DFPH Clock Skew */ | ||
140 | {VIACR, CR99, 0xFF, 0x03}, /* DFP low ; DFPL Clock Skew*/ | ||
141 | {VIACR, CR9B, 0xFF, 0x07} /* DVI on DVP1 ; DVP1 Clock Skew*/ | ||
142 | }; | ||
143 | |||
144 | /* For VT3324: Common Setting for Video Mode */ | ||
145 | struct io_reg CX700_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01}, | ||
146 | {VIASR, SR15, 0x02, 0x02}, | ||
147 | {VIASR, SR16, 0xBF, 0x08}, | ||
148 | {VIASR, SR17, 0xFF, 0x1F}, | ||
149 | {VIASR, SR18, 0xFF, 0x4E}, | ||
150 | {VIASR, SR1A, 0xFB, 0x08}, | ||
151 | {VIASR, SR1B, 0xFF, 0xF0}, | ||
152 | {VIASR, SR1E, 0xFF, 0x01}, | ||
153 | {VIASR, SR2A, 0xFF, 0x00}, | ||
154 | {VIASR, SR2D, 0xC0, 0xC0}, /* delayed E3_ECK */ | ||
155 | {VIACR, CR32, 0xFF, 0x00}, | ||
156 | {VIACR, CR33, 0xFF, 0x00}, | ||
157 | {VIACR, CR35, 0xFF, 0x00}, | ||
158 | {VIACR, CR36, 0x08, 0x00}, | ||
159 | {VIACR, CR47, 0xC8, 0x00}, /* Clear VCK Plus. */ | ||
160 | {VIACR, CR69, 0xFF, 0x00}, | ||
161 | {VIACR, CR6A, 0xFF, 0x40}, | ||
162 | {VIACR, CR6B, 0xFF, 0x00}, | ||
163 | {VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */ | ||
164 | {VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */ | ||
165 | {VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */ | ||
166 | {VIACR, CRD4, 0xFF, 0x81}, /* Second power sequence control */ | ||
167 | {VIACR, CR8B, 0xFF, 0x5D}, /* LCD Power Sequence Control 0 */ | ||
168 | {VIACR, CR8C, 0xFF, 0x2B}, /* LCD Power Sequence Control 1 */ | ||
169 | {VIACR, CR8D, 0xFF, 0x6F}, /* LCD Power Sequence Control 2 */ | ||
170 | {VIACR, CR8E, 0xFF, 0x2B}, /* LCD Power Sequence Control 3 */ | ||
171 | {VIACR, CR8F, 0xFF, 0x01}, /* LCD Power Sequence Control 4 */ | ||
172 | {VIACR, CR90, 0xFF, 0x01}, /* LCD Power Sequence Control 5 */ | ||
173 | {VIACR, CR91, 0xFF, 0x80}, /* 24/12 bit LVDS Data off */ | ||
174 | {VIACR, CR96, 0xFF, 0x00}, | ||
175 | {VIACR, CR97, 0xFF, 0x00}, | ||
176 | {VIACR, CR99, 0xFF, 0x00}, | ||
177 | {VIACR, CR9B, 0xFF, 0x00} | ||
178 | }; | ||
179 | |||
180 | struct io_reg VX855_ModeXregs[] = { | ||
181 | {VIASR, SR10, 0xFF, 0x01}, | ||
182 | {VIASR, SR15, 0x02, 0x02}, | ||
183 | {VIASR, SR16, 0xBF, 0x08}, | ||
184 | {VIASR, SR17, 0xFF, 0x1F}, | ||
185 | {VIASR, SR18, 0xFF, 0x4E}, | ||
186 | {VIASR, SR1A, 0xFB, 0x08}, | ||
187 | {VIASR, SR1B, 0xFF, 0xF0}, | ||
188 | {VIASR, SR1E, 0x07, 0x01}, | ||
189 | {VIASR, SR2A, 0xF0, 0x00}, | ||
190 | {VIASR, SR58, 0xFF, 0x00}, | ||
191 | {VIASR, SR59, 0xFF, 0x00}, | ||
192 | {VIASR, SR2D, 0xC0, 0xC0}, /* delayed E3_ECK */ | ||
193 | {VIACR, CR32, 0xFF, 0x00}, | ||
194 | {VIACR, CR33, 0x7F, 0x00}, | ||
195 | {VIACR, CR35, 0xFF, 0x00}, | ||
196 | {VIACR, CR36, 0x08, 0x00}, | ||
197 | {VIACR, CR69, 0xFF, 0x00}, | ||
198 | {VIACR, CR6A, 0xFD, 0x60}, | ||
199 | {VIACR, CR6B, 0xFF, 0x00}, | ||
200 | {VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */ | ||
201 | {VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */ | ||
202 | {VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */ | ||
203 | {VIACR, CRD4, 0xFF, 0x81}, /* Second power sequence control */ | ||
204 | {VIACR, CR91, 0xFF, 0x80}, /* 24/12 bit LVDS Data off */ | ||
205 | {VIACR, CR96, 0xFF, 0x00}, | ||
206 | {VIACR, CR97, 0xFF, 0x00}, | ||
207 | {VIACR, CR99, 0xFF, 0x00}, | ||
208 | {VIACR, CR9B, 0xFF, 0x00}, | ||
209 | {VIACR, CRD2, 0xFF, 0xFF} /* TMDS/LVDS control register. */ | ||
210 | }; | ||
211 | |||
212 | /* Video Mode Table */ | ||
213 | /* Common Setting for Video Mode */ | ||
214 | struct io_reg CLE266_ModeXregs[] = { {VIASR, SR1E, 0xF0, 0x00}, | ||
215 | {VIASR, SR2A, 0x0F, 0x00}, | ||
216 | {VIASR, SR15, 0x02, 0x02}, | ||
217 | {VIASR, SR16, 0xBF, 0x08}, | ||
218 | {VIASR, SR17, 0xFF, 0x1F}, | ||
219 | {VIASR, SR18, 0xFF, 0x4E}, | ||
220 | {VIASR, SR1A, 0xFB, 0x08}, | ||
221 | |||
222 | {VIACR, CR32, 0xFF, 0x00}, | ||
223 | {VIACR, CR35, 0xFF, 0x00}, | ||
224 | {VIACR, CR36, 0x08, 0x00}, | ||
225 | {VIACR, CR6A, 0xFF, 0x80}, | ||
226 | {VIACR, CR6A, 0xFF, 0xC0}, | ||
227 | |||
228 | {VIACR, CR55, 0x80, 0x00}, | ||
229 | {VIACR, CR5D, 0x80, 0x00}, | ||
230 | |||
231 | {VIAGR, GR20, 0xFF, 0x00}, | ||
232 | {VIAGR, GR21, 0xFF, 0x00}, | ||
233 | {VIAGR, GR22, 0xFF, 0x00}, | ||
234 | |||
235 | }; | ||
236 | |||
237 | /* Mode:1024X768 */ | ||
238 | struct io_reg PM1024x768[] = { {VIASR, 0x16, 0xBF, 0x0C}, | ||
239 | {VIASR, 0x18, 0xFF, 0x4C} | ||
240 | }; | ||
241 | |||
242 | struct patch_table res_patch_table[] = { | ||
243 | {ARRAY_SIZE(PM1024x768), PM1024x768} | ||
244 | }; | ||
245 | |||
246 | /* struct VPITTable { | ||
247 | unsigned char Misc; | ||
248 | unsigned char SR[StdSR]; | ||
249 | unsigned char CR[StdCR]; | ||
250 | unsigned char GR[StdGR]; | ||
251 | unsigned char AR[StdAR]; | ||
252 | };*/ | ||
253 | |||
254 | struct VPITTable VPIT = { | ||
255 | /* Msic */ | ||
256 | 0xC7, | ||
257 | /* Sequencer */ | ||
258 | {0x01, 0x0F, 0x00, 0x0E}, | ||
259 | /* Graphic Controller */ | ||
260 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF}, | ||
261 | /* Attribute Controller */ | ||
262 | {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | ||
263 | 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, | ||
264 | 0x01, 0x00, 0x0F, 0x00} | ||
265 | }; | ||
266 | |||
267 | /********************/ | ||
268 | /* Mode Table */ | ||
269 | /********************/ | ||
270 | |||
271 | static const struct fb_videomode viafb_modes[] = { | ||
272 | {NULL, 60, 480, 640, 40285, 72, 24, 19, 1, 48, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
273 | {NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, 0, 0, 0}, | ||
274 | {NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, 0, 0, 0}, | ||
275 | {NULL, 85, 640, 480, 27780, 80, 56, 25, 1, 56, 3, 0, 0, 0}, | ||
276 | {NULL, 100, 640, 480, 23167, 104, 40, 25, 1, 64, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
277 | {NULL, 120, 640, 480, 19081, 104, 40, 31, 1, 64, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
278 | {NULL, 60, 720, 480, 37426, 88, 16, 13, 1, 72, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
279 | {NULL, 60, 720, 576, 30611, 96, 24, 17, 1, 72, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
280 | {NULL, 60, 800, 600, 25131, 88, 40, 23, 1, 128, 4, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
281 | {NULL, 75, 800, 600, 20202, 160, 16, 21, 1, 80, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
282 | {NULL, 85, 800, 600, 17790, 152, 32, 27, 1, 64, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
283 | {NULL, 100, 800, 600, 14667, 136, 48, 32, 1, 88, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
284 | {NULL, 120, 800, 600, 11911, 144, 56, 39, 1, 88, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
285 | {NULL, 60, 800, 480, 33602, 96, 24, 10, 3, 72, 7, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
286 | {NULL, 60, 848, 480, 31565, 104, 24, 12, 3, 80, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
287 | {NULL, 60, 856, 480, 31517, 104, 16, 13, 1, 88, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
288 | {NULL, 60, 1024, 512, 24218, 136, 32, 15, 1, 104, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
289 | {NULL, 60, 1024, 600, 20423, 144, 40, 18, 1, 104, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
290 | {NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6, 0, 0, 0}, | ||
291 | {NULL, 75, 1024, 768, 12703, 176, 16, 28, 1, 96, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
292 | {NULL, 85, 1024, 768, 10581, 208, 48, 36, 1, 96, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
293 | {NULL, 100, 1024, 768, 8825, 184, 72, 42, 1, 112, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
294 | {NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
295 | {NULL, 60, 1280, 768, 12478, 200, 64, 23, 1, 136, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
296 | {NULL, 50, 1280, 768, 15342, 184, 56, 19, 1, 128, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
297 | {NULL, 60, 960, 600, 21964, 128, 32, 15, 3, 96, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
298 | {NULL, 60, 1000, 600, 20803, 144, 40, 18, 1, 104, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
299 | {NULL, 60, 1024, 576, 21278, 144, 40, 17, 1, 104, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
300 | {NULL, 60, 1088, 612, 18825, 152, 48, 16, 3, 104, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
301 | {NULL, 60, 1152, 720, 14974, 168, 56, 19, 3, 112, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
302 | {NULL, 60, 1200, 720, 14248, 184, 56, 22, 1, 128, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
303 | {NULL, 49, 1200, 900, 17703, 21, 11, 1, 1, 32, 10, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
304 | {NULL, 60, 1280, 600, 16259, 184, 56, 18, 1, 128, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
305 | {NULL, 60, 1280, 800, 11938, 200, 72, 22, 3, 128, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
306 | {NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
307 | {NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
308 | {NULL, 75, 1280, 1024, 7409, 248, 16, 38, 1, 144, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
309 | {NULL, 85, 1280, 1024, 6351, 224, 64, 44, 1, 160, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
310 | {NULL, 60, 1360, 768, 11759, 208, 72, 22, 3, 136, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
311 | {NULL, 60, 1368, 768, 11646, 216, 72, 23, 1, 144, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
312 | {NULL, 50, 1368, 768, 14301, 200, 56, 19, 1, 144, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
313 | {NULL, 60, 1368, 768, 11646, 216, 72, 23, 1, 144, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
314 | {NULL, 60, 1440, 900, 9372, 232, 80, 25, 3, 152, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
315 | {NULL, 75, 1440, 900, 7311, 248, 96, 33, 3, 152, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
316 | {NULL, 60, 1440, 1040, 7993, 248, 96, 33, 1, 152, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
317 | {NULL, 60, 1600, 900, 8449, 256, 88, 26, 3, 168, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
318 | {NULL, 60, 1600, 1024, 7333, 272, 104, 32, 1, 168, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
319 | {NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
320 | {NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
321 | {NULL, 60, 1680, 1050, 6832, 280, 104, 30, 3, 176, 6, 0, 0, 0}, | ||
322 | {NULL, 75, 1680, 1050, 5339, 296, 120, 40, 3, 176, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
323 | {NULL, 60, 1792, 1344, 4883, 328, 128, 46, 1, 200, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
324 | {NULL, 60, 1856, 1392, 4581, 352, 96, 43, 1, 224, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
325 | {NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 208, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
326 | {NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
327 | {NULL, 60, 2048, 1536, 3738, 376, 152, 49, 3, 224, 4, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
328 | {NULL, 60, 1280, 720, 13484, 216, 112, 20, 5, 40, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
329 | {NULL, 50, 1280, 720, 16538, 176, 48, 17, 1, 128, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
330 | {NULL, 60, 1920, 1080, 5776, 328, 128, 32, 3, 200, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
331 | {NULL, 60, 1920, 1200, 5164, 336, 136, 36, 3, 200, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
332 | {NULL, 60, 1400, 1050, 8210, 232, 88, 32, 3, 144, 4, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | ||
333 | {NULL, 75, 1400, 1050, 6398, 248, 104, 42, 3, 144, 4, FB_SYNC_VERT_HIGH_ACT, 0, 0} }; | ||
334 | |||
335 | static const struct fb_videomode viafb_rb_modes[] = { | ||
336 | {NULL, 60, 1360, 768, 13879, 80, 48, 14, 3, 32, 5, FB_SYNC_HOR_HIGH_ACT, 0, 0}, | ||
337 | {NULL, 60, 1440, 900, 11249, 80, 48, 17, 3, 32, 6, FB_SYNC_HOR_HIGH_ACT, 0, 0}, | ||
338 | {NULL, 60, 1400, 1050, 9892, 80, 48, 23, 3, 32, 4, FB_SYNC_HOR_HIGH_ACT, 0, 0}, | ||
339 | {NULL, 60, 1600, 900, 10226, 80, 48, 18, 3, 32, 5, FB_SYNC_HOR_HIGH_ACT, 0, 0}, | ||
340 | {NULL, 60, 1680, 1050, 8387, 80, 48, 21, 3, 32, 6, FB_SYNC_HOR_HIGH_ACT, 0, 0}, | ||
341 | {NULL, 60, 1920, 1080, 7212, 80, 48, 23, 3, 32, 5, FB_SYNC_HOR_HIGH_ACT, 0, 0}, | ||
342 | {NULL, 60, 1920, 1200, 6488, 80, 48, 26, 3, 32, 6, FB_SYNC_HOR_HIGH_ACT, 0, 0} }; | ||
343 | |||
344 | int NUM_TOTAL_CN400_ModeXregs = ARRAY_SIZE(CN400_ModeXregs); | ||
345 | int NUM_TOTAL_CN700_ModeXregs = ARRAY_SIZE(CN700_ModeXregs); | ||
346 | int NUM_TOTAL_KM400_ModeXregs = ARRAY_SIZE(KM400_ModeXregs); | ||
347 | int NUM_TOTAL_CX700_ModeXregs = ARRAY_SIZE(CX700_ModeXregs); | ||
348 | int NUM_TOTAL_VX855_ModeXregs = ARRAY_SIZE(VX855_ModeXregs); | ||
349 | int NUM_TOTAL_CLE266_ModeXregs = ARRAY_SIZE(CLE266_ModeXregs); | ||
350 | int NUM_TOTAL_PATCH_MODE = ARRAY_SIZE(res_patch_table); | ||
351 | |||
352 | |||
353 | static const struct fb_videomode *get_best_mode( | ||
354 | const struct fb_videomode *modes, int n, | ||
355 | int hres, int vres, int refresh) | ||
356 | { | ||
357 | const struct fb_videomode *best = NULL; | ||
358 | int i; | ||
359 | |||
360 | for (i = 0; i < n; i++) { | ||
361 | if (modes[i].xres != hres || modes[i].yres != vres) | ||
362 | continue; | ||
363 | |||
364 | if (!best || abs(modes[i].refresh - refresh) < | ||
365 | abs(best->refresh - refresh)) | ||
366 | best = &modes[i]; | ||
367 | } | ||
368 | |||
369 | return best; | ||
370 | } | ||
371 | |||
372 | const struct fb_videomode *viafb_get_best_mode(int hres, int vres, int refresh) | ||
373 | { | ||
374 | return get_best_mode(viafb_modes, ARRAY_SIZE(viafb_modes), | ||
375 | hres, vres, refresh); | ||
376 | } | ||
377 | |||
378 | const struct fb_videomode *viafb_get_best_rb_mode(int hres, int vres, | ||
379 | int refresh) | ||
380 | { | ||
381 | return get_best_mode(viafb_rb_modes, ARRAY_SIZE(viafb_rb_modes), | ||
382 | hres, vres, refresh); | ||
383 | } | ||
diff --git a/drivers/video/fbdev/via/viamode.h b/drivers/video/fbdev/via/viamode.h new file mode 100644 index 000000000000..dd19106698e7 --- /dev/null +++ b/drivers/video/fbdev/via/viamode.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef __VIAMODE_H__ | ||
23 | #define __VIAMODE_H__ | ||
24 | |||
25 | #include "global.h" | ||
26 | |||
27 | struct VPITTable { | ||
28 | unsigned char Misc; | ||
29 | unsigned char SR[StdSR]; | ||
30 | unsigned char GR[StdGR]; | ||
31 | unsigned char AR[StdAR]; | ||
32 | }; | ||
33 | |||
34 | struct patch_table { | ||
35 | int table_length; | ||
36 | struct io_reg *io_reg_table; | ||
37 | }; | ||
38 | |||
39 | extern int NUM_TOTAL_CN400_ModeXregs; | ||
40 | extern int NUM_TOTAL_CN700_ModeXregs; | ||
41 | extern int NUM_TOTAL_KM400_ModeXregs; | ||
42 | extern int NUM_TOTAL_CX700_ModeXregs; | ||
43 | extern int NUM_TOTAL_VX855_ModeXregs; | ||
44 | extern int NUM_TOTAL_CLE266_ModeXregs; | ||
45 | extern int NUM_TOTAL_PATCH_MODE; | ||
46 | |||
47 | extern struct io_reg CN400_ModeXregs[]; | ||
48 | extern struct io_reg CN700_ModeXregs[]; | ||
49 | extern struct io_reg KM400_ModeXregs[]; | ||
50 | extern struct io_reg CX700_ModeXregs[]; | ||
51 | extern struct io_reg VX800_ModeXregs[]; | ||
52 | extern struct io_reg VX855_ModeXregs[]; | ||
53 | extern struct io_reg CLE266_ModeXregs[]; | ||
54 | extern struct io_reg PM1024x768[]; | ||
55 | extern struct patch_table res_patch_table[]; | ||
56 | extern struct VPITTable VPIT; | ||
57 | |||
58 | const struct fb_videomode *viafb_get_best_mode(int hres, int vres, | ||
59 | int refresh); | ||
60 | const struct fb_videomode *viafb_get_best_rb_mode(int hres, int vres, | ||
61 | int refresh); | ||
62 | |||
63 | #endif /* __VIAMODE_H__ */ | ||
diff --git a/drivers/video/fbdev/via/vt1636.c b/drivers/video/fbdev/via/vt1636.c new file mode 100644 index 000000000000..ee2903b472cf --- /dev/null +++ b/drivers/video/fbdev/via/vt1636.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/via-core.h> | ||
23 | #include <linux/via_i2c.h> | ||
24 | #include "global.h" | ||
25 | |||
26 | static const struct IODATA common_init_data[] = { | ||
27 | /* Index, Mask, Value */ | ||
28 | /* Set panel power sequence timing */ | ||
29 | {0x10, 0xC0, 0x00}, | ||
30 | /* T1: VDD on - Data on. Each increment is 1 ms. (50ms = 031h) */ | ||
31 | {0x0B, 0xFF, 0x40}, | ||
32 | /* T2: Data on - Backlight on. Each increment is 2 ms. (210ms = 068h) */ | ||
33 | {0x0C, 0xFF, 0x31}, | ||
34 | /* T3: Backlight off -Data off. Each increment is 2 ms. (210ms = 068h)*/ | ||
35 | {0x0D, 0xFF, 0x31}, | ||
36 | /* T4: Data off - VDD off. Each increment is 1 ms. (50ms = 031h) */ | ||
37 | {0x0E, 0xFF, 0x68}, | ||
38 | /* T5: VDD off - VDD on. Each increment is 100 ms. (500ms = 04h) */ | ||
39 | {0x0F, 0xFF, 0x68}, | ||
40 | /* LVDS output power up */ | ||
41 | {0x09, 0xA0, 0xA0}, | ||
42 | /* turn on back light */ | ||
43 | {0x10, 0x33, 0x13} | ||
44 | }; | ||
45 | |||
46 | /* Index, Mask, Value */ | ||
47 | static const struct IODATA dual_channel_enable_data = {0x08, 0xF0, 0xE0}; | ||
48 | static const struct IODATA single_channel_enable_data = {0x08, 0xF0, 0x00}; | ||
49 | static const struct IODATA dithering_enable_data = {0x0A, 0x70, 0x50}; | ||
50 | static const struct IODATA dithering_disable_data = {0x0A, 0x70, 0x00}; | ||
51 | static const struct IODATA vdd_on_data = {0x10, 0x20, 0x20}; | ||
52 | static const struct IODATA vdd_off_data = {0x10, 0x20, 0x00}; | ||
53 | |||
54 | u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information | ||
55 | *plvds_setting_info, struct lvds_chip_information *plvds_chip_info, | ||
56 | u8 index) | ||
57 | { | ||
58 | u8 data; | ||
59 | |||
60 | viafb_i2c_readbyte(plvds_chip_info->i2c_port, | ||
61 | plvds_chip_info->lvds_chip_slave_addr, index, &data); | ||
62 | return data; | ||
63 | } | ||
64 | |||
65 | void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information | ||
66 | *plvds_setting_info, struct lvds_chip_information | ||
67 | *plvds_chip_info, struct IODATA io_data) | ||
68 | { | ||
69 | int index, data; | ||
70 | |||
71 | index = io_data.Index; | ||
72 | data = viafb_gpio_i2c_read_lvds(plvds_setting_info, plvds_chip_info, | ||
73 | index); | ||
74 | data = (data & (~io_data.Mask)) | io_data.Data; | ||
75 | |||
76 | viafb_i2c_writebyte(plvds_chip_info->i2c_port, | ||
77 | plvds_chip_info->lvds_chip_slave_addr, index, data); | ||
78 | } | ||
79 | |||
80 | void viafb_init_lvds_vt1636(struct lvds_setting_information | ||
81 | *plvds_setting_info, struct lvds_chip_information *plvds_chip_info) | ||
82 | { | ||
83 | int reg_num, i; | ||
84 | |||
85 | /* Common settings: */ | ||
86 | reg_num = ARRAY_SIZE(common_init_data); | ||
87 | for (i = 0; i < reg_num; i++) | ||
88 | viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, | ||
89 | plvds_chip_info, common_init_data[i]); | ||
90 | |||
91 | /* Input Data Mode Select */ | ||
92 | if (plvds_setting_info->device_lcd_dualedge) | ||
93 | viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, | ||
94 | plvds_chip_info, dual_channel_enable_data); | ||
95 | else | ||
96 | viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, | ||
97 | plvds_chip_info, single_channel_enable_data); | ||
98 | |||
99 | if (plvds_setting_info->LCDDithering) | ||
100 | viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, | ||
101 | plvds_chip_info, dithering_enable_data); | ||
102 | else | ||
103 | viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, | ||
104 | plvds_chip_info, dithering_disable_data); | ||
105 | } | ||
106 | |||
107 | void viafb_enable_lvds_vt1636(struct lvds_setting_information | ||
108 | *plvds_setting_info, | ||
109 | struct lvds_chip_information *plvds_chip_info) | ||
110 | { | ||
111 | viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info, | ||
112 | vdd_on_data); | ||
113 | } | ||
114 | |||
115 | void viafb_disable_lvds_vt1636(struct lvds_setting_information | ||
116 | *plvds_setting_info, | ||
117 | struct lvds_chip_information *plvds_chip_info) | ||
118 | { | ||
119 | viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info, | ||
120 | vdd_off_data); | ||
121 | } | ||
122 | |||
123 | bool viafb_lvds_identify_vt1636(u8 i2c_adapter) | ||
124 | { | ||
125 | u8 Buffer[2]; | ||
126 | |||
127 | DEBUG_MSG(KERN_INFO "viafb_lvds_identify_vt1636.\n"); | ||
128 | |||
129 | /* Sense VT1636 LVDS Transmiter */ | ||
130 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr = | ||
131 | VT1636_LVDS_I2C_ADDR; | ||
132 | |||
133 | /* Check vendor ID first: */ | ||
134 | if (viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, | ||
135 | 0x00, &Buffer[0])) | ||
136 | return false; | ||
137 | viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x01, &Buffer[1]); | ||
138 | |||
139 | if (!((Buffer[0] == 0x06) && (Buffer[1] == 0x11))) | ||
140 | return false; | ||
141 | |||
142 | /* Check Chip ID: */ | ||
143 | viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x02, &Buffer[0]); | ||
144 | viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x03, &Buffer[1]); | ||
145 | if ((Buffer[0] == 0x45) && (Buffer[1] == 0x33)) { | ||
146 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = | ||
147 | VT1636_LVDS; | ||
148 | return true; | ||
149 | } | ||
150 | |||
151 | return false; | ||
152 | } | ||
153 | |||
154 | static int get_clk_range_index(u32 Clk) | ||
155 | { | ||
156 | if (Clk < DPA_CLK_30M) | ||
157 | return DPA_CLK_RANGE_30M; | ||
158 | else if (Clk < DPA_CLK_50M) | ||
159 | return DPA_CLK_RANGE_30_50M; | ||
160 | else if (Clk < DPA_CLK_70M) | ||
161 | return DPA_CLK_RANGE_50_70M; | ||
162 | else if (Clk < DPA_CLK_100M) | ||
163 | return DPA_CLK_RANGE_70_100M; | ||
164 | else if (Clk < DPA_CLK_150M) | ||
165 | return DPA_CLK_RANGE_100_150M; | ||
166 | else | ||
167 | return DPA_CLK_RANGE_150M; | ||
168 | } | ||
169 | |||
170 | static void set_dpa_vt1636(struct lvds_setting_information | ||
171 | *plvds_setting_info, struct lvds_chip_information *plvds_chip_info, | ||
172 | struct VT1636_DPA_SETTING *p_vt1636_dpa_setting) | ||
173 | { | ||
174 | struct IODATA io_data; | ||
175 | |||
176 | io_data.Index = 0x09; | ||
177 | io_data.Mask = 0x1F; | ||
178 | io_data.Data = p_vt1636_dpa_setting->CLK_SEL_ST1; | ||
179 | viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, | ||
180 | plvds_chip_info, io_data); | ||
181 | |||
182 | io_data.Index = 0x08; | ||
183 | io_data.Mask = 0x0F; | ||
184 | io_data.Data = p_vt1636_dpa_setting->CLK_SEL_ST2; | ||
185 | viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info, | ||
186 | io_data); | ||
187 | } | ||
188 | |||
189 | void viafb_vt1636_patch_skew_on_vt3324( | ||
190 | struct lvds_setting_information *plvds_setting_info, | ||
191 | struct lvds_chip_information *plvds_chip_info) | ||
192 | { | ||
193 | struct VT1636_DPA_SETTING dpa = {0x00, 0x00}, dpa_16x12 = {0x0B, 0x03}, | ||
194 | *pdpa; | ||
195 | int index; | ||
196 | |||
197 | DEBUG_MSG(KERN_INFO "viafb_vt1636_patch_skew_on_vt3324.\n"); | ||
198 | |||
199 | /* Graphics DPA settings: */ | ||
200 | index = get_clk_range_index(plvds_setting_info->vclk); | ||
201 | viafb_set_dpa_gfx(plvds_chip_info->output_interface, | ||
202 | &GFX_DPA_SETTING_TBL_VT3324[index]); | ||
203 | |||
204 | /* LVDS Transmitter DPA settings: */ | ||
205 | if (plvds_setting_info->lcd_panel_hres == 1600 && | ||
206 | plvds_setting_info->lcd_panel_vres == 1200) | ||
207 | pdpa = &dpa_16x12; | ||
208 | else | ||
209 | pdpa = &dpa; | ||
210 | |||
211 | set_dpa_vt1636(plvds_setting_info, plvds_chip_info, pdpa); | ||
212 | } | ||
213 | |||
214 | void viafb_vt1636_patch_skew_on_vt3327( | ||
215 | struct lvds_setting_information *plvds_setting_info, | ||
216 | struct lvds_chip_information *plvds_chip_info) | ||
217 | { | ||
218 | struct VT1636_DPA_SETTING dpa = {0x00, 0x00}; | ||
219 | int index; | ||
220 | |||
221 | DEBUG_MSG(KERN_INFO "viafb_vt1636_patch_skew_on_vt3327.\n"); | ||
222 | |||
223 | /* Graphics DPA settings: */ | ||
224 | index = get_clk_range_index(plvds_setting_info->vclk); | ||
225 | viafb_set_dpa_gfx(plvds_chip_info->output_interface, | ||
226 | &GFX_DPA_SETTING_TBL_VT3327[index]); | ||
227 | |||
228 | /* LVDS Transmitter DPA settings: */ | ||
229 | set_dpa_vt1636(plvds_setting_info, plvds_chip_info, &dpa); | ||
230 | } | ||
231 | |||
232 | void viafb_vt1636_patch_skew_on_vt3364( | ||
233 | struct lvds_setting_information *plvds_setting_info, | ||
234 | struct lvds_chip_information *plvds_chip_info) | ||
235 | { | ||
236 | int index; | ||
237 | |||
238 | DEBUG_MSG(KERN_INFO "viafb_vt1636_patch_skew_on_vt3364.\n"); | ||
239 | |||
240 | /* Graphics DPA settings: */ | ||
241 | index = get_clk_range_index(plvds_setting_info->vclk); | ||
242 | viafb_set_dpa_gfx(plvds_chip_info->output_interface, | ||
243 | &GFX_DPA_SETTING_TBL_VT3364[index]); | ||
244 | } | ||
diff --git a/drivers/video/fbdev/via/vt1636.h b/drivers/video/fbdev/via/vt1636.h new file mode 100644 index 000000000000..4c1314e57468 --- /dev/null +++ b/drivers/video/fbdev/via/vt1636.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. | ||
4 | |||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * either version 2, or (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
12 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
13 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
14 | * for more details. | ||
15 | |||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef _VT1636_H_ | ||
23 | #define _VT1636_H_ | ||
24 | #include "chip.h" | ||
25 | bool viafb_lvds_identify_vt1636(u8 i2c_adapter); | ||
26 | void viafb_init_lvds_vt1636(struct lvds_setting_information | ||
27 | *plvds_setting_info, struct lvds_chip_information *plvds_chip_info); | ||
28 | void viafb_enable_lvds_vt1636(struct lvds_setting_information | ||
29 | *plvds_setting_info, | ||
30 | struct lvds_chip_information *plvds_chip_info); | ||
31 | void viafb_disable_lvds_vt1636(struct lvds_setting_information | ||
32 | *plvds_setting_info, | ||
33 | struct lvds_chip_information *plvds_chip_info); | ||
34 | void viafb_vt1636_patch_skew_on_vt3324( | ||
35 | struct lvds_setting_information *plvds_setting_info, | ||
36 | struct lvds_chip_information *plvds_chip_info); | ||
37 | void viafb_vt1636_patch_skew_on_vt3327( | ||
38 | struct lvds_setting_information *plvds_setting_info, | ||
39 | struct lvds_chip_information *plvds_chip_info); | ||
40 | void viafb_vt1636_patch_skew_on_vt3364( | ||
41 | struct lvds_setting_information *plvds_setting_info, | ||
42 | struct lvds_chip_information *plvds_chip_info); | ||
43 | |||
44 | #endif | ||