1 /* program the DAC */
2 /* Author:
3 Rudolf Cornelissen 4/2003-4/2004
4 */
5
6 #define MODULE_BIT 0x00010000
7
8 #include "nm_std.h"
9
10 /*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
nm_dac_mode(int mode,float brightness)11 status_t nm_dac_mode(int mode,float brightness)
12 {
13 uint8 *r, *g, *b, t[256];
14 uint16 i;
15
16 /*set colour arrays to point to space reserved in shared info*/
17 r = si->color_data;
18 g = r + 256;
19 b = g + 256;
20
21 LOG(4,("DAC: Setting screen mode %d brightness %f\n", mode, brightness));
22 /*init a basic palette for brightness specified*/
23 for (i = 0; i < 256; i++)
24 {
25 int ri = i * brightness;
26 if (ri > 255) ri = 255;
27 t[i] = ri;
28 }
29
30 /*modify the palette for the specified mode (&validate mode)*/
31 /* Note: the Neomagic chips have a 6 bit wide Palette RAM! */
32 switch(mode)
33 {
34 case BPP8:
35 LOG(8,("DAC: 8bit mode is indexed by OS, aborting brightness setup.\n"));
36 return B_OK;
37 break;
38 case BPP24:
39 LOG(8,("DAC: 24bit mode is a direct mode, aborting brightness setup.\n"));
40 return B_OK;
41 //fixme: unnessesary? direct mode (6bits PAL RAM is insufficient here!)
42 /* for (i = 0; i < 256; i++)
43 {
44 b[i] = g[i] = r[i] = t[i];
45 }
46 */ break;
47 case BPP16:
48 for (i = 0; i < 32; i++)
49 {
50 /* blue and red have only the 5 most significant bits */
51 b[i] = r[i] = t[i << 3];
52 }
53 for (i = 0; i < 64; i++)
54 {
55 /* the green component has 6 bits */
56 g[i] = t[i << 2];
57 }
58 break;
59 case BPP15:
60 for (i = 0; i < 32; i++)
61 {
62 /* all color components have 5 bits */
63 g[i] = r[i] = b[i] = t[i << 3];
64 }
65 break;
66 default:
67 LOG(8,("DAC: Invalid colordepth requested, aborting!\n"));
68 return B_ERROR;
69 break;
70 }
71
72 if (nm_dac_palette(r, g, b, i) != B_OK) return B_ERROR;
73
74 /*set the mode - also sets VCLK dividor*/
75 // DXIW(MULCTRL, mode);
76 // LOG(2,("DAC: mulctrl 0x%02x\n", DXIR(MULCTRL)));
77
78 /* disable palette RAM adressing mask */
79 ISAWB(PALMASK, 0xff);
80 LOG(2,("DAC: PAL pixrdmsk readback $%02x\n", ISARB(PALMASK)));
81
82 return B_OK;
83 }
84
85 /* program the DAC palette using the given r,g,b values */
nm_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256],uint16 cnt)86 status_t nm_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256], uint16 cnt)
87 {
88 int i;
89
90 LOG(4,("DAC: setting palette\n"));
91
92 /* select first PAL adress before starting programming */
93 ISAWB(PALINDW, 0x00);
94
95 /* loop through all 256 to program DAC */
96 for (i = 0; i < cnt; i++)
97 {
98 /* the 6 implemented bits are on b0-b5 of the bus */
99 ISAWB(PALDATA, (r[i] >> 2));
100 ISAWB(PALDATA, (g[i] >> 2));
101 ISAWB(PALDATA, (b[i] >> 2));
102 }
103 if (ISARB(PALINDW) != (cnt & 0x00ff))
104 {
105 LOG(8,("DAC: PAL write index incorrect after programming\n"));
106 return B_ERROR;
107 }
108 if (1)
109 {//reread LUT
110 uint8 R, G, B;
111
112 /* select first PAL adress to read (modulo 3 counter) */
113 ISAWB(PALINDR, 0x00);
114 for (i = 0; i < cnt; i++)
115 {
116 /* the 6 implemented bits are on b0-b5 of the bus */
117 R = (ISARB(PALDATA) << 2);
118 G = (ISARB(PALDATA) << 2);
119 B = (ISARB(PALDATA) << 2);
120 /* only compare the most significant 6 bits */
121 if (((r[i] & 0xfc) != R) || ((g[i] & 0xfc) != G) || ((b[i] & 0xfc) != B))
122 LOG(1,("DAC palette %d: w %x %x %x, r %x %x %x\n", i, r[i], g[i], b[i], R, G, B)); // apsed
123 }
124 }
125
126 return B_OK;
127 }
128
129 /*program the pixpll - frequency in kHz*/
130 /* important note:
131 * PIXPLLC is used - others should be kept as is
132 */
nm_dac_set_pix_pll(display_mode target)133 status_t nm_dac_set_pix_pll(display_mode target)
134 {
135 uint8 m=0,n=0,p=0;
136 uint8 temp;
137 // uint time = 0;
138
139 float pix_setting, req_pclk;
140 status_t result;
141
142 req_pclk = (target.timing.pixel_clock)/1000.0;
143 LOG(4,("DAC: Setting PIX PLL for pixelclock %f\n", req_pclk));
144
145 result = nm_dac_pix_pll_find(target,&pix_setting,&m,&n,&p);
146 if (result != B_OK)
147 {
148 return result;
149 }
150
151 /*reprogram (disable,select,wait for stability,enable)*/
152 //unknown on Neomagic?:
153 // DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/
154 // DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/
155
156 /* select PixelPLL registerset C */
157 temp = (ISARB(MISCR) | 0x0c);
158 /* we need to wait a bit or the card will mess-up it's register values.. */
159 snooze(10);
160 ISAWB(MISCW, temp);
161
162 /*set VCO divider (lsb) */
163 ISAGRPHW(PLLC_NL, n);
164 /*set VCO divider (msb) if it exists */
165 if (si->ps.card_type >= NM2200)
166 {
167 temp = (ISAGRPHR(PLLC_NH) & 0x0f);
168 /* we need to wait a bit or the card will mess-up it's register values.. */
169 snooze(10);
170 ISAGRPHW(PLLC_NH, (temp | (p & 0xf0)));
171 }
172 /*set main reference frequency divider */
173 ISAGRPHW(PLLC_M, m);
174
175 /* Wait for the PIXPLL frequency to lock until timeout occurs */
176 //unknown on Neomagic?:
177 /* while((!(DXIR(PIXPLLSTAT)&0x40)) & (time <= 2000))
178 {
179 time++;
180 snooze(1);
181 }
182
183 if (time > 2000)
184 LOG(2,("DAC: PIX PLL frequency not locked!\n"));
185 else
186 LOG(2,("DAC: PIX PLL frequency locked\n"));
187 DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); //enable the PIXPLL
188 */
189
190 //for now:
191 /* Give the PIXPLL frequency some time to lock... */
192 snooze(1000);
193 LOG(4,("DAC: PLLSEL $%02x\n", ISARB(MISCR)));
194 LOG(4,("DAC: PLLN $%02x\n", ISAGRPHR(PLLC_NL)));
195 LOG(4,("DAC: PLLM $%02x\n", ISAGRPHR(PLLC_M)));
196
197 LOG(2,("DAC: PIX PLL frequency should be locked now...\n"));
198
199 return B_OK;
200 }
201
202 /* find nearest valid pix pll */
nm_dac_pix_pll_find(display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result)203 status_t nm_dac_pix_pll_find
204 (display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result)
205 {
206 int m = 0, n = 0, p = 0, n_max, m_max;
207 float error, error_best = 999999999;
208 int best[2] = { 0, 0 };
209 float f_vco, max_pclk;
210 float req_pclk = target.timing.pixel_clock/1000.0;
211
212 /* determine the max. scaler settings for the current card */
213 switch (si->ps.card_type)
214 {
215 case NM2070:
216 LOG(4,("DAC: NM2070 restrictions apply\n"));
217 m_max = 32;
218 n_max = 128;
219 break;
220 case NM2090:
221 case NM2093:
222 case NM2097:
223 case NM2160:
224 LOG(4,("DAC: NM2090/93/97/NM2160 restrictions apply\n"));
225 m_max = 64;
226 n_max = 128;
227 break;
228 default:
229 LOG(4,("DAC: NM22xx/NM23xx restrictions apply\n"));
230 m_max = 64;
231 n_max = 2048;
232 break;
233 }
234
235 /* determine the max. pixelclock for the current videomode */
236 switch (target.space)
237 {
238 case B_CMAP8:
239 max_pclk = si->ps.max_dac1_clock_8;
240 break;
241 case B_RGB15_LITTLE:
242 case B_RGB16_LITTLE:
243 max_pclk = si->ps.max_dac1_clock_16;
244 break;
245 case B_RGB24_LITTLE:
246 max_pclk = si->ps.max_dac1_clock_24;
247 break;
248 default:
249 /* use fail-safe value */
250 max_pclk = si->ps.max_dac1_clock_24;
251 break;
252 }
253
254 /* Make sure the requested pixelclock is within the PLL's operational limits */
255 /* lower limit is min_pixel_vco (PLL postscaler does not exist in NM cards) */
256 if (req_pclk < si->ps.min_pixel_vco)
257 {
258 LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n",
259 req_pclk, (float)si->ps.min_pixel_vco));
260 req_pclk = si->ps.min_pixel_vco;
261 }
262 /* upper limit is given by pins in combination with current active mode */
263 if (req_pclk > max_pclk)
264 {
265 LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n",
266 req_pclk, (float)max_pclk));
267 req_pclk = max_pclk;
268 }
269
270 /* calculate the needed VCO frequency for this postscaler setting
271 * (NM cards have no PLL postscaler) */
272 f_vco = req_pclk;
273
274 /* iterate trough all valid reference-frequency postscaler settings */
275 for (m = 1; m <= m_max; m++)
276 {
277 /* only even reference postscaler settings are supported beyond half the range */
278 if ((m > (m_max / 2)) && ((m / 2.0) != 0.0)) continue;
279 /* calculate VCO postscaler setting for current setup.. */
280 n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
281 /* ..and check for validity */
282 if ((n < 1) || (n > n_max)) continue;
283
284 /* find error in frequency this setting gives */
285 error = fabs(req_pclk - ((si->ps.f_ref / m) * n));
286
287 /* note the setting if best yet */
288 if (error < error_best)
289 {
290 error_best = error;
291 best[0] = m;
292 best[1] = n;
293 }
294 }
295
296 /* setup the scalers programming values for found optimum setting */
297 n = best[1] - 1;
298 /* the reference frequency postscaler are actually two postscalers:
299 * p can divide by 1 or 2, and m can divide by 1-32 (1-16 for NM2070). */
300 if (best[0] <= (m_max / 2))
301 {
302 m = best[0] - 1;
303 p = (0 << 7);
304 }
305 else
306 {
307 m = (best[0] / 2) - 1;
308 p = (1 << 7);
309 }
310
311 /* display and return the results */
312 *calc_pclk = (si->ps.f_ref / best[0]) * best[1];
313 *m_result = m;
314 if (si->ps.card_type < NM2200)
315 {
316 *n_result = ((n & 0x07f) | p);
317 *p_result = 0;
318 LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, nm $%02x $%02x\n",
319 req_pclk, *calc_pclk, *n_result, *m_result));
320 }
321 else
322 {
323 *n_result = (n & 0x0ff);
324 *p_result = (((n & 0x700) >> 4) | p);
325 LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, pnm $%02x $%02x $%02x\n",
326 req_pclk, *calc_pclk, *p_result, *n_result, *m_result));
327 }
328
329 return B_OK;
330 }
331