Edit

IABSD.fr/xenocara/driver/xf86-video-sunffb/src/ffb_wid.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2013-06-01 19:20:43
    Hash : 6858fca6
    Message : Update to xf86-video-sunffb 1.2.2

  • driver/xf86-video-sunffb/src/ffb_wid.c
  • /*
     * Acceleration for the Creator and Creator3D framebuffer - WID pool management.
     *
     * Copyright (C) 2000 David S. Miller (davem@redhat.com)
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     * DAVID MILLER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
     * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     *
     */
    
    #ifdef HAVE_CONFIG_H
    #include "config.h"
    #endif
    
    #include "ffb.h"
    
    static void
    determine_numwids(FFBPtr pFfb)
    {
    	ffb_dac_info_t *p = &pFfb->dac_info;
    
    	if (p->flags & FFB_DAC_PAC1)
    		p->wid_table.num_wids = 32;
    	else
    		p->wid_table.num_wids = 64;
    }
    
    static void
    make_wlut_regval(ffb_dac_info_t *p, ffb_wid_info_t *wid)
    {
    	wid->wlut_regval = 0;
    
    	if (p->flags & FFB_DAC_PAC1) {
    		unsigned int color_model_bits;
    
    		/* Pacifica1 format */
    		if (wid->buffer != 0)
    			wid->wlut_regval |= FFBDAC_PAC1_WLUT_DB;
    
    		if (wid->depth == 8) {
    			if (wid->greyscale) {
    				if (wid->linear)
    					color_model_bits = FFBDAC_PAC1_WLUT_C_8LG;
    				else
    					color_model_bits = FFBDAC_PAC1_WLUT_C_8NG;
    			} else {
    				color_model_bits = FFBDAC_PAC1_WLUT_C_8P;
    			}
    		} else {
    			if (wid->direct) {
    				color_model_bits = FFBDAC_PAC1_WLUT_C_24D;
    			} else {
    				if (wid->linear)
    					color_model_bits = FFBDAC_PAC1_WLUT_C_24LT;
    				else
    					color_model_bits = FFBDAC_PAC1_WLUT_C_24NT;
    			}
    		}
    
    		wid->wlut_regval |= color_model_bits;
    
    		switch (wid->channel) {
    		default:
    		case 0:
    			wid->wlut_regval |= FFBDAC_PAC1_WLUT_P_XO;
    			break;
    		case 1:
    			wid->wlut_regval |= FFBDAC_PAC1_WLUT_P_R;
    			break;
    		case 2:
    			wid->wlut_regval |= FFBDAC_PAC1_WLUT_P_G;
    			break;
    		case 3:
    			wid->wlut_regval |= FFBDAC_PAC1_WLUT_P_B;
    			break;
    		};
    	} else {
    		/* Pacifica2 format */
    		if (wid->buffer != 0)
    			wid->wlut_regval |= FFBDAC_PAC2_WLUT_DB;
    
    		if (wid->depth == 24)
    			wid->wlut_regval |= FFBDAC_PAC2_WLUT_DEPTH;
    
    		switch (wid->channel) {
    		default:
    		case 0:
    			wid->wlut_regval |= FFBDAC_PAC2_WLUT_P_XO;
    			break;
    		case 1:
    			wid->wlut_regval |= FFBDAC_PAC2_WLUT_P_R;
    			break;
    		case 2:
    			wid->wlut_regval |= FFBDAC_PAC2_WLUT_P_G;
    			break;
    		case 3:
    			wid->wlut_regval |= FFBDAC_PAC2_WLUT_P_B;
    			break;
    		};
    
    		if ((wid->depth == 8 && wid->greyscale == 0) ||
    		    (wid->depth == 24 && wid->direct != 0))
    			wid->wlut_regval |= FFBDAC_PAC2_WLUT_LKUP;
    
    		if (wid->palette != -1)
    			wid->wlut_regval |=
    				((wid->palette << 4) & FFBDAC_PAC2_WLUT_PTBL);
    	}
    }
    
    static void
    init_wid_table(FFBPtr pFfb)
    {
    	ffb_dac_info_t *p = &pFfb->dac_info;
    	ffb_wid_pool_t *table = &p->wid_table;
    	int i;
    
    	for (i = 0; i < table->num_wids; i++) {
    		table->wid_pool[i].InUse = FALSE;
    		table->wid_pool[i].buffer = 0;
    		table->wid_pool[i].depth = 24;
    		table->wid_pool[i].greyscale = 0;
    		table->wid_pool[i].linear = 0;
    		table->wid_pool[i].direct = 0;
    		table->wid_pool[i].channel = 0;
    		table->wid_pool[i].palette = -1;
    		make_wlut_regval(p, &table->wid_pool[i]);
    	}
    
    	table->wid_pool[table->num_wids - 1].InUse = TRUE;
    	table->wid_pool[table->num_wids - 1].canshare = FALSE;
    }
    
    static void
    init_hw_wids(FFBPtr pFfb)
    {
    	ffb_dac_info_t *p = &pFfb->dac_info;
    	ffb_dacPtr dac = pFfb->dac;
    	ffb_wid_pool_t *table = &p->wid_table;
    	int i;
    
    	if (p->flags & FFB_DAC_PAC1)
    		dac->cfg = FFBDAC_PAC1_APWLUT_BASE;
    	else
    		dac->cfg = FFBDAC_PAC2_APWLUT_BASE;
    	for (i = 0; i < table->num_wids; i++)
    		dac->cfgdata = table->wid_pool[i].wlut_regval;
    
    	if (p->flags & FFB_DAC_PAC1)
    		dac->cfg = FFBDAC_PAC1_SPWLUT_BASE;
    	else
    		dac->cfg = FFBDAC_PAC2_SPWLUT_BASE;
    	for (i = 0; i < table->num_wids; i++)
    		dac->cfgdata = table->wid_pool[i].wlut_regval;
    }
    
    static void
    init_hw_widmode(FFBPtr pFfb)
    {
    	ffb_dacPtr dac = pFfb->dac;
    	ffb_dac_info_t *p = &pFfb->dac_info;
    	unsigned int uctrl;
    
    	/* For now we use the Combined WID mode until I figure
    	 * out exactly how Seperate4 and Seperate8 work.  We
    	 * also disable overlays for the time being.
    	 */
    	p->wid_table.wid_shift = 0;
    
    	dac->cfg = FFBDAC_CFG_UCTRL;
    	uctrl = dac->cfgdata;
    	uctrl &= ~FFBDAC_UCTRL_WMODE;
    	uctrl |= FFBDAC_UCTRL_WM_COMB;
    	uctrl &= ~FFBDAC_UCTRL_OVENAB;
    	dac->cfg = FFBDAC_CFG_UCTRL;
    	dac->cfgdata = uctrl;
    }
    
    void
    FFBWidPoolInit(FFBPtr pFfb)
    {
    	determine_numwids(pFfb);
    	init_wid_table(pFfb);
    	init_hw_wids(pFfb);
    	init_hw_widmode(pFfb);
    }
    
    static void
    update_wids(FFBPtr pFfb, int index)
    {
    	ffb_dac_info_t *p = &pFfb->dac_info;
    	ffb_dacPtr dac = pFfb->dac;
    	unsigned int base;
    	int limit;
    
    	if (pFfb->vtSema)
    		return;
    
    	if (p->flags & FFB_DAC_PAC1)
    		base = FFBDAC_PAC1_SPWLUT(index);
    	else
    		base = FFBDAC_PAC2_SPWLUT(index);
    	DACCFG_WRITE(dac, base, p->wid_table.wid_pool[index].wlut_regval);
    
    	/* Schedule the window transfer. */
    	DACCFG_WRITE(dac, FFBDAC_CFG_WTCTRL, 
    		     (FFBDAC_CFG_WTCTRL_TCMD | FFBDAC_CFG_WTCTRL_TE));
    
    	limit = 1000000;
    	while (limit--) {
    		unsigned int wtctrl = DACCFG_READ(dac, FFBDAC_CFG_WTCTRL);
    
    		if ((wtctrl & FFBDAC_CFG_WTCTRL_DS) == 0)
    			break;
    	}
    }
    
    unsigned int
    FFBWidAlloc(FFBPtr pFfb, int visclass, int cmap, Bool canshare)
    {
    	ffb_dac_info_t *p = &pFfb->dac_info;
    	ffb_wid_pool_t *table = &p->wid_table;
    	int i, depth, direct, static_greyscale, palette, channel;
    
    	direct = 0;
    	static_greyscale = 0;
    	switch (visclass) {
    	case StaticGray:
    		static_greyscale = 1;
    		/* Fallthrough... */
    	case StaticColor:
    	case GrayScale:
    	case PseudoColor:
    		depth = 8;
    		channel = 1;
    		break;
    
    	case DirectColor:
    		direct = 1;
    		/* Fallthrough... */
    	case TrueColor:
    		depth = 24;
    		channel = 0;
    		break;
    
    	default:
    		return (unsigned int) -1;
    	};
    
    	palette = -1;
    	if (p->flags & FFB_DAC_PAC1) {
    		if (visclass == PseudoColor ||
    		    visclass == GrayScale ||
    		    visclass == DirectColor)
    			palette = 0;
    	} else {
    		if (visclass == PseudoColor)
    			palette = 0;
    		if (visclass == GrayScale)
    			palette = 1;
    		if (visclass == DirectColor)
    			palette = 2;
    	}
    
    	if (canshare) {
    		for (i = 0; i < table->num_wids; i++) {
    			if (table->wid_pool[i].InUse == TRUE &&
    			    table->wid_pool[i].canshare == TRUE &&
    			    table->wid_pool[i].palette == palette &&
    			    table->wid_pool[i].direct == direct &&
    			    table->wid_pool[i].greyscale == static_greyscale &&
    			    table->wid_pool[i].channel == channel &&
    			    table->wid_pool[i].depth == depth) {
    				table->wid_pool[i].refcount++;
    				return i << table->wid_shift;
    			}
    		}
    	}
    
    	for (i = 0; i < table->num_wids; i++) {
    		if (table->wid_pool[i].InUse == FALSE)
    			break;
    	}
    
    	if (i != table->num_wids) {
    		table->wid_pool[i].InUse = TRUE;
    		table->wid_pool[i].buffer = 0;
    		table->wid_pool[i].depth = depth;
    		table->wid_pool[i].palette = palette;
    		table->wid_pool[i].direct = direct;
    		table->wid_pool[i].greyscale = static_greyscale;
    		if (depth == 8)
    			table->wid_pool[i].channel = 1;
    		else
    			table->wid_pool[i].channel = 0;
    		table->wid_pool[i].refcount = 1;
    		table->wid_pool[i].canshare = canshare;
    		make_wlut_regval(p, &table->wid_pool[i]);
    		update_wids(pFfb, i);
    		return i << table->wid_shift;
    	}
    
    	return (unsigned int) -1;
    }
    
    void
    FFBWidFree(FFBPtr pFfb, unsigned int wid)
    {
    	ffb_dac_info_t *p = &pFfb->dac_info;
    	ffb_wid_pool_t *table = &p->wid_table;
    	int index = wid >> table->wid_shift;
    
    	if (index < 0 || index >= table->num_wids) {
    		return;
    	}
    
    	if (--table->wid_pool[index].refcount == 0) {
    		table->wid_pool[index].InUse = FALSE;
    	}
    }
    
    /* Double Buffering support. */
    
    unsigned int
    FFBWidUnshare(FFBPtr pFfb, unsigned int wid)
    {
    	ffb_dac_info_t *p = &pFfb->dac_info;
    	ffb_wid_pool_t *table = &p->wid_table;
    	int index = wid >> table->wid_shift;
    	int i;
    
    	if (index < 0 || index >= table->num_wids) {
    		return (unsigned int) -1;
    	}
    
    	for (i = 0; i < table->num_wids; i++) {
    		if (table->wid_pool[i].InUse == FALSE)
    			break;
    	}
    
    	if (i == table->num_wids) {
    		return (unsigned int) -1;
    	}
    
    	table->wid_pool[i].InUse = TRUE;
    	table->wid_pool[i].buffer = 0;
    	table->wid_pool[i].depth = table->wid_pool[index].depth;
    	table->wid_pool[i].palette = table->wid_pool[index].palette;
    	table->wid_pool[i].direct = table->wid_pool[index].direct;
    	table->wid_pool[i].greyscale = table->wid_pool[index].greyscale;
    	table->wid_pool[i].channel = table->wid_pool[index].channel;
    	table->wid_pool[i].refcount = 1;
    	table->wid_pool[i].canshare = FALSE;
    	make_wlut_regval(p, &table->wid_pool[i]);
    	update_wids(pFfb, i);
    
    	/* Now free the original WID. */
    	if (--table->wid_pool[index].refcount == 0) {
    		table->wid_pool[index].InUse = FALSE;
    	}
    
    	return i << table->wid_shift;
    }
    
    unsigned int
    FFBWidReshare(FFBPtr pFfb, unsigned int wid)
    {
    	ffb_dac_info_t *p = &pFfb->dac_info;
    	ffb_wid_pool_t *table = &p->wid_table;
    	int index = wid >> table->wid_shift;
    	int i;
    
    	if (index < 0 || index >= table->num_wids) {
    		return wid;
    	}
    
    	for (i = 0; i < table->num_wids; i++) {
    		if (table->wid_pool[i].InUse == TRUE &&
    		    table->wid_pool[i].canshare == TRUE &&
    		    table->wid_pool[i].depth == table->wid_pool[index].depth &&
    		    table->wid_pool[i].palette == table->wid_pool[index].palette &&
    		    table->wid_pool[i].direct == table->wid_pool[index].direct &&
    		    table->wid_pool[i].greyscale == table->wid_pool[index].greyscale &&
    		    table->wid_pool[i].channel == table->wid_pool[index].channel)
    			break;
    	}
    
    	if (i == table->num_wids) {
    		/* OK, very simple, just make the old one shared. */
    		table->wid_pool[index].canshare = TRUE;
    		table->wid_pool[index].buffer = 0;
    		make_wlut_regval(p, &table->wid_pool[index]);
    		update_wids(pFfb, index);
    		return wid;
    	}
    
    	/* Ok, free the original WID. */
    	if (--table->wid_pool[index].refcount == 0) {
    		table->wid_pool[index].InUse = FALSE;
    	}
    
    	/* And grab a reference to the new one. */
    	table->wid_pool[i].refcount++;
    
    	/* And return the shared one. */
    	return i << table->wid_shift;
    }
    
    void
    FFBWidChangeBuffer(FFBPtr pFfb, unsigned int wid, int visible)
    {
    	ffb_dac_info_t *p = &pFfb->dac_info;
    	ffb_wid_pool_t *table = &p->wid_table;
    	int index = wid >> table->wid_shift;
    	int buffer;
    
    	if (index < 0 || index >= table->num_wids)
    		return;
    
    	buffer = (table->wid_pool[index].buffer ^= 1);
    	if (visible) {
    		unsigned int bit;
    
    		if (p->flags & FFB_DAC_PAC1)
    			bit = FFBDAC_PAC1_WLUT_DB;
    		else
    			bit = FFBDAC_PAC2_WLUT_DB;
    
    		if (buffer)
    			table->wid_pool[index].wlut_regval |= bit;
    		else
    			table->wid_pool[index].wlut_regval &= ~bit;
    
    		update_wids(pFfb, index);
    	}
    }