Home | History | Annotate | Line # | Download | only in src
      1 /* Copyright (c) 2008 Advanced Micro Devices, Inc.
      2  *
      3  * Permission is hereby granted, free of charge, to any person obtaining a copy
      4  * of this software and associated documentation files (the "Software"), to
      5  * deal in the Software without restriction, including without limitation the
      6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      7  * sell copies of the Software, and to permit persons to whom the Software is
      8  * furnished to do so, subject to the following conditions:
      9  *
     10  * The above copyright notice and this permission notice shall be included in
     11  * all copies or substantial portions of the Software.
     12  *
     13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     19  * IN THE SOFTWARE.
     20  *
     21  * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
     22  * contributors may be used to endorse or promote products derived from this
     23  * software without specific prior written permission.
     24  */
     25 
     26 #ifdef HAVE_CONFIG_H
     27 #include "config.h"
     28 #endif
     29 
     30 #include "xorg-server.h"
     31 
     32 #include "xf86.h"
     33 #include "geode.h"
     34 #include "xf86Crtc.h"
     35 #include "cim/cim_defs.h"
     36 #include "cim/cim_regs.h"
     37 
     38 typedef struct _LXOutputPrivateRec {
     39     int video_enable;
     40     unsigned long video_flags;
     41     GeodeMemPtr rotate_mem;
     42 } LXCrtcPrivateRec, *LXCrtcPrivatePtr;
     43 
     44 void
     45 lx_enable_dac_power(ScrnInfoPtr pScrni, int option)
     46 {
     47     GeodeRec *pGeode = GEODEPTR(pScrni);
     48 
     49     df_set_crt_enable(DF_CRT_ENABLE);
     50 
     51     /* Turn off the DAC if we don't need the CRT */
     52 
     53     if (option && (!(pGeode->Output & OUTPUT_CRT))) {
     54         unsigned int misc = READ_VID32(DF_VID_MISC);
     55 
     56         misc |= DF_DAC_POWER_DOWN;
     57         WRITE_VID32(DF_VID_MISC, misc);
     58     }
     59 
     60     if (pGeode->Output & OUTPUT_PANEL)
     61         df_set_panel_enable(1);
     62 }
     63 
     64 void
     65 lx_disable_dac_power(ScrnInfoPtr pScrni, int option)
     66 {
     67     GeodeRec *pGeode = GEODEPTR(pScrni);
     68 
     69     if (pGeode->Output & OUTPUT_PANEL)
     70         df_set_panel_enable(0);
     71 
     72     if (pGeode->Output & OUTPUT_CRT) {
     73 
     74         /* Wait for the panel to finish its procedure */
     75 
     76         if (pGeode->Output & OUTPUT_PANEL)
     77             while ((READ_VID32(DF_POWER_MANAGEMENT) & 2) == 0);
     78         df_set_crt_enable(option);
     79     }
     80 }
     81 
     82 static void
     83 lx_set_panel_mode(VG_DISPLAY_MODE * mode, DisplayModePtr pMode)
     84 {
     85     int hsync, vsync;
     86 
     87     mode->mode_width = mode->panel_width = pMode->HDisplay;
     88     mode->mode_height = mode->panel_height = pMode->VDisplay;
     89 
     90     mode->hactive = pMode->HDisplay;
     91     mode->hblankstart = pMode->HDisplay;
     92     mode->hsyncstart = pMode->HSyncStart;
     93     mode->hsyncend = pMode->HSyncEnd;
     94     mode->hblankend = pMode->HTotal;
     95     mode->htotal = pMode->HTotal;
     96 
     97     mode->vactive = pMode->VDisplay;
     98     mode->vblankstart = pMode->VDisplay;
     99     mode->vsyncstart = pMode->VSyncStart;
    100     mode->vsyncend = pMode->VSyncEnd;
    101     mode->vblankend = pMode->VTotal;
    102     mode->vtotal = pMode->VTotal;
    103 
    104     mode->vactive_even = pMode->VDisplay;
    105     mode->vblankstart_even = pMode->VDisplay;
    106     mode->vsyncstart_even = pMode->VSyncStart;
    107     mode->vsyncend_even = pMode->VSyncEnd;
    108     mode->vblankend_even = pMode->VTotal;
    109     mode->vtotal_even = pMode->VTotal;
    110 
    111     mode->frequency = (int) ((pMode->Clock / 1000.0) * 0x10000);
    112 
    113     /* In panel mode, Cimarron purposely swizzles these,
    114      * so we swizzle them first  */
    115 
    116     hsync = (pMode->Flags & V_NHSYNC) ? 0 : 1;
    117     vsync = (pMode->Flags & V_NVSYNC) ? 0 : 1;
    118 
    119     mode->flags |= (hsync) ? VG_MODEFLAG_NEG_HSYNC : 0;
    120     mode->flags |= (vsync) ? VG_MODEFLAG_NEG_VSYNC : 0;
    121 }
    122 
    123 static void
    124 lx_set_crt_mode(VG_DISPLAY_MODE * mode, DisplayModePtr pMode)
    125 {
    126     int hsync, vsync;
    127 
    128     mode->mode_width = mode->panel_width = pMode->HDisplay;
    129     mode->mode_height = mode->panel_height = pMode->VDisplay;
    130 
    131     mode->hactive = pMode->CrtcHDisplay;
    132     mode->hblankstart = pMode->CrtcHBlankStart;
    133     mode->hsyncstart = pMode->CrtcHSyncStart;
    134     mode->hsyncend = pMode->CrtcHSyncEnd;
    135     mode->hblankend = pMode->CrtcHBlankEnd;
    136     mode->htotal = pMode->CrtcHTotal;
    137 
    138     mode->vactive = pMode->CrtcVDisplay;
    139     mode->vblankstart = pMode->CrtcVBlankStart;
    140     mode->vsyncstart = pMode->CrtcVSyncStart;
    141     mode->vsyncend = pMode->CrtcVSyncEnd;
    142     mode->vblankend = pMode->CrtcVBlankEnd;
    143     mode->vtotal = pMode->CrtcVTotal;
    144 
    145     mode->vactive_even = pMode->CrtcVDisplay;
    146     mode->vblankstart_even = pMode->CrtcVBlankStart;
    147     mode->vsyncstart_even = pMode->CrtcVSyncStart;
    148     mode->vsyncend_even = pMode->CrtcVSyncEnd;
    149     mode->vblankend_even = pMode->CrtcVBlankEnd;
    150     mode->vtotal_even = pMode->CrtcVTotal;
    151 
    152     mode->frequency = (int) ((pMode->Clock / 1000.0) * 0x10000);
    153 
    154     hsync = (pMode->Flags & V_NHSYNC) ? 1 : 0;
    155     vsync = (pMode->Flags & V_NVSYNC) ? 1 : 0;
    156 
    157     mode->flags |= (hsync) ? VG_MODEFLAG_NEG_HSYNC : 0;
    158     mode->flags |= (vsync) ? VG_MODEFLAG_NEG_VSYNC : 0;
    159 }
    160 
    161 static int
    162 lx_set_mode(ScrnInfoPtr pScrni, DisplayModePtr pMode, int bpp)
    163 {
    164     GeodeRec *pGeode = GEODEPTR(pScrni);
    165     VG_DISPLAY_MODE mode;
    166     int ret;
    167 
    168     memset(&mode, 0, sizeof(mode));
    169 
    170     mode.flags |= pGeode->Output & OUTPUT_CRT ? VG_MODEFLAG_CRT_AND_FP : 0;
    171 
    172     if (pGeode->Output & OUTPUT_PANEL) {
    173         mode.flags |= VG_MODEFLAG_PANELOUT;
    174         if (pGeode->Output & OUTPUT_CRT)
    175             mode.flags |= VG_MODEFLAG_CRT_AND_FP;
    176     }
    177 
    178     if (pGeode->Output & OUTPUT_PANEL && pGeode->Scale)
    179         lx_set_panel_mode(&mode, pGeode->panelMode);
    180     else
    181         lx_set_crt_mode(&mode, pMode);
    182 
    183     mode.src_width = pMode->HDisplay;
    184     mode.src_height = pMode->VDisplay;
    185 
    186     /* Set the filter coefficients to the default values */
    187     vg_set_scaler_filter_coefficients(NULL, NULL);
    188 
    189     ret = vg_set_custom_mode(&mode, bpp);
    190     return (ret == CIM_STATUS_OK) ? 0 : -1;
    191 }
    192 
    193 static void
    194 lx_crtc_dpms(xf86CrtcPtr crtc, int mode)
    195 {
    196     ScrnInfoPtr pScrni = crtc->scrn;
    197     GeodeRec *pGeode = GEODEPTR(pScrni);
    198 
    199     if (pGeode->Output & OUTPUT_DCON)
    200         DCONDPMSSet(pScrni, mode);
    201 
    202     switch (mode) {
    203     case DPMSModeOn:
    204         lx_enable_dac_power(pScrni, 1);
    205         break;
    206 
    207     case DPMSModeStandby:
    208         lx_disable_dac_power(pScrni, DF_CRT_STANDBY);
    209         break;
    210 
    211     case DPMSModeSuspend:
    212         lx_disable_dac_power(pScrni, DF_CRT_SUSPEND);
    213         break;
    214 
    215     case DPMSModeOff:
    216         lx_disable_dac_power(pScrni, DF_CRT_DISABLE);
    217         break;
    218     }
    219 }
    220 
    221 static Bool
    222 lx_crtc_lock(xf86CrtcPtr crtc)
    223 {
    224     /* Wait until the GPU is idle */
    225     gp_wait_until_idle();
    226     return TRUE;
    227 }
    228 
    229 static void
    230 lx_crtc_unlock(xf86CrtcPtr crtc)
    231 {
    232     /* Nothing to do here */
    233 }
    234 
    235 static void
    236 lx_crtc_prepare(xf86CrtcPtr crtc)
    237 {
    238     LXCrtcPrivatePtr lx_crtc = crtc->driver_private;
    239 
    240     /* Disable the video */
    241     df_get_video_enable(&lx_crtc->video_enable, &lx_crtc->video_flags);
    242 
    243     if (lx_crtc->video_enable)
    244         df_set_video_enable(0, 0);
    245 
    246     /* Turn off compression */
    247     vg_set_compression_enable(0);
    248 
    249     /* Hide the cursor */
    250     crtc->funcs->hide_cursor(crtc);
    251 
    252     /* Turn off the display */
    253     crtc->funcs->dpms(crtc, DPMSModeOff);
    254 }
    255 
    256 static Bool
    257 lx_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
    258                    DisplayModePtr adjusted_mode)
    259 {
    260     return TRUE;
    261 }
    262 
    263 static void
    264 lx_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
    265                  DisplayModePtr adjusted_mode, int x, int y)
    266 {
    267     ScrnInfoPtr pScrni = crtc->scrn;
    268     GeodeRec *pGeode = GEODEPTR(pScrni);
    269     DF_VIDEO_SOURCE_PARAMS vs_odd, vs_even;
    270     unsigned int rpitch;
    271 
    272     df_get_video_source_configuration(&vs_odd, &vs_even);
    273 
    274     /* Note - the memory gets adjusted when virtualX/virtualY
    275      * gets changed - so we don't need to worry about it here
    276      */
    277 
    278     if (lx_set_mode(pScrni, adjusted_mode, pScrni->bitsPerPixel))
    279         ErrorF("ERROR!  Unable to set the mode!\n");
    280 
    281     /* The output gets turned in in the output code as
    282      * per convention */
    283 
    284     /* For rotation, any write to the frame buffer region marks
    285      * the retire frame as dirty.
    286      */
    287     if (crtc->rotatedData != NULL) {
    288         rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8);
    289         vg_set_display_pitch(rpitch);
    290     }
    291     else
    292         vg_set_display_pitch(pGeode->Pitch);
    293     gp_set_bpp(pScrni->bitsPerPixel);
    294 
    295     /* Set the acceleration offset if we are drawing to a shadow */
    296     if (crtc->rotatedData != NULL)
    297         vg_set_display_offset((unsigned int) ((char *) crtc->rotatedData -
    298                                               (char *) pGeode->FBBase));
    299     else
    300         vg_set_display_offset(0);
    301 
    302     /* FIXME: What's up with X and Y?  Does that come into play
    303      * here? */
    304 
    305     df_configure_video_source(&vs_odd, &vs_even);
    306 
    307     vg_wait_vertical_blank();
    308 }
    309 
    310 static void
    311 lx_crtc_commit(xf86CrtcPtr crtc)
    312 {
    313     LXCrtcPrivatePtr lx_crtc = crtc->driver_private;
    314     ScrnInfoPtr pScrni = crtc->scrn;
    315     GeodeRec *pGeode = GEODEPTR(pScrni);
    316 
    317     /* Turn back on the sreen */
    318     crtc->funcs->dpms(crtc, DPMSModeOn);
    319 
    320     /* Turn on compression */
    321 
    322     if (pGeode->Compression) {
    323         vg_configure_compression(&(pGeode->CBData));
    324         vg_set_compression_enable(1);
    325     }
    326 
    327     /* Load the cursor */
    328     if (crtc->scrn->pScreen != NULL) {
    329 #ifdef HAVE_XF86_CURSOR_RESET_CURSOR
    330         xf86CursorResetCursor(crtc->scrn->pScreen);
    331 #else
    332         xf86_reload_cursors(crtc->scrn->pScreen);
    333 #endif
    334         crtc->funcs->hide_cursor(crtc);
    335         crtc->cursor_shown = FALSE;
    336     }
    337 
    338     /* Renable the video */
    339 
    340     if (lx_crtc->video_enable)
    341         df_set_video_enable(lx_crtc->video_enable, lx_crtc->video_flags);
    342 
    343     lx_crtc->video_enable = 0;
    344     lx_crtc->video_flags = 0;
    345 }
    346 
    347 static void
    348 lx_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green,
    349                   CARD16 *blue, int size)
    350 {
    351     unsigned int dcfg;
    352     int i;
    353 
    354     assert(size == 256);
    355 
    356     /* We need the Gamma Correction for video - fading operation,
    357      * the values address should be plused for every cycle.
    358      * Special for Screensaver Operation.
    359      */
    360 
    361     for (i = 0; i < 256; i++) {
    362         unsigned int val;
    363 
    364         (*red) &= 0xff00;
    365         (*green) &= 0xff00;
    366         (*blue) &= 0xff00;
    367         val = (*(red++) << 8) | *(green++) | (*(blue++) >> 8);
    368 
    369         df_set_video_palette_entry(i, val);
    370     }
    371 
    372     /* df_set_video_palette_entry automatically turns on
    373      * gamma for video - if this gets called, we assume that
    374      * RandR wants it set for graphics, so reverse cimarron
    375      */
    376 
    377     dcfg = READ_VID32(DF_DISPLAY_CONFIG);
    378     dcfg &= ~DF_DCFG_GV_PAL_BYP;
    379     WRITE_VID32(DF_DISPLAY_CONFIG, dcfg);
    380 }
    381 
    382     /* The Xserver has a scratch pixmap allocation routine that will
    383      * try to use the existing scratch pixmap if possible. When the driver
    384      * or any other user stop using it, it need to clear out any pixmap
    385      * state (private data etc) otherwise the next user may get stale data.
    386      */
    387 
    388     /* Use our own wrapper to allocate a pixmap for wrapping a buffer object
    389      * It removes using scratch pixmaps for rotate.
    390      */
    391 static PixmapPtr
    392 lx_create_bo_pixmap(ScreenPtr pScreen,
    393                     int width, int height,
    394                     int depth, int bpp, int pitch, pointer pPixData)
    395 {
    396     PixmapPtr pixmap;
    397 
    398 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,0,0,0)
    399     pixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0);
    400 #else
    401     pixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth);
    402 #endif
    403 
    404     if (!pixmap)
    405         return NULL;
    406     if (!(*pScreen->ModifyPixmapHeader) (pixmap, width, height,
    407                                          depth, bpp, pitch, pPixData)) {
    408         /* ModifyPixmapHeader failed, so we can't use it as scratch pixmap
    409          */
    410         (*pScreen->DestroyPixmap) (pixmap);
    411         return NULL;
    412     }
    413 
    414     return pixmap;
    415 }
    416 
    417 static void
    418 lx_destory_bo_pixmap(PixmapPtr pixmap)
    419 {
    420     ScreenPtr pScreen = pixmap->drawable.pScreen;
    421 
    422     (*pScreen->DestroyPixmap) (pixmap);
    423 }
    424 
    425     /* Allocates shadow memory, and allocating a new space for Rotation.
    426      * The size is measured in bytes, and the offset from the beginning
    427      * of card space is returned.
    428      */
    429 
    430 static Bool
    431 LXAllocShadow(ScrnInfoPtr pScrni, int size)
    432 {
    433     GeodeRec *pGeode = GEODEPTR(pScrni);
    434 
    435     if (pGeode->shadowArea) {
    436         if (pGeode->shadowArea->size != size) {
    437             exaOffscreenFree(pScrni->pScreen, pGeode->shadowArea);
    438             pGeode->shadowArea = NULL;
    439         }
    440     }
    441 
    442     if (pGeode->shadowArea == NULL) {
    443         pGeode->shadowArea =
    444             exaOffscreenAlloc(pScrni->pScreen, size, 4, TRUE, NULL, NULL);
    445 
    446         if (pGeode->shadowArea == NULL)
    447             return FALSE;
    448     }
    449 
    450     pScrni->fbOffset = pGeode->shadowArea->offset;
    451     return TRUE;
    452 }
    453 
    454 static void *
    455 lx_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
    456 {
    457     ScrnInfoPtr pScrni = crtc->scrn;
    458     GeodePtr pGeode = GEODEPTR(pScrni);
    459     unsigned int rpitch, size;
    460 
    461     rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8);
    462     size = rpitch * height;
    463 
    464     /* Allocate shadow memory */
    465     if (LXAllocShadow(pScrni, size) == FALSE) {
    466         xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
    467                    "Couldn't allocate the shadow memory for rotation\n");
    468         xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
    469                    " You need 0x%x bytes, but only 0x%x bytes are available\n",
    470                    size, GeodeOffscreenFreeSize(pGeode));
    471 
    472         return NULL;
    473     }
    474 
    475     memset(pGeode->FBBase + pGeode->shadowArea->offset, 0, size);
    476     return pGeode->FBBase + pGeode->shadowArea->offset;
    477 }
    478 
    479 static PixmapPtr
    480 lx_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
    481 {
    482     ScrnInfoPtr pScrni = crtc->scrn;
    483     PixmapPtr rpixmap;
    484     unsigned int rpitch;
    485 
    486     rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8);
    487     if (!data)
    488         data = lx_crtc_shadow_allocate(crtc, width, height);
    489 
    490     rpixmap = lx_create_bo_pixmap(pScrni->pScreen,
    491                                   width, height, pScrni->depth,
    492                                   pScrni->bitsPerPixel, rpitch, data);
    493 
    494     if (rpixmap == NULL) {
    495         xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
    496                    "Couldn't allocate shadow pixmap for rotated CRTC\n");
    497     }
    498 
    499     return rpixmap;
    500 }
    501 
    502 static void
    503 lx_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rpixmap, void *data)
    504 {
    505     ScrnInfoPtr pScrni = crtc->scrn;
    506     GeodeRec *pGeode = GEODEPTR(pScrni);
    507 
    508     if (rpixmap)
    509         lx_destory_bo_pixmap(rpixmap);
    510 
    511     /* Free shadow memory */
    512     if (data) {
    513         gp_wait_until_idle();
    514         if (pGeode->shadowArea != NULL) {
    515             exaOffscreenFree(pScrni->pScreen, pGeode->shadowArea);
    516             pGeode->shadowArea = NULL;
    517         }
    518     }
    519 }
    520 
    521 static void
    522 lx_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
    523 {
    524     vg_set_mono_cursor_colors(bg, fg);
    525 }
    526 
    527 static void
    528 lx_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
    529 {
    530     VG_PANNING_COORDINATES panning;
    531 
    532     vg_set_cursor_position(x, y, &panning);
    533 }
    534 
    535 static void
    536 lx_crtc_show_cursor(xf86CrtcPtr crtc)
    537 {
    538     vg_set_cursor_enable(1);
    539 }
    540 
    541 static void
    542 lx_crtc_hide_cursor(xf86CrtcPtr crtc)
    543 {
    544     vg_set_cursor_enable(0);
    545 }
    546 
    547 static void
    548 lx_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
    549 {
    550     LXLoadARGBCursorImage(crtc->scrn, (unsigned char *) image);
    551 }
    552 
    553 static const xf86CrtcFuncsRec lx_crtc_funcs = {
    554     .dpms = lx_crtc_dpms,
    555     .lock = lx_crtc_lock,
    556     .unlock = lx_crtc_unlock,
    557     .mode_fixup = lx_crtc_mode_fixup,
    558     .prepare = lx_crtc_prepare,
    559     .mode_set = lx_crtc_mode_set,
    560     .commit = lx_crtc_commit,
    561     .gamma_set = lx_crtc_gamma_set,
    562     .shadow_create = lx_crtc_shadow_create,
    563     .shadow_allocate = lx_crtc_shadow_allocate,
    564     .shadow_destroy = lx_crtc_shadow_destroy,
    565     .set_cursor_colors = lx_crtc_set_cursor_colors,
    566     .set_cursor_position = lx_crtc_set_cursor_position,
    567     .show_cursor = lx_crtc_show_cursor,
    568     .hide_cursor = lx_crtc_hide_cursor,
    569     .load_cursor_argb = lx_crtc_load_cursor_argb,
    570 };
    571 
    572 void
    573 LXSetupCrtc(ScrnInfoPtr pScrni)
    574 {
    575     xf86CrtcPtr crtc;
    576     LXCrtcPrivatePtr lxpriv;
    577 
    578     crtc = xf86CrtcCreate(pScrni, &lx_crtc_funcs);
    579 
    580     if (crtc == NULL) {
    581         ErrorF("ERROR - failed to create a CRTC\n");
    582         return;
    583     }
    584 
    585     lxpriv = xnfcalloc(1, sizeof(LXCrtcPrivateRec));
    586 
    587     if (!lxpriv) {
    588         xf86CrtcDestroy(crtc);
    589         ErrorF("unable to allocate memory for lxpriv\n");
    590         return;
    591     }
    592 
    593     crtc->driver_private = lxpriv;
    594 }
    595