1*4882a593Smuzhiyun /*-*- linux-c -*-
2*4882a593Smuzhiyun * linux/drivers/video/i810_main.h -- Intel 810 Non-discrete Video Timings
3*4882a593Smuzhiyun * (VESA GTF)
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
6*4882a593Smuzhiyun * All Rights Reserved
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General Public
10*4882a593Smuzhiyun * License. See the file COPYING in the main directory of this archive for
11*4882a593Smuzhiyun * more details.
12*4882a593Smuzhiyun */
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include "i810_regs.h"
16*4882a593Smuzhiyun #include "i810.h"
17*4882a593Smuzhiyun #include "i810_main.h"
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun /*
20*4882a593Smuzhiyun * FIFO and Watermark tables - based almost wholly on i810_wmark.c in
21*4882a593Smuzhiyun * XFree86 v4.03 by Precision Insight. Slightly modified for integer
22*4882a593Smuzhiyun * operation, instead of float
23*4882a593Smuzhiyun */
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun struct wm_info {
26*4882a593Smuzhiyun u32 freq;
27*4882a593Smuzhiyun u32 wm;
28*4882a593Smuzhiyun };
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun static struct wm_info i810_wm_8_100[] = {
31*4882a593Smuzhiyun { 15, 0x0070c000 }, { 19, 0x0070c000 }, { 25, 0x22003000 },
32*4882a593Smuzhiyun { 28, 0x22003000 }, { 31, 0x22003000 }, { 36, 0x22007000 },
33*4882a593Smuzhiyun { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22008000 },
34*4882a593Smuzhiyun { 50, 0x22008000 }, { 56, 0x22008000 }, { 65, 0x22008000 },
35*4882a593Smuzhiyun { 75, 0x22008000 }, { 78, 0x22008000 }, { 80, 0x22008000 },
36*4882a593Smuzhiyun { 94, 0x22008000 }, { 96, 0x22107000 }, { 99, 0x22107000 },
37*4882a593Smuzhiyun { 108, 0x22107000 }, { 121, 0x22107000 }, { 128, 0x22107000 },
38*4882a593Smuzhiyun { 132, 0x22109000 }, { 135, 0x22109000 }, { 157, 0x2210b000 },
39*4882a593Smuzhiyun { 162, 0x2210b000 }, { 175, 0x2210b000 }, { 189, 0x2220e000 },
40*4882a593Smuzhiyun { 195, 0x2220e000 }, { 202, 0x2220e000 }, { 204, 0x2220e000 },
41*4882a593Smuzhiyun { 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 },
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun static struct wm_info i810_wm_16_100[] = {
45*4882a593Smuzhiyun { 15, 0x0070c000 }, { 19, 0x0020c000 }, { 25, 0x22006000 },
46*4882a593Smuzhiyun { 28, 0x22006000 }, { 31, 0x22007000 }, { 36, 0x22007000 },
47*4882a593Smuzhiyun { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22009000 },
48*4882a593Smuzhiyun { 50, 0x22009000 }, { 56, 0x22108000 }, { 65, 0x2210e000 },
49*4882a593Smuzhiyun { 75, 0x2210e000 }, { 78, 0x2210e000 }, { 80, 0x22210000 },
50*4882a593Smuzhiyun { 94, 0x22210000 }, { 96, 0x22210000 }, { 99, 0x22210000 },
51*4882a593Smuzhiyun { 108, 0x22210000 }, { 121, 0x22210000 }, { 128, 0x22210000 },
52*4882a593Smuzhiyun { 132, 0x22314000 }, { 135, 0x22314000 }, { 157, 0x22415000 },
53*4882a593Smuzhiyun { 162, 0x22416000 }, { 175, 0x22416000 }, { 189, 0x22416000 },
54*4882a593Smuzhiyun { 195, 0x22416000 }, { 202, 0x22416000 }, { 204, 0x22416000 },
55*4882a593Smuzhiyun { 218, 0x22416000 }, { 229, 0x22416000 },
56*4882a593Smuzhiyun };
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun static struct wm_info i810_wm_24_100[] = {
59*4882a593Smuzhiyun { 15, 0x0020c000 }, { 19, 0x0040c000 }, { 25, 0x22009000 },
60*4882a593Smuzhiyun { 28, 0x22009000 }, { 31, 0x2200a000 }, { 36, 0x2210c000 },
61*4882a593Smuzhiyun { 40, 0x2210c000 }, { 45, 0x2210c000 }, { 49, 0x22111000 },
62*4882a593Smuzhiyun { 50, 0x22111000 }, { 56, 0x22111000 }, { 65, 0x22214000 },
63*4882a593Smuzhiyun { 75, 0x22214000 }, { 78, 0x22215000 }, { 80, 0x22216000 },
64*4882a593Smuzhiyun { 94, 0x22218000 }, { 96, 0x22418000 }, { 99, 0x22418000 },
65*4882a593Smuzhiyun { 108, 0x22418000 }, { 121, 0x22418000 }, { 128, 0x22419000 },
66*4882a593Smuzhiyun { 132, 0x22519000 }, { 135, 0x4441d000 }, { 157, 0x44419000 },
67*4882a593Smuzhiyun { 162, 0x44419000 }, { 175, 0x44419000 }, { 189, 0x44419000 },
68*4882a593Smuzhiyun { 195, 0x44419000 }, { 202, 0x44419000 }, { 204, 0x44419000 },
69*4882a593Smuzhiyun };
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun static struct wm_info i810_wm_8_133[] = {
72*4882a593Smuzhiyun { 15, 0x0070c000 }, { 19, 0x0070c000 }, { 25, 0x22003000 },
73*4882a593Smuzhiyun { 28, 0x22003000 }, { 31, 0x22003000 }, { 36, 0x22007000 },
74*4882a593Smuzhiyun { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22008000 },
75*4882a593Smuzhiyun { 50, 0x22008000 }, { 56, 0x22008000 }, { 65, 0x22008000 },
76*4882a593Smuzhiyun { 75, 0x22008000 }, { 78, 0x22008000 }, { 80, 0x22008000 },
77*4882a593Smuzhiyun { 94, 0x22008000 }, { 96, 0x22107000 }, { 99, 0x22107000 },
78*4882a593Smuzhiyun { 108, 0x22107000 }, { 121, 0x22107000 }, { 128, 0x22107000 },
79*4882a593Smuzhiyun { 132, 0x22109000 }, { 135, 0x22109000 }, { 157, 0x2210b000 },
80*4882a593Smuzhiyun { 162, 0x2210b000 }, { 175, 0x2210b000 }, { 189, 0x2220e000 },
81*4882a593Smuzhiyun { 195, 0x2220e000 }, { 202, 0x2220e000 }, { 204, 0x2220e000 },
82*4882a593Smuzhiyun { 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 },
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun static struct wm_info i810_wm_16_133[] = {
86*4882a593Smuzhiyun { 15, 0x0020c000 }, { 19, 0x0020c000 }, { 25, 0x22006000 },
87*4882a593Smuzhiyun { 28, 0x22006000 }, { 31, 0x22007000 }, { 36, 0x22007000 },
88*4882a593Smuzhiyun { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22009000 },
89*4882a593Smuzhiyun { 50, 0x22009000 }, { 56, 0x22108000 }, { 65, 0x2210e000 },
90*4882a593Smuzhiyun { 75, 0x2210e000 }, { 78, 0x2210e000 }, { 80, 0x22210000 },
91*4882a593Smuzhiyun { 94, 0x22210000 }, { 96, 0x22210000 }, { 99, 0x22210000 },
92*4882a593Smuzhiyun { 108, 0x22210000 }, { 121, 0x22210000 }, { 128, 0x22210000 },
93*4882a593Smuzhiyun { 132, 0x22314000 }, { 135, 0x22314000 }, { 157, 0x22415000 },
94*4882a593Smuzhiyun { 162, 0x22416000 }, { 175, 0x22416000 }, { 189, 0x22416000 },
95*4882a593Smuzhiyun { 195, 0x22416000 }, { 202, 0x22416000 }, { 204, 0x22416000 },
96*4882a593Smuzhiyun { 218, 0x22416000 }, { 229, 0x22416000 },
97*4882a593Smuzhiyun };
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun static struct wm_info i810_wm_24_133[] = {
100*4882a593Smuzhiyun { 15, 0x0020c000 }, { 19, 0x00408000 }, { 25, 0x22009000 },
101*4882a593Smuzhiyun { 28, 0x22009000 }, { 31, 0x2200a000 }, { 36, 0x2210c000 },
102*4882a593Smuzhiyun { 40, 0x2210c000 }, { 45, 0x2210c000 }, { 49, 0x22111000 },
103*4882a593Smuzhiyun { 50, 0x22111000 }, { 56, 0x22111000 }, { 65, 0x22214000 },
104*4882a593Smuzhiyun { 75, 0x22214000 }, { 78, 0x22215000 }, { 80, 0x22216000 },
105*4882a593Smuzhiyun { 94, 0x22218000 }, { 96, 0x22418000 }, { 99, 0x22418000 },
106*4882a593Smuzhiyun { 108, 0x22418000 }, { 121, 0x22418000 }, { 128, 0x22419000 },
107*4882a593Smuzhiyun { 132, 0x22519000 }, { 135, 0x4441d000 }, { 157, 0x44419000 },
108*4882a593Smuzhiyun { 162, 0x44419000 }, { 175, 0x44419000 }, { 189, 0x44419000 },
109*4882a593Smuzhiyun { 195, 0x44419000 }, { 202, 0x44419000 }, { 204, 0x44419000 },
110*4882a593Smuzhiyun };
111*4882a593Smuzhiyun
round_off_xres(u32 * xres)112*4882a593Smuzhiyun void round_off_xres(u32 *xres) { }
round_off_yres(u32 * xres,u32 * yres)113*4882a593Smuzhiyun void round_off_yres(u32 *xres, u32 *yres) { }
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun /**
116*4882a593Smuzhiyun * i810fb_encode_registers - encode @var to hardware register values
117*4882a593Smuzhiyun * @var: pointer to var structure
118*4882a593Smuzhiyun * @par: pointer to hardware par structure
119*4882a593Smuzhiyun *
120*4882a593Smuzhiyun * DESCRIPTION:
121*4882a593Smuzhiyun * Timing values in @var will be converted to appropriate
122*4882a593Smuzhiyun * register values of @par.
123*4882a593Smuzhiyun */
i810fb_encode_registers(const struct fb_var_screeninfo * var,struct i810fb_par * par,u32 xres,u32 yres)124*4882a593Smuzhiyun void i810fb_encode_registers(const struct fb_var_screeninfo *var,
125*4882a593Smuzhiyun struct i810fb_par *par, u32 xres, u32 yres)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun int n, blank_s, blank_e;
128*4882a593Smuzhiyun u8 __iomem *mmio = par->mmio_start_virtual;
129*4882a593Smuzhiyun u8 msr = 0;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun /* Horizontal */
132*4882a593Smuzhiyun /* htotal */
133*4882a593Smuzhiyun n = ((xres + var->right_margin + var->hsync_len +
134*4882a593Smuzhiyun var->left_margin) >> 3) - 5;
135*4882a593Smuzhiyun par->regs.cr00 = (u8) n;
136*4882a593Smuzhiyun par->regs.cr35 = (u8) ((n >> 8) & 1);
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /* xres */
139*4882a593Smuzhiyun par->regs.cr01 = (u8) ((xres >> 3) - 1);
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun /* hblank */
142*4882a593Smuzhiyun blank_e = (xres + var->right_margin + var->hsync_len +
143*4882a593Smuzhiyun var->left_margin) >> 3;
144*4882a593Smuzhiyun blank_e--;
145*4882a593Smuzhiyun blank_s = blank_e - 127;
146*4882a593Smuzhiyun if (blank_s < (xres >> 3))
147*4882a593Smuzhiyun blank_s = xres >> 3;
148*4882a593Smuzhiyun par->regs.cr02 = (u8) blank_s;
149*4882a593Smuzhiyun par->regs.cr03 = (u8) (blank_e & 0x1F);
150*4882a593Smuzhiyun par->regs.cr05 = (u8) ((blank_e & (1 << 5)) << 2);
151*4882a593Smuzhiyun par->regs.cr39 = (u8) ((blank_e >> 6) & 1);
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun /* hsync */
154*4882a593Smuzhiyun par->regs.cr04 = (u8) ((xres + var->right_margin) >> 3);
155*4882a593Smuzhiyun par->regs.cr05 |= (u8) (((xres + var->right_margin +
156*4882a593Smuzhiyun var->hsync_len) >> 3) & 0x1F);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /* Vertical */
159*4882a593Smuzhiyun /* vtotal */
160*4882a593Smuzhiyun n = yres + var->lower_margin + var->vsync_len + var->upper_margin - 2;
161*4882a593Smuzhiyun par->regs.cr06 = (u8) (n & 0xFF);
162*4882a593Smuzhiyun par->regs.cr30 = (u8) ((n >> 8) & 0x0F);
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun /* vsync */
165*4882a593Smuzhiyun n = yres + var->lower_margin;
166*4882a593Smuzhiyun par->regs.cr10 = (u8) (n & 0xFF);
167*4882a593Smuzhiyun par->regs.cr32 = (u8) ((n >> 8) & 0x0F);
168*4882a593Smuzhiyun par->regs.cr11 = i810_readb(CR11, mmio) & ~0x0F;
169*4882a593Smuzhiyun par->regs.cr11 |= (u8) ((yres + var->lower_margin +
170*4882a593Smuzhiyun var->vsync_len) & 0x0F);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /* yres */
173*4882a593Smuzhiyun n = yres - 1;
174*4882a593Smuzhiyun par->regs.cr12 = (u8) (n & 0xFF);
175*4882a593Smuzhiyun par->regs.cr31 = (u8) ((n >> 8) & 0x0F);
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun /* vblank */
178*4882a593Smuzhiyun blank_e = yres + var->lower_margin + var->vsync_len +
179*4882a593Smuzhiyun var->upper_margin;
180*4882a593Smuzhiyun blank_e--;
181*4882a593Smuzhiyun blank_s = blank_e - 127;
182*4882a593Smuzhiyun if (blank_s < yres)
183*4882a593Smuzhiyun blank_s = yres;
184*4882a593Smuzhiyun par->regs.cr15 = (u8) (blank_s & 0xFF);
185*4882a593Smuzhiyun par->regs.cr33 = (u8) ((blank_s >> 8) & 0x0F);
186*4882a593Smuzhiyun par->regs.cr16 = (u8) (blank_e & 0xFF);
187*4882a593Smuzhiyun par->regs.cr09 = 0;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun /* sync polarity */
190*4882a593Smuzhiyun if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
191*4882a593Smuzhiyun msr |= 1 << 6;
192*4882a593Smuzhiyun if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
193*4882a593Smuzhiyun msr |= 1 << 7;
194*4882a593Smuzhiyun par->regs.msr = msr;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /* interlace */
197*4882a593Smuzhiyun if (var->vmode & FB_VMODE_INTERLACED)
198*4882a593Smuzhiyun par->interlace = (1 << 7) | ((u8) (var->yres >> 4));
199*4882a593Smuzhiyun else
200*4882a593Smuzhiyun par->interlace = 0;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (var->vmode & FB_VMODE_DOUBLE)
203*4882a593Smuzhiyun par->regs.cr09 |= 1 << 7;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun /* overlay */
206*4882a593Smuzhiyun par->ovract = ((var->xres + var->right_margin + var->hsync_len +
207*4882a593Smuzhiyun var->left_margin - 32) | ((var->xres - 32) << 16));
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
i810fb_fill_var_timings(struct fb_var_screeninfo * var)210*4882a593Smuzhiyun void i810fb_fill_var_timings(struct fb_var_screeninfo *var) { }
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun /**
213*4882a593Smuzhiyun * i810_get_watermark - gets watermark
214*4882a593Smuzhiyun * @var: pointer to fb_var_screeninfo
215*4882a593Smuzhiyun * @par: pointer to i810fb_par structure
216*4882a593Smuzhiyun *
217*4882a593Smuzhiyun * DESCRIPTION:
218*4882a593Smuzhiyun * Gets the required watermark based on
219*4882a593Smuzhiyun * pixelclock and RAMBUS frequency.
220*4882a593Smuzhiyun *
221*4882a593Smuzhiyun * RETURNS:
222*4882a593Smuzhiyun * watermark
223*4882a593Smuzhiyun */
i810_get_watermark(const struct fb_var_screeninfo * var,struct i810fb_par * par)224*4882a593Smuzhiyun u32 i810_get_watermark(const struct fb_var_screeninfo *var,
225*4882a593Smuzhiyun struct i810fb_par *par)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun struct wm_info *wmark = NULL;
228*4882a593Smuzhiyun u32 i, size = 0, pixclock, wm_best = 0, min, diff;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun if (par->mem_freq == 100) {
231*4882a593Smuzhiyun switch (var->bits_per_pixel) {
232*4882a593Smuzhiyun case 8:
233*4882a593Smuzhiyun wmark = i810_wm_8_100;
234*4882a593Smuzhiyun size = ARRAY_SIZE(i810_wm_8_100);
235*4882a593Smuzhiyun break;
236*4882a593Smuzhiyun case 16:
237*4882a593Smuzhiyun wmark = i810_wm_16_100;
238*4882a593Smuzhiyun size = ARRAY_SIZE(i810_wm_16_100);
239*4882a593Smuzhiyun break;
240*4882a593Smuzhiyun case 24:
241*4882a593Smuzhiyun case 32:
242*4882a593Smuzhiyun wmark = i810_wm_24_100;
243*4882a593Smuzhiyun size = ARRAY_SIZE(i810_wm_24_100);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun } else {
246*4882a593Smuzhiyun switch(var->bits_per_pixel) {
247*4882a593Smuzhiyun case 8:
248*4882a593Smuzhiyun wmark = i810_wm_8_133;
249*4882a593Smuzhiyun size = ARRAY_SIZE(i810_wm_8_133);
250*4882a593Smuzhiyun break;
251*4882a593Smuzhiyun case 16:
252*4882a593Smuzhiyun wmark = i810_wm_16_133;
253*4882a593Smuzhiyun size = ARRAY_SIZE(i810_wm_16_133);
254*4882a593Smuzhiyun break;
255*4882a593Smuzhiyun case 24:
256*4882a593Smuzhiyun case 32:
257*4882a593Smuzhiyun wmark = i810_wm_24_133;
258*4882a593Smuzhiyun size = ARRAY_SIZE(i810_wm_24_133);
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun pixclock = 1000000/var->pixclock;
263*4882a593Smuzhiyun min = ~0;
264*4882a593Smuzhiyun for (i = 0; i < size; i++) {
265*4882a593Smuzhiyun if (pixclock <= wmark[i].freq)
266*4882a593Smuzhiyun diff = wmark[i].freq - pixclock;
267*4882a593Smuzhiyun else
268*4882a593Smuzhiyun diff = pixclock - wmark[i].freq;
269*4882a593Smuzhiyun if (diff < min) {
270*4882a593Smuzhiyun wm_best = wmark[i].wm;
271*4882a593Smuzhiyun min = diff;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun return wm_best;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
277