1/* 2Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. 3Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. 4Copyright (C) 2008 Mandriva Linux. All Rights Reserved. 5Copyright (C) 2008 Francisco Jerez. All Rights Reserved. 6 7Permission is hereby granted, free of charge, to any person obtaining a copy of 8this software and associated documentation files (the "Software"), to deal in 9the Software without restriction, including without limitation the rights to 10use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 11of the Software, and to permit persons to whom the Software is furnished to do 12so, subject to the following conditions: 13 14The above copyright notice and this permission notice shall be included in all 15copies or substantial portions of the Software. 16 17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- 19NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24Except as contained in this notice, the names of The XFree86 Project and 25Silicon Motion shall not be used in advertising or otherwise to promote the 26sale, use or other dealings in this Software without prior written 27authorization from The XFree86 Project or Silicon Motion. 28*/ 29 30#ifdef HAVE_CONFIG_H 31#include "config.h" 32#endif 33 34#include "smi.h" 35#include "smi_crtc.h" 36#include "smi_501.h" 37 38/* Want to see register dumps for now */ 39#undef VERBLEV 40#define VERBLEV 1 41 42/* 43 * Prototypes 44 */ 45static void SMI501_CrtcHideCursor(xf86CrtcPtr crtc); 46 47/* 48 * Implementation 49 */ 50static void 51SMI501_CrtcVideoInit_lcd(xf86CrtcPtr crtc) 52{ 53 ScrnInfoPtr pScrn=crtc->scrn; 54 SMIPtr pSmi = SMIPTR(pScrn); 55 MSOCRegPtr mode = pSmi->mode; 56 int pitch, width; 57 58 ENTER(); 59 60 if (!pSmi->HwCursor) 61 SMI501_CrtcHideCursor(crtc); 62 63 mode->panel_display_ctl.value = READ_SCR(pSmi, PANEL_DISPLAY_CTL); 64 mode->panel_fb_width.value = READ_SCR(pSmi, PANEL_FB_WIDTH); 65 66 mode->panel_display_ctl.f.format = 67 pScrn->bitsPerPixel == 8 ? 0 : 68 pScrn->bitsPerPixel == 16 ? 1 : 2; 69 70 pitch = (((crtc->rotatedData? crtc->mode.HDisplay : pScrn->displayWidth) * 71 pSmi->Bpp) + 15) & ~15; 72 width = ((crtc->mode.HDisplay * pSmi->Bpp) + 15) & ~ 15; 73 74 /* >> 4 because of the "unused bits" that should be set to 0 */ 75 mode->panel_fb_width.f.offset = pitch >> 4; 76 mode->panel_fb_width.f.width = width >> 4; 77 78 mode->panel_display_ctl.f.gamma = pSmi->Bpp > 1; 79 80 WRITE_SCR(pSmi, PANEL_DISPLAY_CTL, mode->panel_display_ctl.value); 81 WRITE_SCR(pSmi, PANEL_FB_WIDTH, mode->panel_fb_width.value); 82 83 LEAVE(); 84} 85 86static void 87SMI501_CrtcVideoInit_crt(xf86CrtcPtr crtc) 88{ 89 ScrnInfoPtr pScrn=crtc->scrn; 90 SMIPtr pSmi = SMIPTR(pScrn); 91 MSOCRegPtr mode = pSmi->mode; 92 int pitch, width; 93 94 ENTER(); 95 96 if (!pSmi->HwCursor) 97 SMI501_CrtcHideCursor(crtc); 98 99 mode->crt_display_ctl.value = READ_SCR(pSmi, CRT_DISPLAY_CTL); 100 mode->crt_fb_width.value = READ_SCR(pSmi, CRT_FB_WIDTH); 101 102 mode->crt_display_ctl.f.format = 103 pScrn->bitsPerPixel == 8 ? 0 : 104 pScrn->bitsPerPixel == 16 ? 1 : 2; 105 106 pitch = (((crtc->rotatedData? crtc->mode.HDisplay : pScrn->displayWidth) * 107 pSmi->Bpp) + 15) & ~15; 108 width = ((crtc->mode.HDisplay * pSmi->Bpp) + 15) & ~ 15; 109 110 /* >> 4 because of the "unused bits" that should be set to 0 */ 111 mode->crt_fb_width.f.offset = pitch >> 4; 112 mode->crt_fb_width.f.width = width >> 4; 113 114 mode->crt_display_ctl.f.gamma = pSmi->Bpp > 1; 115 116 WRITE_SCR(pSmi, CRT_DISPLAY_CTL, mode->crt_display_ctl.value); 117 WRITE_SCR(pSmi, CRT_FB_WIDTH, mode->crt_fb_width.value); 118 119 LEAVE(); 120} 121 122static void 123SMI501_CrtcAdjustFrame(xf86CrtcPtr crtc, int x, int y) 124{ 125 ScrnInfoPtr pScrn=crtc->scrn; 126 SMIPtr pSmi = SMIPTR(pScrn); 127 xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn); 128 MSOCRegPtr mode = pSmi->mode; 129 CARD32 Base; 130 131 ENTER(); 132 133 if(crtc->rotatedData) 134 Base = (char*)crtc->rotatedData - (char*)pSmi->FBBase; 135 else 136 Base = pSmi->FBOffset + (x + y * pScrn->displayWidth) * pSmi->Bpp; 137 138 Base = (Base + 15) & ~15; 139 140 if (crtc == crtcConf->crtc[0]) { 141 mode->panel_fb_address.f.address = Base >> 4; 142 mode->panel_fb_address.f.pending = 1; 143 WRITE_SCR(pSmi, PANEL_FB_ADDRESS, mode->panel_fb_address.value); 144 } 145 else { 146 mode->crt_display_ctl.f.pixel = ((x * pSmi->Bpp) & 15) / pSmi->Bpp; 147 WRITE_SCR(pSmi, CRT_DISPLAY_CTL, mode->crt_display_ctl.value); 148 mode->crt_fb_address.f.address = Base >> 4; 149 mode->crt_fb_address.f.mselect = 0; 150 mode->crt_fb_address.f.pending = 1; 151 WRITE_SCR(pSmi, CRT_FB_ADDRESS, mode->crt_fb_address.value); 152 } 153 154 LEAVE(); 155} 156 157static void 158SMI501_CrtcModeSet_lcd(xf86CrtcPtr crtc, 159 DisplayModePtr xf86mode, 160 DisplayModePtr adjusted_mode, 161 int x, int y) 162{ 163 ScrnInfoPtr pScrn=crtc->scrn; 164 SMIPtr pSmi = SMIPTR(pScrn); 165 MSOCRegPtr mode = pSmi->mode; 166 double p2_diff, pll_diff; 167 int32_t x2_select, x2_divider, x2_shift, x2_1xclck; 168 169 ENTER(); 170 171 /* Initialize the display controller */ 172 173 SMI501_CrtcVideoInit_lcd(crtc); 174 175 /* P2CLK have dividers 1, 3 and 5 */ 176 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, 177 "Clock request %5.2f (max_divider %d)\n", 178 (double)xf86mode->Clock, 5); 179 p2_diff = SMI501_FindClock(xf86mode->Clock, 5, 180 (uint32_t)mode->device_id.f.revision >= 0xc0, 181 &x2_1xclck, &x2_select, &x2_divider, 182 &x2_shift); 183 mode->clock.f.p2_select = x2_select; 184 mode->clock.f.p2_divider = x2_divider; 185 mode->clock.f.p2_shift = x2_shift; 186 mode->clock.f.p2_1xclck = x2_1xclck; 187 188 /* Check if it is a SMI 502 */ 189 /* FIXME May need to add a Boolean option here, (or use extra 190 * xorg.conf options?) to force it to not use 502 mode set. */ 191 if ((uint32_t)mode->device_id.f.revision >= 0xc0) { 192 int32_t m, n, xclck; 193 194 pll_diff = SMI501_FindPLLClock(xf86mode->Clock, &m, &n, &xclck); 195 if (pll_diff < p2_diff) { 196 197 /* Zero the pre 502 bitfield */ 198 mode->clock.f.p2_select = 0; 199 mode->clock.f.p2_divider = 0; 200 mode->clock.f.p2_shift = 0; 201 mode->clock.f.p2_1xclck = 0; 202 203 mode->clock.f.pll_select = 1; 204 mode->pll_ctl.f.m = m; 205 mode->pll_ctl.f.n = n; 206 207 /* 0: Crystal input 208 * 1: Test clock input */ 209 mode->pll_ctl.f.select = 0; 210 211 /* 0: pll output divided by 1 212 * 1: pll output divided by 2 */ 213 mode->pll_ctl.f.divider = xclck != 1; 214 mode->pll_ctl.f.power = 1; 215 } 216 else 217 mode->clock.f.pll_select = 0; 218 } 219 else 220 mode->clock.f.pll_select = 0; 221 222 mode->panel_display_ctl.f.enable = 1; 223 mode->panel_display_ctl.f.timing = 1; 224 225 mode->panel_wwidth.f.x = 0; 226 mode->panel_wwidth.f.width = xf86mode->HDisplay; 227 228 mode->panel_wheight.f.y = 0; 229 mode->panel_wheight.f.height = xf86mode->VDisplay; 230 231#ifdef USE_PANEL_CENTER 232 mode->panel_plane_tl.f.left = (pSmi->lcdWidth - xf86mode->HDisplay) >> 1; 233 mode->panel_plane_tl.f.top = (pSmi->lcdHeight - xf86mode->VDisplay) >> 1; 234 235 mode->panel_plane_br.f.right = mode->panel_plane_tl.f.left + 236 xf86mode->HDisplay - 1; 237 mode->panel_plane_br.f.bottom = mode->panel_plane_tl.f.top + 238 xf86mode->VDisplay - 1; 239#else 240 mode->panel_plane_tl.f.left = 0; 241 mode->panel_plane_tl.f.top = 0; 242 243 mode->panel_plane_br.f.right = xf86mode->HDisplay - 1; 244 mode->panel_plane_br.f.bottom = xf86mode->VDisplay - 1; 245#endif 246 247 /* 0 means pulse high */ 248 mode->panel_display_ctl.f.hsync = !(xf86mode->Flags & V_PHSYNC); 249 mode->panel_display_ctl.f.vsync = !(xf86mode->Flags & V_PVSYNC); 250 251 mode->panel_htotal.f.total = xf86mode->HTotal - 1; 252 mode->panel_htotal.f.end = xf86mode->HDisplay - 1; 253 254 mode->panel_hsync.f.start = xf86mode->HSyncStart - 1; 255 mode->panel_hsync.f.width = xf86mode->HSyncEnd - 256 xf86mode->HSyncStart; 257 258 mode->panel_vtotal.f.total = xf86mode->VTotal - 1; 259 mode->panel_vtotal.f.end = xf86mode->VDisplay - 1; 260 261 mode->panel_vsync.f.start = xf86mode->VSyncStart; 262 mode->panel_vsync.f.height = xf86mode->VSyncEnd - 263 xf86mode->VSyncStart; 264 265 266 SMI501_WriteMode_lcd(pScrn,mode); 267 SMI501_CrtcAdjustFrame(crtc, x, y); 268 269 LEAVE(); 270} 271 272static void 273SMI501_CrtcModeSet_crt(xf86CrtcPtr crtc, 274 DisplayModePtr xf86mode, 275 DisplayModePtr adjusted_mode, 276 int x, int y) 277{ 278 ScrnInfoPtr pScrn=crtc->scrn; 279 SMIPtr pSmi = SMIPTR(pScrn); 280 MSOCRegPtr mode = pSmi->mode; 281 int32_t x2_select, x2_divider, x2_shift, x2_1xclck; 282 283 ENTER(); 284 285 /* Initialize the display controller */ 286 287 SMI501_CrtcVideoInit_crt(crtc); 288 289 /* V2CLK have dividers 1 and 3 */ 290 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, 291 "Clock request %5.2f (max_divider %d)\n", 292 (double)xf86mode->Clock, 3); 293 (void)SMI501_FindClock(xf86mode->Clock, 3, 294 (uint32_t)mode->device_id.f.revision >= 0xc0, 295 &x2_1xclck, &x2_select, &x2_divider, &x2_shift); 296 mode->clock.f.v2_select = x2_select; 297 mode->clock.f.v2_divider = x2_divider; 298 mode->clock.f.v2_shift = x2_shift; 299 mode->clock.f.v2_1xclck = x2_1xclck; 300 301 /* 0: select panel - 1: select crt */ 302 mode->crt_display_ctl.f.select = 1; 303 mode->crt_display_ctl.f.enable = 1; 304 mode->crt_display_ctl.f.timing = 1; 305 /* 0: show pixels - 1: blank */ 306 mode->crt_display_ctl.f.blank = 0; 307 308 mode->crt_fb_address.f.mextern = 0; /* local memory */ 309 310 /* 0 means pulse high */ 311 mode->crt_display_ctl.f.hsync = !(xf86mode->Flags & V_PHSYNC); 312 mode->crt_display_ctl.f.vsync = !(xf86mode->Flags & V_PVSYNC); 313 314 mode->crt_htotal.f.total = xf86mode->HTotal - 1; 315 mode->crt_htotal.f.end = xf86mode->HDisplay - 1; 316 317 mode->crt_hsync.f.start = xf86mode->HSyncStart - 1; 318 mode->crt_hsync.f.width = xf86mode->HSyncEnd - 319 xf86mode->HSyncStart; 320 321 mode->crt_vtotal.f.total = xf86mode->VTotal - 1; 322 mode->crt_vtotal.f.end = xf86mode->VDisplay - 1; 323 324 mode->crt_vsync.f.start = xf86mode->VSyncStart; 325 mode->crt_vsync.f.height = xf86mode->VSyncEnd - 326 xf86mode->VSyncStart; 327 328 SMI501_WriteMode_crt(pScrn,mode); 329 SMI501_CrtcAdjustFrame(crtc, x, y); 330 331 LEAVE(); 332} 333 334static void 335SMI501_CrtcLoadLUT(xf86CrtcPtr crtc) 336{ 337 ScrnInfoPtr pScrn = crtc->scrn; 338 SMIPtr pSmi = SMIPTR(pScrn); 339 xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn); 340 SMICrtcPrivatePtr crtcPriv = SMICRTC(crtc); 341 int i,port; 342 343 ENTER(); 344 345 port = crtc == crtcConf->crtc[0] ? PANEL_PALETTE : CRT_PALETTE; 346 for (i = 0; i < 256; i++) 347 WRITE_SCR(pSmi, port + (i << 2), 348 (crtcPriv->lut_r[i] >> 8 << 16) | 349 (crtcPriv->lut_g[i] >> 8 << 8) | 350 (crtcPriv->lut_b[i] >> 8) ); 351 352 LEAVE(); 353} 354 355static void 356SMI501_CrtcSetCursorColors(xf86CrtcPtr crtc, int bg, int fg) 357{ 358 ScrnInfoPtr pScrn = crtc->scrn; 359 SMIPtr pSmi = SMIPTR(pScrn); 360 xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn); 361 int32_t port, value; 362 363 ENTER(); 364 365 /* for the SMI501 HWCursor, there are 4 possible colors, one of which 366 * is transparent: M,S: 0,0 = Transparent 367 * 0,1 = color 1 368 * 1,0 = color 2 369 * 1,1 = color 3 370 * To simplify implementation, we use color2 == bg and 371 * color3 == fg 372 * Color 1 is don't care, so we set it to color 2's value 373 */ 374 375 /* Pack the true color components into 16 bit RGB -- 5:6:5 */ 376 value = ((bg & 0xF80000) >> 8 | 377 (bg & 0x00FC00) >> 5 | 378 (bg & 0x0000F8) >> 3); 379 380 value |= ((bg & 0xF80000) << 8 | 381 (bg & 0x00FC00) << 11 | 382 (bg & 0x0000F8) << 13); 383 port = crtc == crtcConf->crtc[0] ? 0x00f8 : 0x0238; 384 WRITE_DCR(pSmi, port, value); 385 386 value = ((fg & 0xF80000) >> 8 | 387 (fg & 0x00FC00) >> 5 | 388 (fg & 0x0000F8) >> 3); 389 port = crtc == crtcConf->crtc[0] ? 0x00fc : 0x023c; 390 WRITE_DCR(pSmi, port, value); 391 392 LEAVE(); 393} 394 395static void 396SMI501_CrtcSetCursorPosition(xf86CrtcPtr crtc, int x, int y) 397{ 398 ScrnInfoPtr pScrn = crtc->scrn; 399 SMIPtr pSmi = SMIPTR(pScrn); 400 xf86CrtcConfigPtr crtcConf; 401#if SMI_CURSOR_ALPHA_PLANE 402 SMICrtcPrivatePtr smi_crtc = SMICRTC(crtc); 403 MSOCRegPtr mode; 404#endif 405 int32_t port, offset; 406 407 ENTER(); 408 409#if SMI_CURSOR_ALPHA_PLANE 410 if (smi_crtc->argb_cursor) { 411 mode = pSmi->mode; 412 413 /* uncomment next line if you want to see it rendering the cursor */ 414 /* x = y = 0; */ 415 416 mode->alpha_plane_tl.f.left = x; 417 mode->alpha_plane_tl.f.top = y; 418 419 mode->alpha_plane_br.f.right = x + SMI501_CURSOR_SIZE - 1; 420 mode->alpha_plane_br.f.bottom = y + SMI501_CURSOR_SIZE - 1; 421 422 WRITE_SCR(pSmi, ALPHA_PLANE_TL, mode->alpha_plane_tl.value); 423 WRITE_SCR(pSmi, ALPHA_PLANE_BR, mode->alpha_plane_br.value); 424 } 425 else 426#endif 427 { 428 crtcConf = XF86_CRTC_CONFIG_PTR(pScrn); 429 430 if (x >= 0) 431 offset = x & SMI501_MASK_MAXBITS; 432 else 433 offset = (-x & SMI501_MASK_MAXBITS) | SMI501_MASK_BOUNDARY; 434 435 if (y >= 0) 436 offset |= (y & SMI501_MASK_MAXBITS) << 16; 437 else 438 offset |= ((-y & SMI501_MASK_MAXBITS) | SMI501_MASK_BOUNDARY) << 16; 439 440 port = crtc == crtcConf->crtc[0] ? 0x00f4 : 0x0234; 441 WRITE_DCR(pSmi, port, offset); 442 } 443 444 LEAVE(); 445} 446 447static void 448SMI501_CrtcShowCursor(xf86CrtcPtr crtc) 449{ 450 ScrnInfoPtr pScrn = crtc->scrn; 451 SMIPtr pSmi = SMIPTR(pScrn); 452 xf86CrtcConfigPtr crtcConf; 453#if SMI_CURSOR_ALPHA_PLANE 454 SMICrtcPrivatePtr smi_crtc = SMICRTC(crtc); 455 MSOCRegPtr mode; 456#endif 457 int32_t port, value; 458 459 ENTER(); 460 461#if SMI_CURSOR_ALPHA_PLANE 462 if (smi_crtc->argb_cursor) { 463 mode = pSmi->mode; 464 465 mode->alpha_display_ctl.f.enable = 1; 466 WRITE_SCR(pSmi, ALPHA_DISPLAY_CTL, mode->alpha_display_ctl.value); 467 } 468 else 469#endif 470 { 471 crtcConf = XF86_CRTC_CONFIG_PTR(pScrn); 472 473 port = crtc == crtcConf->crtc[0] ? 0x00f0 : 0x0230; 474 value = READ_DCR(pSmi, port); 475 value |= SMI501_MASK_HWCENABLE; 476 WRITE_DCR(pSmi, port, value); 477 } 478 479 LEAVE(); 480} 481 482static void 483SMI501_CrtcHideCursor(xf86CrtcPtr crtc) 484{ 485 ScrnInfoPtr pScrn = crtc->scrn; 486 SMIPtr pSmi = SMIPTR(pScrn); 487 xf86CrtcConfigPtr crtcConf; 488#if SMI_CURSOR_ALPHA_PLANE 489 SMICrtcPrivatePtr smi_crtc = SMICRTC(crtc); 490 MSOCRegPtr mode; 491#endif 492 int32_t port, value; 493 494 ENTER(); 495 496#if SMI_CURSOR_ALPHA_PLANE 497 if (smi_crtc->argb_cursor) { 498 mode = pSmi->mode; 499 500 mode->alpha_display_ctl.f.enable = 0; 501 WRITE_SCR(pSmi, ALPHA_DISPLAY_CTL, mode->alpha_display_ctl.value); 502 } 503 else 504#endif 505 { 506 crtcConf = XF86_CRTC_CONFIG_PTR(pScrn); 507 508 port = crtc == crtcConf->crtc[0] ? 0x00f0 : 0x0230; 509 value = READ_DCR(pSmi, port); 510 value &= ~SMI501_MASK_HWCENABLE; 511 WRITE_DCR(pSmi, port, value); 512 } 513 514 LEAVE(); 515} 516 517static void 518SMI501_CrtcLoadCursorImage(xf86CrtcPtr crtc, CARD8 *image) 519{ 520 ScrnInfoPtr pScrn = crtc->scrn; 521 SMIPtr pSmi = SMIPTR(pScrn); 522#if SMI_CURSOR_ALPHA_PLANE 523 SMICrtcPrivatePtr smi_crtc = SMICRTC(crtc); 524#endif 525 xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn); 526 int32_t port, value; 527 528 ENTER(); 529 530 port = crtc == crtcConf->crtc[0] ? 0x00f0 : 0x0230; 531 value = pSmi->FBCursorOffset + (port == 0x00f0 ? 0 : SMI501_CURSOR_SIZE); 532 WRITE_DCR(pSmi, port, value); 533 memcpy(pSmi->FBBase + value, image, 534 /* FIXME 1024, but then, should not be using 64x64 cursors */ 535 (SMI501_MAX_CURSOR >> 2) * SMI501_MAX_CURSOR); 536#if SMI_CURSOR_ALPHA_PLANE 537 smi_crtc->argb_cursor = FALSE; 538#endif 539 540 LEAVE(); 541} 542 543#if SMI_CURSOR_ALPHA_PLANE 544static void 545SMI501_CrtcLoadCursorArgb(xf86CrtcPtr crtc, CARD32 *image) 546{ 547 ScrnInfoPtr pScrn = crtc->scrn; 548 SMIPtr pSmi = SMIPTR(pScrn); 549 SMICrtcPrivatePtr smi_crtc = SMICRTC(crtc); 550 MSOCRegPtr mode = pSmi->mode; 551 int16_t *framebuffer; 552 int32_t x, y, bits; 553 int32_t format; 554 555 ENTER(); 556 557#define ALPHA_RGB_565 1 558#define ALPHA_ARGB_4444 3 559 560 /* select alpha format */ 561 mode->alpha_display_ctl.f.format = ALPHA_ARGB_4444; 562 563 /* 0: use per pixel alpha value 1: use alpha value specified in alpha */ 564 if (mode->alpha_display_ctl.f.format == ALPHA_RGB_565) { 565 mode->alpha_display_ctl.f.select = 1; 566 /* 0 to 15, with 0 being transparent and 15 opaque */ 567 mode->alpha_display_ctl.f.alpha = 7; 568 } 569 else { 570 /* use per pixel alpha */ 571 mode->alpha_display_ctl.f.select = 0; 572 } 573 574 /* alpha layer buffer */ 575 mode->alpha_fb_address.value = 0; 576 mode->alpha_fb_address.f.address = pSmi->FBCursorOffset >> 4; 577 578 /* more clearly: width = (SMI501_MAX_CURSOR << 1) >> 4 579 * as the structure is matching the register spec, where it says 580 * the first 4 bits are hardwired to zero */ 581 mode->alpha_fb_width.f.offset = SMI501_MAX_CURSOR >> 3; 582 mode->alpha_fb_width.f.width = SMI501_MAX_CURSOR >> 3; 583 584 mode->alpha_chroma_key.f.value = 0; 585 mode->alpha_chroma_key.f.mask = 0; 586 /* enable chroma key */ 587 mode->alpha_display_ctl.f.chromakey = 1; 588 589 framebuffer = (int16_t *)(pSmi->FBBase + pSmi->FBCursorOffset); 590 if (mode->alpha_display_ctl.f.format == ALPHA_RGB_565) { 591 /* convert image to rgb 5:6:5 */ 592 for (y = 0; y < SMI501_MAX_CURSOR; y++) { 593 for (x = 0; x < SMI501_MAX_CURSOR; x++) { 594 bits = image[y * SMI501_MAX_CURSOR + x]; 595 framebuffer[y * SMI501_MAX_CURSOR + x] = 596 (((bits & 0xf80000) >> 8) | 597 ((bits & 0x00fc00) >> 5) | 598 ((bits & 0x0000f8) >> 3)); 599 } 600 } 601 } 602 else { 603 /* convert image to argb 4:4:4:4 */ 604 for (y = 0; y < SMI501_MAX_CURSOR; y++) { 605 for (x = 0; x < SMI501_MAX_CURSOR; x++) { 606 bits = image[y * SMI501_MAX_CURSOR + x]; 607 framebuffer[y * SMI501_MAX_CURSOR + x] = 608 (((bits & 0xf0000000) >> 16) | 609 ((bits & 0x00f00000) >> 12) | 610 ((bits & 0x0000f000) >> 8) | 611 ((bits & 0x000000f0) >> 4)); 612 } 613 } 614 } 615 SMI501_WriteMode_alpha(pScrn, mode); 616 smi_crtc->argb_cursor = TRUE; 617 618 LEAVE(); 619 } 620#endif 621 622Bool 623SMI501_CrtcPreInit(ScrnInfoPtr pScrn) 624{ 625 SMIPtr pSmi = SMIPTR(pScrn); 626 xf86CrtcPtr crtc; 627 xf86CrtcFuncsPtr crtcFuncs; 628 SMICrtcPrivatePtr crtcPriv; 629 630 ENTER(); 631 632 /* CRTC0 is LCD */ 633 SMI_CrtcFuncsInit_base(&crtcFuncs, &crtcPriv); 634 crtcFuncs->mode_set = SMI501_CrtcModeSet_lcd; 635 crtcPriv->adjust_frame = SMI501_CrtcAdjustFrame; 636 crtcPriv->video_init = SMI501_CrtcVideoInit_lcd; 637 crtcPriv->load_lut = SMI501_CrtcLoadLUT; 638 639 if (pSmi->HwCursor) { 640 crtcFuncs->set_cursor_colors = SMI501_CrtcSetCursorColors; 641 crtcFuncs->set_cursor_position = SMI501_CrtcSetCursorPosition; 642 crtcFuncs->show_cursor = SMI501_CrtcShowCursor; 643 crtcFuncs->hide_cursor = SMI501_CrtcHideCursor; 644 crtcFuncs->load_cursor_image = SMI501_CrtcLoadCursorImage; 645#if SMI_CURSOR_ALPHA_PLANE 646 if (!pSmi->Dualhead) 647 crtcFuncs->load_cursor_argb = SMI501_CrtcLoadCursorArgb; 648#endif 649 } 650 651 if (! (crtc = xf86CrtcCreate(pScrn, crtcFuncs))) 652 LEAVE(FALSE); 653 crtc->driver_private = crtcPriv; 654 655 /* CRTC1 is CRT */ 656 if (pSmi->Dualhead) { 657 SMI_CrtcFuncsInit_base(&crtcFuncs, &crtcPriv); 658 crtcFuncs->mode_set = SMI501_CrtcModeSet_crt; 659 crtcPriv->adjust_frame = SMI501_CrtcAdjustFrame; 660 crtcPriv->video_init = SMI501_CrtcVideoInit_crt; 661 crtcPriv->load_lut = SMI501_CrtcLoadLUT; 662 663 if (pSmi->HwCursor) { 664 crtcFuncs->set_cursor_colors = SMI501_CrtcSetCursorColors; 665 crtcFuncs->set_cursor_position = SMI501_CrtcSetCursorPosition; 666 crtcFuncs->show_cursor = SMI501_CrtcShowCursor; 667 crtcFuncs->hide_cursor = SMI501_CrtcHideCursor; 668 crtcFuncs->load_cursor_image = SMI501_CrtcLoadCursorImage; 669 } 670 671 if (! (crtc = xf86CrtcCreate(pScrn, crtcFuncs))) 672 LEAVE(FALSE); 673 crtc->driver_private = crtcPriv; 674 } 675 676 LEAVE(TRUE); 677} 678 679