lx_display.c revision 04007eba
1f29dbc25Smrg/* Copyright (c) 2008 Advanced Micro Devices, Inc.
2f29dbc25Smrg *
3f29dbc25Smrg * Permission is hereby granted, free of charge, to any person obtaining a copy
4f29dbc25Smrg * of this software and associated documentation files (the "Software"), to
5f29dbc25Smrg * deal in the Software without restriction, including without limitation the
6f29dbc25Smrg * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7f29dbc25Smrg * sell copies of the Software, and to permit persons to whom the Software is
8f29dbc25Smrg * furnished to do so, subject to the following conditions:
9f29dbc25Smrg *
10f29dbc25Smrg * The above copyright notice and this permission notice shall be included in
11f29dbc25Smrg * all copies or substantial portions of the Software.
12f29dbc25Smrg *
13f29dbc25Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14f29dbc25Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15f29dbc25Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16f29dbc25Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17f29dbc25Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18f29dbc25Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19f29dbc25Smrg * IN THE SOFTWARE.
20f29dbc25Smrg *
21f29dbc25Smrg * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
22f29dbc25Smrg * contributors may be used to endorse or promote products derived from this
23f29dbc25Smrg * software without specific prior written permission.
24f29dbc25Smrg */
25f29dbc25Smrg
26f29dbc25Smrg#ifdef HAVE_CONFIG_H
27f29dbc25Smrg#include "config.h"
28f29dbc25Smrg#endif
29f29dbc25Smrg
30f29dbc25Smrg#include "xf86.h"
31f29dbc25Smrg#include "geode.h"
32f29dbc25Smrg#include "xf86Crtc.h"
33f29dbc25Smrg#include "cim/cim_defs.h"
34f29dbc25Smrg#include "cim/cim_regs.h"
35f29dbc25Smrg
3604007ebaSmrgtypedef struct _LXOutputPrivateRec {
37f29dbc25Smrg    int video_enable;
38f29dbc25Smrg    unsigned long video_flags;
39f29dbc25Smrg    GeodeMemPtr rotate_mem;
40f29dbc25Smrg} LXCrtcPrivateRec, *LXCrtcPrivatePtr;
41f29dbc25Smrg
42f29dbc25Smrgstatic void
43f29dbc25Smrglx_enable_dac_power(ScrnInfoPtr pScrni, int option)
44f29dbc25Smrg{
45f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
46f29dbc25Smrg
47f29dbc25Smrg    df_set_crt_enable(DF_CRT_ENABLE);
48f29dbc25Smrg
49f29dbc25Smrg    /* Turn off the DAC if we don't need the CRT */
50f29dbc25Smrg
51f29dbc25Smrg    if (option && (!(pGeode->Output & OUTPUT_CRT))) {
5204007ebaSmrg        unsigned int misc = READ_VID32(DF_VID_MISC);
53f29dbc25Smrg
5404007ebaSmrg        misc |= DF_DAC_POWER_DOWN;
5504007ebaSmrg        WRITE_VID32(DF_VID_MISC, misc);
56f29dbc25Smrg    }
57f29dbc25Smrg
58f29dbc25Smrg    if (pGeode->Output & OUTPUT_PANEL)
5904007ebaSmrg        df_set_panel_enable(1);
60f29dbc25Smrg}
61f29dbc25Smrg
62f29dbc25Smrgstatic void
63f29dbc25Smrglx_disable_dac_power(ScrnInfoPtr pScrni, int option)
64f29dbc25Smrg{
65f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
66f29dbc25Smrg
67f29dbc25Smrg    if (pGeode->Output & OUTPUT_PANEL)
6804007ebaSmrg        df_set_panel_enable(0);
69f29dbc25Smrg
70f29dbc25Smrg    if (pGeode->Output & OUTPUT_CRT) {
71f29dbc25Smrg
7204007ebaSmrg        /* Wait for the panel to finish its procedure */
73f29dbc25Smrg
7404007ebaSmrg        if (pGeode->Output & OUTPUT_PANEL)
7504007ebaSmrg            while ((READ_VID32(DF_POWER_MANAGEMENT) & 2) == 0);
7604007ebaSmrg        df_set_crt_enable(option);
77f29dbc25Smrg    }
78f29dbc25Smrg}
79f29dbc25Smrg
80f29dbc25Smrgstatic void
81f29dbc25Smrglx_set_panel_mode(VG_DISPLAY_MODE * mode, DisplayModePtr pMode)
82f29dbc25Smrg{
83f29dbc25Smrg    int hsync, vsync;
84f29dbc25Smrg
85f29dbc25Smrg    mode->mode_width = mode->panel_width = pMode->HDisplay;
86f29dbc25Smrg    mode->mode_height = mode->panel_height = pMode->VDisplay;
87f29dbc25Smrg
88f29dbc25Smrg    mode->hactive = pMode->HDisplay;
89f29dbc25Smrg    mode->hblankstart = pMode->HDisplay;
90f29dbc25Smrg    mode->hsyncstart = pMode->HSyncStart;
91f29dbc25Smrg    mode->hsyncend = pMode->HSyncEnd;
92f29dbc25Smrg    mode->hblankend = pMode->HTotal;
93f29dbc25Smrg    mode->htotal = pMode->HTotal;
94f29dbc25Smrg
95f29dbc25Smrg    mode->vactive = pMode->VDisplay;
96f29dbc25Smrg    mode->vblankstart = pMode->VDisplay;
97f29dbc25Smrg    mode->vsyncstart = pMode->VSyncStart;
98f29dbc25Smrg    mode->vsyncend = pMode->VSyncEnd;
99f29dbc25Smrg    mode->vblankend = pMode->VTotal;
100f29dbc25Smrg    mode->vtotal = pMode->VTotal;
101f29dbc25Smrg
102f29dbc25Smrg    mode->vactive_even = pMode->VDisplay;
103f29dbc25Smrg    mode->vblankstart_even = pMode->VDisplay;
104f29dbc25Smrg    mode->vsyncstart_even = pMode->VSyncStart;
105f29dbc25Smrg    mode->vsyncend_even = pMode->VSyncEnd;
106f29dbc25Smrg    mode->vblankend_even = pMode->VTotal;
107f29dbc25Smrg    mode->vtotal_even = pMode->VTotal;
108f29dbc25Smrg
10904007ebaSmrg    mode->frequency = (int) ((pMode->Clock / 1000.0) * 0x10000);
110f29dbc25Smrg
111f29dbc25Smrg    /* In panel mode, Cimarron purposely swizzles these,
112f29dbc25Smrg     * so we swizzle them first  */
113f29dbc25Smrg
114f29dbc25Smrg    hsync = (pMode->Flags & V_NHSYNC) ? 0 : 1;
115f29dbc25Smrg    vsync = (pMode->Flags & V_NVSYNC) ? 0 : 1;
116f29dbc25Smrg
117f29dbc25Smrg    mode->flags |= (hsync) ? VG_MODEFLAG_NEG_HSYNC : 0;
118f29dbc25Smrg    mode->flags |= (vsync) ? VG_MODEFLAG_NEG_VSYNC : 0;
119f29dbc25Smrg}
120f29dbc25Smrg
121f29dbc25Smrgstatic void
122f29dbc25Smrglx_set_crt_mode(VG_DISPLAY_MODE * mode, DisplayModePtr pMode)
123f29dbc25Smrg{
124f29dbc25Smrg    int hsync, vsync;
125f29dbc25Smrg
126f29dbc25Smrg    mode->mode_width = mode->panel_width = pMode->HDisplay;
127f29dbc25Smrg    mode->mode_height = mode->panel_height = pMode->VDisplay;
128f29dbc25Smrg
129f29dbc25Smrg    mode->hactive = pMode->CrtcHDisplay;
130f29dbc25Smrg    mode->hblankstart = pMode->CrtcHBlankStart;
131f29dbc25Smrg    mode->hsyncstart = pMode->CrtcHSyncStart;
132f29dbc25Smrg    mode->hsyncend = pMode->CrtcHSyncEnd;
133f29dbc25Smrg    mode->hblankend = pMode->CrtcHBlankEnd;
134f29dbc25Smrg    mode->htotal = pMode->CrtcHTotal;
135f29dbc25Smrg
136f29dbc25Smrg    mode->vactive = pMode->CrtcVDisplay;
137f29dbc25Smrg    mode->vblankstart = pMode->CrtcVBlankStart;
138f29dbc25Smrg    mode->vsyncstart = pMode->CrtcVSyncStart;
139f29dbc25Smrg    mode->vsyncend = pMode->CrtcVSyncEnd;
140f29dbc25Smrg    mode->vblankend = pMode->CrtcVBlankEnd;
141f29dbc25Smrg    mode->vtotal = pMode->CrtcVTotal;
142f29dbc25Smrg
143f29dbc25Smrg    mode->vactive_even = pMode->CrtcVDisplay;
144f29dbc25Smrg    mode->vblankstart_even = pMode->CrtcVBlankStart;
145f29dbc25Smrg    mode->vsyncstart_even = pMode->CrtcVSyncStart;
146f29dbc25Smrg    mode->vsyncend_even = pMode->CrtcVSyncEnd;
147f29dbc25Smrg    mode->vblankend_even = pMode->CrtcVBlankEnd;
148f29dbc25Smrg    mode->vtotal_even = pMode->CrtcVTotal;
149f29dbc25Smrg
15004007ebaSmrg    mode->frequency = (int) ((pMode->Clock / 1000.0) * 0x10000);
151f29dbc25Smrg
152f29dbc25Smrg    hsync = (pMode->Flags & V_NHSYNC) ? 1 : 0;
153f29dbc25Smrg    vsync = (pMode->Flags & V_NVSYNC) ? 1 : 0;
154f29dbc25Smrg
155f29dbc25Smrg    mode->flags |= (hsync) ? VG_MODEFLAG_NEG_HSYNC : 0;
156f29dbc25Smrg    mode->flags |= (vsync) ? VG_MODEFLAG_NEG_VSYNC : 0;
157f29dbc25Smrg}
158f29dbc25Smrg
159f29dbc25Smrgstatic int
160f29dbc25Smrglx_set_mode(ScrnInfoPtr pScrni, DisplayModePtr pMode, int bpp)
161f29dbc25Smrg{
162f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
163f29dbc25Smrg    VG_DISPLAY_MODE mode;
164f29dbc25Smrg    int ret;
165f29dbc25Smrg
166f29dbc25Smrg    memset(&mode, 0, sizeof(mode));
167f29dbc25Smrg
168f29dbc25Smrg    mode.flags |= pGeode->Output & OUTPUT_CRT ? VG_MODEFLAG_CRT_AND_FP : 0;
169f29dbc25Smrg
170f29dbc25Smrg    if (pGeode->Output & OUTPUT_PANEL) {
17104007ebaSmrg        mode.flags |= VG_MODEFLAG_PANELOUT;
17204007ebaSmrg        if (pGeode->Output & OUTPUT_CRT)
17304007ebaSmrg            mode.flags |= VG_MODEFLAG_CRT_AND_FP;
174f29dbc25Smrg    }
175f29dbc25Smrg
176f29dbc25Smrg    if (pGeode->Output & OUTPUT_PANEL && pGeode->Scale)
17704007ebaSmrg        lx_set_panel_mode(&mode, pGeode->panelMode);
178f29dbc25Smrg    else
17904007ebaSmrg        lx_set_crt_mode(&mode, pMode);
180f29dbc25Smrg
181f29dbc25Smrg    mode.src_width = pMode->HDisplay;
182f29dbc25Smrg    mode.src_height = pMode->VDisplay;
183f29dbc25Smrg
184f29dbc25Smrg    /* Set the filter coefficients to the default values */
185f29dbc25Smrg    vg_set_scaler_filter_coefficients(NULL, NULL);
186f29dbc25Smrg
187f29dbc25Smrg    ret = vg_set_custom_mode(&mode, bpp);
188f29dbc25Smrg    return (ret == CIM_STATUS_OK) ? 0 : -1;
189f29dbc25Smrg}
190f29dbc25Smrg
191f29dbc25Smrgstatic void
192f29dbc25Smrglx_crtc_dpms(xf86CrtcPtr crtc, int mode)
193f29dbc25Smrg{
194f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
195f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
196f29dbc25Smrg
197f29dbc25Smrg    if (pGeode->Output & OUTPUT_DCON)
19804007ebaSmrg        DCONDPMSSet(pScrni, mode);
199f29dbc25Smrg
200f29dbc25Smrg    switch (mode) {
201f29dbc25Smrg    case DPMSModeOn:
20204007ebaSmrg        lx_enable_dac_power(pScrni, 1);
20304007ebaSmrg        break;
204f29dbc25Smrg
205f29dbc25Smrg    case DPMSModeStandby:
20604007ebaSmrg        lx_disable_dac_power(pScrni, DF_CRT_STANDBY);
20704007ebaSmrg        break;
208f29dbc25Smrg
209f29dbc25Smrg    case DPMSModeSuspend:
21004007ebaSmrg        lx_disable_dac_power(pScrni, DF_CRT_SUSPEND);
21104007ebaSmrg        break;
212f29dbc25Smrg
213f29dbc25Smrg    case DPMSModeOff:
21404007ebaSmrg        lx_disable_dac_power(pScrni, DF_CRT_DISABLE);
21504007ebaSmrg        break;
216f29dbc25Smrg    }
217f29dbc25Smrg}
218f29dbc25Smrg
219f29dbc25Smrgstatic Bool
220f29dbc25Smrglx_crtc_lock(xf86CrtcPtr crtc)
221f29dbc25Smrg{
222f29dbc25Smrg    /* Wait until the GPU is idle */
223f29dbc25Smrg    gp_wait_until_idle();
224f29dbc25Smrg    return TRUE;
225f29dbc25Smrg}
226f29dbc25Smrg
227f29dbc25Smrgstatic void
228f29dbc25Smrglx_crtc_unlock(xf86CrtcPtr crtc)
229f29dbc25Smrg{
230f29dbc25Smrg    /* Nothing to do here */
231f29dbc25Smrg}
232f29dbc25Smrg
233f29dbc25Smrgstatic void
234f29dbc25Smrglx_crtc_prepare(xf86CrtcPtr crtc)
235f29dbc25Smrg{
236f29dbc25Smrg    LXCrtcPrivatePtr lx_crtc = crtc->driver_private;
237f29dbc25Smrg
238f29dbc25Smrg    /* Disable the video */
239f29dbc25Smrg    df_get_video_enable(&lx_crtc->video_enable, &lx_crtc->video_flags);
240f29dbc25Smrg
241f29dbc25Smrg    if (lx_crtc->video_enable)
24204007ebaSmrg        df_set_video_enable(0, 0);
243f29dbc25Smrg
244f29dbc25Smrg    /* Turn off compression */
245f29dbc25Smrg    vg_set_compression_enable(0);
246f29dbc25Smrg
247f29dbc25Smrg    /* Hide the cursor */
248f29dbc25Smrg    crtc->funcs->hide_cursor(crtc);
249f29dbc25Smrg
250f29dbc25Smrg    /* Turn off the display */
251f29dbc25Smrg    crtc->funcs->dpms(crtc, DPMSModeOff);
252f29dbc25Smrg}
253f29dbc25Smrg
254f29dbc25Smrgstatic Bool
255f29dbc25Smrglx_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
25604007ebaSmrg                   DisplayModePtr adjusted_mode)
257f29dbc25Smrg{
258f29dbc25Smrg    return TRUE;
259f29dbc25Smrg}
260f29dbc25Smrg
261f29dbc25Smrgstatic void
262f29dbc25Smrglx_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
26304007ebaSmrg                 DisplayModePtr adjusted_mode, int x, int y)
264f29dbc25Smrg{
265f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
266f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
267f29dbc25Smrg    DF_VIDEO_SOURCE_PARAMS vs_odd, vs_even;
268170d5fdcSmrg    unsigned int rpitch;
269f29dbc25Smrg
270f29dbc25Smrg    df_get_video_source_configuration(&vs_odd, &vs_even);
271f29dbc25Smrg
272f29dbc25Smrg    /* Note - the memory gets adjusted when virtualX/virtualY
273f29dbc25Smrg     * gets changed - so we don't need to worry about it here
274f29dbc25Smrg     */
275f29dbc25Smrg
276f29dbc25Smrg    if (lx_set_mode(pScrni, adjusted_mode, pScrni->bitsPerPixel))
27704007ebaSmrg        ErrorF("ERROR!  Unable to set the mode!\n");
278f29dbc25Smrg
279f29dbc25Smrg    /* The output gets turned in in the output code as
280f29dbc25Smrg     * per convention */
281f29dbc25Smrg
282170d5fdcSmrg    /* For rotation, any write to the frame buffer region marks
283170d5fdcSmrg     * the retire frame as dirty.
284170d5fdcSmrg     */
285170d5fdcSmrg    if (crtc->rotatedData != NULL) {
28604007ebaSmrg        rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8);
28704007ebaSmrg        vg_set_display_pitch(rpitch);
288170d5fdcSmrg    }
289170d5fdcSmrg    else
29004007ebaSmrg        vg_set_display_pitch(pGeode->Pitch);
291f29dbc25Smrg    gp_set_bpp(pScrni->bitsPerPixel);
292f29dbc25Smrg
293f29dbc25Smrg    /* Set the acceleration offset if we are drawing to a shadow */
294f29dbc25Smrg    if (crtc->rotatedData != NULL)
29504007ebaSmrg        vg_set_display_offset((unsigned int) ((char *) crtc->rotatedData -
29604007ebaSmrg                                              (char *) pGeode->FBBase));
297f29dbc25Smrg    else
29804007ebaSmrg        vg_set_display_offset(0);
299f29dbc25Smrg
300f29dbc25Smrg    /* FIXME: Whats up with X and Y?  Does that come into play
301f29dbc25Smrg     * here? */
302f29dbc25Smrg
303f29dbc25Smrg    df_configure_video_source(&vs_odd, &vs_even);
304f29dbc25Smrg
305f29dbc25Smrg    vg_wait_vertical_blank();
306f29dbc25Smrg}
307f29dbc25Smrg
308f29dbc25Smrgstatic void
309f29dbc25Smrglx_crtc_commit(xf86CrtcPtr crtc)
310f29dbc25Smrg{
311f29dbc25Smrg    LXCrtcPrivatePtr lx_crtc = crtc->driver_private;
312f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
313f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
314f29dbc25Smrg
315f29dbc25Smrg    /* Turn back on the sreen */
316f29dbc25Smrg    crtc->funcs->dpms(crtc, DPMSModeOn);
317f29dbc25Smrg
318f29dbc25Smrg    /* Turn on compression */
319f29dbc25Smrg
320f29dbc25Smrg    if (pGeode->Compression) {
32104007ebaSmrg        vg_configure_compression(&(pGeode->CBData));
32204007ebaSmrg        vg_set_compression_enable(1);
323f29dbc25Smrg    }
324f29dbc25Smrg
325f29dbc25Smrg    /* Load the cursor */
326f29dbc25Smrg    if (crtc->scrn->pScreen != NULL) {
32704007ebaSmrg        xf86_reload_cursors(crtc->scrn->pScreen);
32804007ebaSmrg        crtc->funcs->hide_cursor(crtc);
32904007ebaSmrg        crtc->cursor_shown = FALSE;
330f29dbc25Smrg    }
331f29dbc25Smrg
332f29dbc25Smrg    /* Renable the video */
333f29dbc25Smrg
334f29dbc25Smrg    if (lx_crtc->video_enable)
33504007ebaSmrg        df_set_video_enable(lx_crtc->video_enable, lx_crtc->video_flags);
336f29dbc25Smrg
337f29dbc25Smrg    lx_crtc->video_enable = 0;
338f29dbc25Smrg    lx_crtc->video_flags = 0;
339f29dbc25Smrg}
340f29dbc25Smrg
341f29dbc25Smrgstatic void
34204007ebaSmrglx_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green,
34304007ebaSmrg                  CARD16 *blue, int size)
344f29dbc25Smrg{
345f29dbc25Smrg    unsigned int dcfg;
346f29dbc25Smrg    int i;
347f29dbc25Smrg
348f29dbc25Smrg    assert(size == 256);
349f29dbc25Smrg
350170d5fdcSmrg    /* We need the Gamma Correction for video - fading operation,
351170d5fdcSmrg     * the values address should be plused for every cycle.
352170d5fdcSmrg     * Special for Screensaver Operation.
353170d5fdcSmrg     */
354170d5fdcSmrg
355f29dbc25Smrg    for (i = 0; i < 256; i++) {
35604007ebaSmrg        unsigned int val;
35704007ebaSmrg
358170d5fdcSmrg        (*red) &= 0xff00;
359170d5fdcSmrg        (*green) &= 0xff00;
360170d5fdcSmrg        (*blue) &= 0xff00;
36104007ebaSmrg        val = (*(red++) << 8) | *(green++) | (*(blue++) >> 8);
362f29dbc25Smrg
36304007ebaSmrg        df_set_video_palette_entry(i, val);
364f29dbc25Smrg    }
365f29dbc25Smrg
366f29dbc25Smrg    /* df_set_video_palette_entry automatically turns on
367f29dbc25Smrg     * gamma for video - if this gets called, we assume that
368f29dbc25Smrg     * RandR wants it set for graphics, so reverse cimarron
369f29dbc25Smrg     */
370f29dbc25Smrg
371f29dbc25Smrg    dcfg = READ_VID32(DF_DISPLAY_CONFIG);
372f29dbc25Smrg    dcfg &= ~DF_DCFG_GV_PAL_BYP;
373f29dbc25Smrg    WRITE_VID32(DF_DISPLAY_CONFIG, dcfg);
374f29dbc25Smrg}
375f29dbc25Smrg
376170d5fdcSmrg    /* The Xserver has a scratch pixmap allocation routine that will
377170d5fdcSmrg     * try to use the existing scratch pixmap if possible. When the driver
378170d5fdcSmrg     * or any other user stop using it, it need to clear out any pixmap
379170d5fdcSmrg     * state (private data etc) otherwise the next user may get stale data.
380170d5fdcSmrg     */
381170d5fdcSmrg
382170d5fdcSmrg    /* Use our own wrapper to allocate a pixmap for wrapping a buffer object
383170d5fdcSmrg     * It removes using scratch pixmaps for rotate.
384170d5fdcSmrg     */
385170d5fdcSmrgstatic PixmapPtr
386170d5fdcSmrglx_create_bo_pixmap(ScreenPtr pScreen,
38704007ebaSmrg                    int width, int height,
38804007ebaSmrg                    int depth, int bpp, int pitch, pointer pPixData)
389170d5fdcSmrg{
390170d5fdcSmrg    PixmapPtr pixmap;
391170d5fdcSmrg
3927aef237fSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,0,0,0)
39304007ebaSmrg    pixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0);
3947aef237fSmrg#else
39504007ebaSmrg    pixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth);
3967aef237fSmrg#endif
3977aef237fSmrg
398170d5fdcSmrg    if (!pixmap)
39904007ebaSmrg        return NULL;
40004007ebaSmrg    if (!(*pScreen->ModifyPixmapHeader) (pixmap, width, height,
40104007ebaSmrg                                         depth, bpp, pitch, pPixData)) {
40204007ebaSmrg        /* ModifyPixmapHeader failed, so we can't use it as scratch pixmap
40304007ebaSmrg         */
40404007ebaSmrg        (*pScreen->DestroyPixmap) (pixmap);
40504007ebaSmrg        return NULL;
406170d5fdcSmrg    }
407170d5fdcSmrg
408170d5fdcSmrg    return pixmap;
409170d5fdcSmrg}
410170d5fdcSmrg
411170d5fdcSmrgstatic void
412170d5fdcSmrglx_destory_bo_pixmap(PixmapPtr pixmap)
413170d5fdcSmrg{
414170d5fdcSmrg    ScreenPtr pScreen = pixmap->drawable.pScreen;
415170d5fdcSmrg
41604007ebaSmrg    (*pScreen->DestroyPixmap) (pixmap);
417170d5fdcSmrg}
418170d5fdcSmrg
419170d5fdcSmrg    /* Allocates shadow memory, and allocating a new space for Rotation.
420170d5fdcSmrg     * The size is measured in bytes, and the offset from the beginning
421170d5fdcSmrg     * of card space is returned.
422170d5fdcSmrg     */
423170d5fdcSmrg
424170d5fdcSmrgstatic Bool
425170d5fdcSmrgLXAllocShadow(ScrnInfoPtr pScrni, int size)
426170d5fdcSmrg{
427170d5fdcSmrg    GeodeRec *pGeode = GEODEPTR(pScrni);
428170d5fdcSmrg
429170d5fdcSmrg    if (pGeode->shadowArea) {
43004007ebaSmrg        if (pGeode->shadowArea->size != size) {
43104007ebaSmrg            exaOffscreenFree(pScrni->pScreen, pGeode->shadowArea);
43204007ebaSmrg            pGeode->shadowArea = NULL;
43304007ebaSmrg        }
434170d5fdcSmrg    }
435170d5fdcSmrg
436170d5fdcSmrg    if (pGeode->shadowArea == NULL) {
43704007ebaSmrg        pGeode->shadowArea =
43804007ebaSmrg            exaOffscreenAlloc(pScrni->pScreen, size, 4, TRUE, NULL, NULL);
439170d5fdcSmrg
44004007ebaSmrg        if (pGeode->shadowArea == NULL)
44104007ebaSmrg            return FALSE;
442170d5fdcSmrg    }
443170d5fdcSmrg
444170d5fdcSmrg    pScrni->fbOffset = pGeode->shadowArea->offset;
445170d5fdcSmrg    return TRUE;
446170d5fdcSmrg}
447170d5fdcSmrg
448f29dbc25Smrgstatic void *
449f29dbc25Smrglx_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
450f29dbc25Smrg{
451f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
452f29dbc25Smrg    GeodePtr pGeode = GEODEPTR(pScrni);
453f29dbc25Smrg    unsigned int rpitch, size;
454f29dbc25Smrg
455f29dbc25Smrg    rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8);
456f29dbc25Smrg    size = rpitch * height;
457f29dbc25Smrg
458170d5fdcSmrg    /* Allocate shadow memory */
459170d5fdcSmrg    if (LXAllocShadow(pScrni, size) == FALSE) {
46004007ebaSmrg        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
46104007ebaSmrg                   "Couldn't allocate the shadow memory for rotation\n");
46204007ebaSmrg        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
46304007ebaSmrg                   " You need 0x%x bytes, but only 0x%x bytes are available\n",
46404007ebaSmrg                   size, GeodeOffscreenFreeSize(pGeode));
465f29dbc25Smrg
46604007ebaSmrg        return NULL;
467f29dbc25Smrg    }
468f29dbc25Smrg
469170d5fdcSmrg    memset(pGeode->FBBase + pGeode->shadowArea->offset, 0, size);
470170d5fdcSmrg    return pGeode->FBBase + pGeode->shadowArea->offset;
471f29dbc25Smrg}
472f29dbc25Smrg
473f29dbc25Smrgstatic PixmapPtr
474f29dbc25Smrglx_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
475f29dbc25Smrg{
476f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
477f29dbc25Smrg    PixmapPtr rpixmap;
478170d5fdcSmrg    unsigned int rpitch;
479f29dbc25Smrg
480170d5fdcSmrg    rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8);
481f29dbc25Smrg    if (!data)
48204007ebaSmrg        data = lx_crtc_shadow_allocate(crtc, width, height);
483f29dbc25Smrg
484170d5fdcSmrg    rpixmap = lx_create_bo_pixmap(pScrni->pScreen,
48504007ebaSmrg                                  width, height, pScrni->depth,
48604007ebaSmrg                                  pScrni->bitsPerPixel, rpitch, data);
487f29dbc25Smrg
488f29dbc25Smrg    if (rpixmap == NULL) {
48904007ebaSmrg        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
49004007ebaSmrg                   "Couldn't allocate shadow pixmap for rotated CRTC\n");
491f29dbc25Smrg    }
492f29dbc25Smrg
493f29dbc25Smrg    return rpixmap;
494f29dbc25Smrg}
495f29dbc25Smrg
496f29dbc25Smrgstatic void
497f29dbc25Smrglx_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rpixmap, void *data)
498f29dbc25Smrg{
499f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
500f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
501f29dbc25Smrg
502f29dbc25Smrg    if (rpixmap)
50304007ebaSmrg        lx_destory_bo_pixmap(rpixmap);
504f29dbc25Smrg
505170d5fdcSmrg    /* Free shadow memory */
506f29dbc25Smrg    if (data) {
50704007ebaSmrg        gp_wait_until_idle();
50804007ebaSmrg        if (pGeode->shadowArea != NULL) {
50904007ebaSmrg            exaOffscreenFree(pScrni->pScreen, pGeode->shadowArea);
51004007ebaSmrg            pGeode->shadowArea = NULL;
51104007ebaSmrg        }
512f29dbc25Smrg    }
513f29dbc25Smrg}
514f29dbc25Smrg
515f29dbc25Smrgstatic void
516f29dbc25Smrglx_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
517f29dbc25Smrg{
518f29dbc25Smrg    vg_set_mono_cursor_colors(bg, fg);
519f29dbc25Smrg}
520f29dbc25Smrg
521f29dbc25Smrgstatic void
522f29dbc25Smrglx_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
523f29dbc25Smrg{
524f29dbc25Smrg    VG_PANNING_COORDINATES panning;
52504007ebaSmrg
526f29dbc25Smrg    vg_set_cursor_position(x, y, &panning);
527f29dbc25Smrg}
528f29dbc25Smrg
529f29dbc25Smrgstatic void
530f29dbc25Smrglx_crtc_show_cursor(xf86CrtcPtr crtc)
531f29dbc25Smrg{
532f29dbc25Smrg    vg_set_cursor_enable(1);
533f29dbc25Smrg}
534f29dbc25Smrg
535f29dbc25Smrgstatic void
536f29dbc25Smrglx_crtc_hide_cursor(xf86CrtcPtr crtc)
537f29dbc25Smrg{
538f29dbc25Smrg    vg_set_cursor_enable(0);
539f29dbc25Smrg}
540f29dbc25Smrg
541f29dbc25Smrgstatic void
542f29dbc25Smrglx_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
543f29dbc25Smrg{
544f29dbc25Smrg    LXLoadARGBCursorImage(crtc->scrn, (unsigned char *) image);
545f29dbc25Smrg}
546f29dbc25Smrg
547f29dbc25Smrgstatic const xf86CrtcFuncsRec lx_crtc_funcs = {
548f29dbc25Smrg    .dpms = lx_crtc_dpms,
549f29dbc25Smrg    .lock = lx_crtc_lock,
550f29dbc25Smrg    .unlock = lx_crtc_unlock,
551f29dbc25Smrg    .mode_fixup = lx_crtc_mode_fixup,
552f29dbc25Smrg    .prepare = lx_crtc_prepare,
553f29dbc25Smrg    .mode_set = lx_crtc_mode_set,
554f29dbc25Smrg    .commit = lx_crtc_commit,
555f29dbc25Smrg    .gamma_set = lx_crtc_gamma_set,
556f29dbc25Smrg    .shadow_create = lx_crtc_shadow_create,
557f29dbc25Smrg    .shadow_allocate = lx_crtc_shadow_allocate,
558f29dbc25Smrg    .shadow_destroy = lx_crtc_shadow_destroy,
559f29dbc25Smrg    .set_cursor_colors = lx_crtc_set_cursor_colors,
560f29dbc25Smrg    .set_cursor_position = lx_crtc_set_cursor_position,
561f29dbc25Smrg    .show_cursor = lx_crtc_show_cursor,
562f29dbc25Smrg    .hide_cursor = lx_crtc_hide_cursor,
563f29dbc25Smrg    .load_cursor_argb = lx_crtc_load_cursor_argb,
564f29dbc25Smrg};
565f29dbc25Smrg
566f29dbc25Smrgvoid
567f29dbc25SmrgLXSetupCrtc(ScrnInfoPtr pScrni)
568f29dbc25Smrg{
569f29dbc25Smrg    xf86CrtcPtr crtc;
570f29dbc25Smrg    LXCrtcPrivatePtr lxpriv;
571f29dbc25Smrg
572f29dbc25Smrg    crtc = xf86CrtcCreate(pScrni, &lx_crtc_funcs);
573f29dbc25Smrg
574f29dbc25Smrg    if (crtc == NULL) {
57504007ebaSmrg        ErrorF("ERROR - failed to create a CRTC\n");
57604007ebaSmrg        return;
577f29dbc25Smrg    }
578f29dbc25Smrg
57904007ebaSmrg    lxpriv = xnfcalloc(1, sizeof(LXCrtcPrivateRec));
580f29dbc25Smrg
581f29dbc25Smrg    if (!lxpriv) {
58204007ebaSmrg        xf86CrtcDestroy(crtc);
58304007ebaSmrg        ErrorF("unable to allocate memory for lxpriv\n");
58404007ebaSmrg        return;
585f29dbc25Smrg    }
586f29dbc25Smrg
587f29dbc25Smrg    crtc->driver_private = lxpriv;
588f29dbc25Smrg}
589