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