1/*
2 * Acceleration for the Creator and Creator3D framebuffer - WID pool management.
3 *
4 * Copyright (C) 2000 David S. Miller (davem@redhat.com)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * DAVID MILLER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include "ffb.h"
30
31static void
32determine_numwids(FFBPtr pFfb)
33{
34	ffb_dac_info_t *p = &pFfb->dac_info;
35
36	if (p->flags & FFB_DAC_PAC1)
37		p->wid_table.num_wids = 32;
38	else
39		p->wid_table.num_wids = 64;
40}
41
42static void
43make_wlut_regval(ffb_dac_info_t *p, ffb_wid_info_t *wid)
44{
45	wid->wlut_regval = 0;
46
47	if (p->flags & FFB_DAC_PAC1) {
48		unsigned int color_model_bits;
49
50		/* Pacifica1 format */
51		if (wid->buffer != 0)
52			wid->wlut_regval |= FFBDAC_PAC1_WLUT_DB;
53
54		if (wid->depth == 8) {
55			if (wid->greyscale) {
56				if (wid->linear)
57					color_model_bits = FFBDAC_PAC1_WLUT_C_8LG;
58				else
59					color_model_bits = FFBDAC_PAC1_WLUT_C_8NG;
60			} else {
61				color_model_bits = FFBDAC_PAC1_WLUT_C_8P;
62			}
63		} else {
64			if (wid->direct) {
65				color_model_bits = FFBDAC_PAC1_WLUT_C_24D;
66			} else {
67				if (wid->linear)
68					color_model_bits = FFBDAC_PAC1_WLUT_C_24LT;
69				else
70					color_model_bits = FFBDAC_PAC1_WLUT_C_24NT;
71			}
72		}
73
74		wid->wlut_regval |= color_model_bits;
75
76		switch (wid->channel) {
77		default:
78		case 0:
79			wid->wlut_regval |= FFBDAC_PAC1_WLUT_P_XO;
80			break;
81		case 1:
82			wid->wlut_regval |= FFBDAC_PAC1_WLUT_P_R;
83			break;
84		case 2:
85			wid->wlut_regval |= FFBDAC_PAC1_WLUT_P_G;
86			break;
87		case 3:
88			wid->wlut_regval |= FFBDAC_PAC1_WLUT_P_B;
89			break;
90		};
91	} else {
92		/* Pacifica2 format */
93		if (wid->buffer != 0)
94			wid->wlut_regval |= FFBDAC_PAC2_WLUT_DB;
95
96		if (wid->depth == 24)
97			wid->wlut_regval |= FFBDAC_PAC2_WLUT_DEPTH;
98
99		switch (wid->channel) {
100		default:
101		case 0:
102			wid->wlut_regval |= FFBDAC_PAC2_WLUT_P_XO;
103			break;
104		case 1:
105			wid->wlut_regval |= FFBDAC_PAC2_WLUT_P_R;
106			break;
107		case 2:
108			wid->wlut_regval |= FFBDAC_PAC2_WLUT_P_G;
109			break;
110		case 3:
111			wid->wlut_regval |= FFBDAC_PAC2_WLUT_P_B;
112			break;
113		};
114
115		if ((wid->depth == 8 && wid->greyscale == 0) ||
116		    (wid->depth == 24 && wid->direct != 0))
117			wid->wlut_regval |= FFBDAC_PAC2_WLUT_LKUP;
118
119		if (wid->palette != -1)
120			wid->wlut_regval |=
121				((wid->palette << 4) & FFBDAC_PAC2_WLUT_PTBL);
122	}
123}
124
125static void
126init_wid_table(FFBPtr pFfb)
127{
128	ffb_dac_info_t *p = &pFfb->dac_info;
129	ffb_wid_pool_t *table = &p->wid_table;
130	int i;
131
132	for (i = 0; i < table->num_wids; i++) {
133		table->wid_pool[i].InUse = FALSE;
134		table->wid_pool[i].buffer = 0;
135		table->wid_pool[i].depth = 24;
136		table->wid_pool[i].greyscale = 0;
137		table->wid_pool[i].linear = 0;
138		table->wid_pool[i].direct = 0;
139		table->wid_pool[i].channel = 0;
140		table->wid_pool[i].palette = -1;
141		make_wlut_regval(p, &table->wid_pool[i]);
142	}
143
144	table->wid_pool[table->num_wids - 1].InUse = TRUE;
145	table->wid_pool[table->num_wids - 1].canshare = FALSE;
146}
147
148static void
149init_hw_wids(FFBPtr pFfb)
150{
151	ffb_dac_info_t *p = &pFfb->dac_info;
152	ffb_dacPtr dac = pFfb->dac;
153	ffb_wid_pool_t *table = &p->wid_table;
154	int i;
155
156	if (p->flags & FFB_DAC_PAC1)
157		dac->cfg = FFBDAC_PAC1_APWLUT_BASE;
158	else
159		dac->cfg = FFBDAC_PAC2_APWLUT_BASE;
160	for (i = 0; i < table->num_wids; i++)
161		dac->cfgdata = table->wid_pool[i].wlut_regval;
162
163	if (p->flags & FFB_DAC_PAC1)
164		dac->cfg = FFBDAC_PAC1_SPWLUT_BASE;
165	else
166		dac->cfg = FFBDAC_PAC2_SPWLUT_BASE;
167	for (i = 0; i < table->num_wids; i++)
168		dac->cfgdata = table->wid_pool[i].wlut_regval;
169}
170
171static void
172init_hw_widmode(FFBPtr pFfb)
173{
174	ffb_dacPtr dac = pFfb->dac;
175	ffb_dac_info_t *p = &pFfb->dac_info;
176	unsigned int uctrl;
177
178	/* For now we use the Combined WID mode until I figure
179	 * out exactly how Seperate4 and Seperate8 work.  We
180	 * also disable overlays for the time being.
181	 */
182	p->wid_table.wid_shift = 0;
183
184	dac->cfg = FFBDAC_CFG_UCTRL;
185	uctrl = dac->cfgdata;
186	uctrl &= ~FFBDAC_UCTRL_WMODE;
187	uctrl |= FFBDAC_UCTRL_WM_COMB;
188	uctrl &= ~FFBDAC_UCTRL_OVENAB;
189	dac->cfg = FFBDAC_CFG_UCTRL;
190	dac->cfgdata = uctrl;
191}
192
193void
194FFBWidPoolInit(FFBPtr pFfb)
195{
196	determine_numwids(pFfb);
197	init_wid_table(pFfb);
198	init_hw_wids(pFfb);
199	init_hw_widmode(pFfb);
200}
201
202static void
203update_wids(FFBPtr pFfb, int index)
204{
205	ffb_dac_info_t *p = &pFfb->dac_info;
206	ffb_dacPtr dac = pFfb->dac;
207	unsigned int base;
208	int limit;
209
210	if (pFfb->vtSema)
211		return;
212
213	if (p->flags & FFB_DAC_PAC1)
214		base = FFBDAC_PAC1_SPWLUT(index);
215	else
216		base = FFBDAC_PAC2_SPWLUT(index);
217	DACCFG_WRITE(dac, base, p->wid_table.wid_pool[index].wlut_regval);
218
219	/* Schedule the window transfer. */
220	DACCFG_WRITE(dac, FFBDAC_CFG_WTCTRL,
221		     (FFBDAC_CFG_WTCTRL_TCMD | FFBDAC_CFG_WTCTRL_TE));
222
223	limit = 1000000;
224	while (limit--) {
225		unsigned int wtctrl = DACCFG_READ(dac, FFBDAC_CFG_WTCTRL);
226
227		if ((wtctrl & FFBDAC_CFG_WTCTRL_DS) == 0)
228			break;
229	}
230}
231
232unsigned int
233FFBWidAlloc(FFBPtr pFfb, int visclass, int cmap, Bool canshare)
234{
235	ffb_dac_info_t *p = &pFfb->dac_info;
236	ffb_wid_pool_t *table = &p->wid_table;
237	int i, depth, direct, static_greyscale, palette, channel;
238
239	direct = 0;
240	static_greyscale = 0;
241	switch (visclass) {
242	case StaticGray:
243		static_greyscale = 1;
244		/* Fallthrough... */
245	case StaticColor:
246	case GrayScale:
247	case PseudoColor:
248		depth = 8;
249		channel = 1;
250		break;
251
252	case DirectColor:
253		direct = 1;
254		/* Fallthrough... */
255	case TrueColor:
256		depth = 24;
257		channel = 0;
258		break;
259
260	default:
261		return (unsigned int) -1;
262	};
263
264	palette = -1;
265	if (p->flags & FFB_DAC_PAC1) {
266		if (visclass == PseudoColor ||
267		    visclass == GrayScale ||
268		    visclass == DirectColor)
269			palette = 0;
270	} else {
271		if (visclass == PseudoColor)
272			palette = 0;
273		if (visclass == GrayScale)
274			palette = 1;
275		if (visclass == DirectColor)
276			palette = 2;
277	}
278
279	if (canshare) {
280		for (i = 0; i < table->num_wids; i++) {
281			if (table->wid_pool[i].InUse == TRUE &&
282			    table->wid_pool[i].canshare == TRUE &&
283			    table->wid_pool[i].palette == palette &&
284			    table->wid_pool[i].direct == direct &&
285			    table->wid_pool[i].greyscale == static_greyscale &&
286			    table->wid_pool[i].channel == channel &&
287			    table->wid_pool[i].depth == depth) {
288				table->wid_pool[i].refcount++;
289				return i << table->wid_shift;
290			}
291		}
292	}
293
294	for (i = 0; i < table->num_wids; i++) {
295		if (table->wid_pool[i].InUse == FALSE)
296			break;
297	}
298
299	if (i != table->num_wids) {
300		table->wid_pool[i].InUse = TRUE;
301		table->wid_pool[i].buffer = 0;
302		table->wid_pool[i].depth = depth;
303		table->wid_pool[i].palette = palette;
304		table->wid_pool[i].direct = direct;
305		table->wid_pool[i].greyscale = static_greyscale;
306		if (depth == 8)
307			table->wid_pool[i].channel = 1;
308		else
309			table->wid_pool[i].channel = 0;
310		table->wid_pool[i].refcount = 1;
311		table->wid_pool[i].canshare = canshare;
312		make_wlut_regval(p, &table->wid_pool[i]);
313		update_wids(pFfb, i);
314		return i << table->wid_shift;
315	}
316
317	return (unsigned int) -1;
318}
319
320void
321FFBWidFree(FFBPtr pFfb, unsigned int wid)
322{
323	ffb_dac_info_t *p = &pFfb->dac_info;
324	ffb_wid_pool_t *table = &p->wid_table;
325	int index = wid >> table->wid_shift;
326
327	if (index < 0 || index >= table->num_wids) {
328		return;
329	}
330
331	if (--table->wid_pool[index].refcount == 0) {
332		table->wid_pool[index].InUse = FALSE;
333	}
334}
335
336/* Double Buffering support. */
337
338unsigned int
339FFBWidUnshare(FFBPtr pFfb, unsigned int wid)
340{
341	ffb_dac_info_t *p = &pFfb->dac_info;
342	ffb_wid_pool_t *table = &p->wid_table;
343	int index = wid >> table->wid_shift;
344	int i;
345
346	if (index < 0 || index >= table->num_wids) {
347		return (unsigned int) -1;
348	}
349
350	for (i = 0; i < table->num_wids; i++) {
351		if (table->wid_pool[i].InUse == FALSE)
352			break;
353	}
354
355	if (i == table->num_wids) {
356		return (unsigned int) -1;
357	}
358
359	table->wid_pool[i].InUse = TRUE;
360	table->wid_pool[i].buffer = 0;
361	table->wid_pool[i].depth = table->wid_pool[index].depth;
362	table->wid_pool[i].palette = table->wid_pool[index].palette;
363	table->wid_pool[i].direct = table->wid_pool[index].direct;
364	table->wid_pool[i].greyscale = table->wid_pool[index].greyscale;
365	table->wid_pool[i].channel = table->wid_pool[index].channel;
366	table->wid_pool[i].refcount = 1;
367	table->wid_pool[i].canshare = FALSE;
368	make_wlut_regval(p, &table->wid_pool[i]);
369	update_wids(pFfb, i);
370
371	/* Now free the original WID. */
372	if (--table->wid_pool[index].refcount == 0) {
373		table->wid_pool[index].InUse = FALSE;
374	}
375
376	return i << table->wid_shift;
377}
378
379unsigned int
380FFBWidReshare(FFBPtr pFfb, unsigned int wid)
381{
382	ffb_dac_info_t *p = &pFfb->dac_info;
383	ffb_wid_pool_t *table = &p->wid_table;
384	int index = wid >> table->wid_shift;
385	int i;
386
387	if (index < 0 || index >= table->num_wids) {
388		return wid;
389	}
390
391	for (i = 0; i < table->num_wids; i++) {
392		if (table->wid_pool[i].InUse == TRUE &&
393		    table->wid_pool[i].canshare == TRUE &&
394		    table->wid_pool[i].depth == table->wid_pool[index].depth &&
395		    table->wid_pool[i].palette == table->wid_pool[index].palette &&
396		    table->wid_pool[i].direct == table->wid_pool[index].direct &&
397		    table->wid_pool[i].greyscale == table->wid_pool[index].greyscale &&
398		    table->wid_pool[i].channel == table->wid_pool[index].channel)
399			break;
400	}
401
402	if (i == table->num_wids) {
403		/* OK, very simple, just make the old one shared. */
404		table->wid_pool[index].canshare = TRUE;
405		table->wid_pool[index].buffer = 0;
406		make_wlut_regval(p, &table->wid_pool[index]);
407		update_wids(pFfb, index);
408		return wid;
409	}
410
411	/* Ok, free the original WID. */
412	if (--table->wid_pool[index].refcount == 0) {
413		table->wid_pool[index].InUse = FALSE;
414	}
415
416	/* And grab a reference to the new one. */
417	table->wid_pool[i].refcount++;
418
419	/* And return the shared one. */
420	return i << table->wid_shift;
421}
422
423void
424FFBWidChangeBuffer(FFBPtr pFfb, unsigned int wid, int visible)
425{
426	ffb_dac_info_t *p = &pFfb->dac_info;
427	ffb_wid_pool_t *table = &p->wid_table;
428	int index = wid >> table->wid_shift;
429	int buffer;
430
431	if (index < 0 || index >= table->num_wids)
432		return;
433
434	buffer = (table->wid_pool[index].buffer ^= 1);
435	if (visible) {
436		unsigned int bit;
437
438		if (p->flags & FFB_DAC_PAC1)
439			bit = FFBDAC_PAC1_WLUT_DB;
440		else
441			bit = FFBDAC_PAC2_WLUT_DB;
442
443		if (buffer)
444			table->wid_pool[index].wlut_regval |= bit;
445		else
446			table->wid_pool[index].wlut_regval &= ~bit;
447
448		update_wids(pFfb, index);
449	}
450}
451