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