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)*/
11status_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 */
86status_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	}
108if (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 */
133status_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 */
203status_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