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