/* * 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); } }