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
3000be8644Schristos#include "xorg-server.h"
3100be8644Schristos
32f29dbc25Smrg#include "xf86.h"
33f29dbc25Smrg#include "geode.h"
34f29dbc25Smrg#include "xf86Crtc.h"
35f29dbc25Smrg#include "cim/cim_defs.h"
36f29dbc25Smrg#include "cim/cim_regs.h"
37f29dbc25Smrg
3804007ebaSmrgtypedef struct _LXOutputPrivateRec {
39f29dbc25Smrg    int video_enable;
40f29dbc25Smrg    unsigned long video_flags;
41f29dbc25Smrg    GeodeMemPtr rotate_mem;
42f29dbc25Smrg} LXCrtcPrivateRec, *LXCrtcPrivatePtr;
43f29dbc25Smrg
44e9a8eab3Smrgvoid
45f29dbc25Smrglx_enable_dac_power(ScrnInfoPtr pScrni, int option)
46f29dbc25Smrg{
47f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
48f29dbc25Smrg
49f29dbc25Smrg    df_set_crt_enable(DF_CRT_ENABLE);
50f29dbc25Smrg
51f29dbc25Smrg    /* Turn off the DAC if we don't need the CRT */
52f29dbc25Smrg
53f29dbc25Smrg    if (option && (!(pGeode->Output & OUTPUT_CRT))) {
5404007ebaSmrg        unsigned int misc = READ_VID32(DF_VID_MISC);
55f29dbc25Smrg
5604007ebaSmrg        misc |= DF_DAC_POWER_DOWN;
5704007ebaSmrg        WRITE_VID32(DF_VID_MISC, misc);
58f29dbc25Smrg    }
59f29dbc25Smrg
60f29dbc25Smrg    if (pGeode->Output & OUTPUT_PANEL)
6104007ebaSmrg        df_set_panel_enable(1);
62f29dbc25Smrg}
63f29dbc25Smrg
64e9a8eab3Smrgvoid
65f29dbc25Smrglx_disable_dac_power(ScrnInfoPtr pScrni, int option)
66f29dbc25Smrg{
67f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
68f29dbc25Smrg
69f29dbc25Smrg    if (pGeode->Output & OUTPUT_PANEL)
7004007ebaSmrg        df_set_panel_enable(0);
71f29dbc25Smrg
72f29dbc25Smrg    if (pGeode->Output & OUTPUT_CRT) {
73f29dbc25Smrg
7404007ebaSmrg        /* Wait for the panel to finish its procedure */
75f29dbc25Smrg
7604007ebaSmrg        if (pGeode->Output & OUTPUT_PANEL)
7704007ebaSmrg            while ((READ_VID32(DF_POWER_MANAGEMENT) & 2) == 0);
7804007ebaSmrg        df_set_crt_enable(option);
79f29dbc25Smrg    }
80f29dbc25Smrg}
81f29dbc25Smrg
82f29dbc25Smrgstatic void
83f29dbc25Smrglx_set_panel_mode(VG_DISPLAY_MODE * mode, DisplayModePtr pMode)
84f29dbc25Smrg{
85f29dbc25Smrg    int hsync, vsync;
86f29dbc25Smrg
87f29dbc25Smrg    mode->mode_width = mode->panel_width = pMode->HDisplay;
88f29dbc25Smrg    mode->mode_height = mode->panel_height = pMode->VDisplay;
89f29dbc25Smrg
90f29dbc25Smrg    mode->hactive = pMode->HDisplay;
91f29dbc25Smrg    mode->hblankstart = pMode->HDisplay;
92f29dbc25Smrg    mode->hsyncstart = pMode->HSyncStart;
93f29dbc25Smrg    mode->hsyncend = pMode->HSyncEnd;
94f29dbc25Smrg    mode->hblankend = pMode->HTotal;
95f29dbc25Smrg    mode->htotal = pMode->HTotal;
96f29dbc25Smrg
97f29dbc25Smrg    mode->vactive = pMode->VDisplay;
98f29dbc25Smrg    mode->vblankstart = pMode->VDisplay;
99f29dbc25Smrg    mode->vsyncstart = pMode->VSyncStart;
100f29dbc25Smrg    mode->vsyncend = pMode->VSyncEnd;
101f29dbc25Smrg    mode->vblankend = pMode->VTotal;
102f29dbc25Smrg    mode->vtotal = pMode->VTotal;
103f29dbc25Smrg
104f29dbc25Smrg    mode->vactive_even = pMode->VDisplay;
105f29dbc25Smrg    mode->vblankstart_even = pMode->VDisplay;
106f29dbc25Smrg    mode->vsyncstart_even = pMode->VSyncStart;
107f29dbc25Smrg    mode->vsyncend_even = pMode->VSyncEnd;
108f29dbc25Smrg    mode->vblankend_even = pMode->VTotal;
109f29dbc25Smrg    mode->vtotal_even = pMode->VTotal;
110f29dbc25Smrg
11104007ebaSmrg    mode->frequency = (int) ((pMode->Clock / 1000.0) * 0x10000);
112f29dbc25Smrg
113f29dbc25Smrg    /* In panel mode, Cimarron purposely swizzles these,
114f29dbc25Smrg     * so we swizzle them first  */
115f29dbc25Smrg
116f29dbc25Smrg    hsync = (pMode->Flags & V_NHSYNC) ? 0 : 1;
117f29dbc25Smrg    vsync = (pMode->Flags & V_NVSYNC) ? 0 : 1;
118f29dbc25Smrg
119f29dbc25Smrg    mode->flags |= (hsync) ? VG_MODEFLAG_NEG_HSYNC : 0;
120f29dbc25Smrg    mode->flags |= (vsync) ? VG_MODEFLAG_NEG_VSYNC : 0;
121f29dbc25Smrg}
122f29dbc25Smrg
123f29dbc25Smrgstatic void
124f29dbc25Smrglx_set_crt_mode(VG_DISPLAY_MODE * mode, DisplayModePtr pMode)
125f29dbc25Smrg{
126f29dbc25Smrg    int hsync, vsync;
127f29dbc25Smrg
128f29dbc25Smrg    mode->mode_width = mode->panel_width = pMode->HDisplay;
129f29dbc25Smrg    mode->mode_height = mode->panel_height = pMode->VDisplay;
130f29dbc25Smrg
131f29dbc25Smrg    mode->hactive = pMode->CrtcHDisplay;
132f29dbc25Smrg    mode->hblankstart = pMode->CrtcHBlankStart;
133f29dbc25Smrg    mode->hsyncstart = pMode->CrtcHSyncStart;
134f29dbc25Smrg    mode->hsyncend = pMode->CrtcHSyncEnd;
135f29dbc25Smrg    mode->hblankend = pMode->CrtcHBlankEnd;
136f29dbc25Smrg    mode->htotal = pMode->CrtcHTotal;
137f29dbc25Smrg
138f29dbc25Smrg    mode->vactive = pMode->CrtcVDisplay;
139f29dbc25Smrg    mode->vblankstart = pMode->CrtcVBlankStart;
140f29dbc25Smrg    mode->vsyncstart = pMode->CrtcVSyncStart;
141f29dbc25Smrg    mode->vsyncend = pMode->CrtcVSyncEnd;
142f29dbc25Smrg    mode->vblankend = pMode->CrtcVBlankEnd;
143f29dbc25Smrg    mode->vtotal = pMode->CrtcVTotal;
144f29dbc25Smrg
145f29dbc25Smrg    mode->vactive_even = pMode->CrtcVDisplay;
146f29dbc25Smrg    mode->vblankstart_even = pMode->CrtcVBlankStart;
147f29dbc25Smrg    mode->vsyncstart_even = pMode->CrtcVSyncStart;
148f29dbc25Smrg    mode->vsyncend_even = pMode->CrtcVSyncEnd;
149f29dbc25Smrg    mode->vblankend_even = pMode->CrtcVBlankEnd;
150f29dbc25Smrg    mode->vtotal_even = pMode->CrtcVTotal;
151f29dbc25Smrg
15204007ebaSmrg    mode->frequency = (int) ((pMode->Clock / 1000.0) * 0x10000);
153f29dbc25Smrg
154f29dbc25Smrg    hsync = (pMode->Flags & V_NHSYNC) ? 1 : 0;
155f29dbc25Smrg    vsync = (pMode->Flags & V_NVSYNC) ? 1 : 0;
156f29dbc25Smrg
157f29dbc25Smrg    mode->flags |= (hsync) ? VG_MODEFLAG_NEG_HSYNC : 0;
158f29dbc25Smrg    mode->flags |= (vsync) ? VG_MODEFLAG_NEG_VSYNC : 0;
159f29dbc25Smrg}
160f29dbc25Smrg
161f29dbc25Smrgstatic int
162f29dbc25Smrglx_set_mode(ScrnInfoPtr pScrni, DisplayModePtr pMode, int bpp)
163f29dbc25Smrg{
164f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
165f29dbc25Smrg    VG_DISPLAY_MODE mode;
166f29dbc25Smrg    int ret;
167f29dbc25Smrg
168f29dbc25Smrg    memset(&mode, 0, sizeof(mode));
169f29dbc25Smrg
170f29dbc25Smrg    mode.flags |= pGeode->Output & OUTPUT_CRT ? VG_MODEFLAG_CRT_AND_FP : 0;
171f29dbc25Smrg
172f29dbc25Smrg    if (pGeode->Output & OUTPUT_PANEL) {
17304007ebaSmrg        mode.flags |= VG_MODEFLAG_PANELOUT;
17404007ebaSmrg        if (pGeode->Output & OUTPUT_CRT)
17504007ebaSmrg            mode.flags |= VG_MODEFLAG_CRT_AND_FP;
176f29dbc25Smrg    }
177f29dbc25Smrg
178f29dbc25Smrg    if (pGeode->Output & OUTPUT_PANEL && pGeode->Scale)
17904007ebaSmrg        lx_set_panel_mode(&mode, pGeode->panelMode);
180f29dbc25Smrg    else
18104007ebaSmrg        lx_set_crt_mode(&mode, pMode);
182f29dbc25Smrg
183f29dbc25Smrg    mode.src_width = pMode->HDisplay;
184f29dbc25Smrg    mode.src_height = pMode->VDisplay;
185f29dbc25Smrg
186f29dbc25Smrg    /* Set the filter coefficients to the default values */
187f29dbc25Smrg    vg_set_scaler_filter_coefficients(NULL, NULL);
188f29dbc25Smrg
189f29dbc25Smrg    ret = vg_set_custom_mode(&mode, bpp);
190f29dbc25Smrg    return (ret == CIM_STATUS_OK) ? 0 : -1;
191f29dbc25Smrg}
192f29dbc25Smrg
193f29dbc25Smrgstatic void
194f29dbc25Smrglx_crtc_dpms(xf86CrtcPtr crtc, int mode)
195f29dbc25Smrg{
196f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
197f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
198f29dbc25Smrg
199f29dbc25Smrg    if (pGeode->Output & OUTPUT_DCON)
20004007ebaSmrg        DCONDPMSSet(pScrni, mode);
201f29dbc25Smrg
202f29dbc25Smrg    switch (mode) {
203f29dbc25Smrg    case DPMSModeOn:
20404007ebaSmrg        lx_enable_dac_power(pScrni, 1);
20504007ebaSmrg        break;
206f29dbc25Smrg
207f29dbc25Smrg    case DPMSModeStandby:
20804007ebaSmrg        lx_disable_dac_power(pScrni, DF_CRT_STANDBY);
20904007ebaSmrg        break;
210f29dbc25Smrg
211f29dbc25Smrg    case DPMSModeSuspend:
21204007ebaSmrg        lx_disable_dac_power(pScrni, DF_CRT_SUSPEND);
21304007ebaSmrg        break;
214f29dbc25Smrg
215f29dbc25Smrg    case DPMSModeOff:
21604007ebaSmrg        lx_disable_dac_power(pScrni, DF_CRT_DISABLE);
21704007ebaSmrg        break;
218f29dbc25Smrg    }
219f29dbc25Smrg}
220f29dbc25Smrg
221f29dbc25Smrgstatic Bool
222f29dbc25Smrglx_crtc_lock(xf86CrtcPtr crtc)
223f29dbc25Smrg{
224f29dbc25Smrg    /* Wait until the GPU is idle */
225f29dbc25Smrg    gp_wait_until_idle();
226f29dbc25Smrg    return TRUE;
227f29dbc25Smrg}
228f29dbc25Smrg
229f29dbc25Smrgstatic void
230f29dbc25Smrglx_crtc_unlock(xf86CrtcPtr crtc)
231f29dbc25Smrg{
232f29dbc25Smrg    /* Nothing to do here */
233f29dbc25Smrg}
234f29dbc25Smrg
235f29dbc25Smrgstatic void
236f29dbc25Smrglx_crtc_prepare(xf86CrtcPtr crtc)
237f29dbc25Smrg{
238f29dbc25Smrg    LXCrtcPrivatePtr lx_crtc = crtc->driver_private;
239f29dbc25Smrg
240f29dbc25Smrg    /* Disable the video */
241f29dbc25Smrg    df_get_video_enable(&lx_crtc->video_enable, &lx_crtc->video_flags);
242f29dbc25Smrg
243f29dbc25Smrg    if (lx_crtc->video_enable)
24404007ebaSmrg        df_set_video_enable(0, 0);
245f29dbc25Smrg
246f29dbc25Smrg    /* Turn off compression */
247f29dbc25Smrg    vg_set_compression_enable(0);
248f29dbc25Smrg
249f29dbc25Smrg    /* Hide the cursor */
250f29dbc25Smrg    crtc->funcs->hide_cursor(crtc);
251f29dbc25Smrg
252f29dbc25Smrg    /* Turn off the display */
253f29dbc25Smrg    crtc->funcs->dpms(crtc, DPMSModeOff);
254f29dbc25Smrg}
255f29dbc25Smrg
256f29dbc25Smrgstatic Bool
257f29dbc25Smrglx_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
25804007ebaSmrg                   DisplayModePtr adjusted_mode)
259f29dbc25Smrg{
260f29dbc25Smrg    return TRUE;
261f29dbc25Smrg}
262f29dbc25Smrg
263f29dbc25Smrgstatic void
264f29dbc25Smrglx_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
26504007ebaSmrg                 DisplayModePtr adjusted_mode, int x, int y)
266f29dbc25Smrg{
267f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
268f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
269f29dbc25Smrg    DF_VIDEO_SOURCE_PARAMS vs_odd, vs_even;
270170d5fdcSmrg    unsigned int rpitch;
271f29dbc25Smrg
272f29dbc25Smrg    df_get_video_source_configuration(&vs_odd, &vs_even);
273f29dbc25Smrg
274f29dbc25Smrg    /* Note - the memory gets adjusted when virtualX/virtualY
275f29dbc25Smrg     * gets changed - so we don't need to worry about it here
276f29dbc25Smrg     */
277f29dbc25Smrg
278f29dbc25Smrg    if (lx_set_mode(pScrni, adjusted_mode, pScrni->bitsPerPixel))
27904007ebaSmrg        ErrorF("ERROR!  Unable to set the mode!\n");
280f29dbc25Smrg
281f29dbc25Smrg    /* The output gets turned in in the output code as
282f29dbc25Smrg     * per convention */
283f29dbc25Smrg
284170d5fdcSmrg    /* For rotation, any write to the frame buffer region marks
285170d5fdcSmrg     * the retire frame as dirty.
286170d5fdcSmrg     */
287170d5fdcSmrg    if (crtc->rotatedData != NULL) {
28804007ebaSmrg        rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8);
28904007ebaSmrg        vg_set_display_pitch(rpitch);
290170d5fdcSmrg    }
291170d5fdcSmrg    else
29204007ebaSmrg        vg_set_display_pitch(pGeode->Pitch);
293f29dbc25Smrg    gp_set_bpp(pScrni->bitsPerPixel);
294f29dbc25Smrg
295f29dbc25Smrg    /* Set the acceleration offset if we are drawing to a shadow */
296f29dbc25Smrg    if (crtc->rotatedData != NULL)
29704007ebaSmrg        vg_set_display_offset((unsigned int) ((char *) crtc->rotatedData -
29804007ebaSmrg                                              (char *) pGeode->FBBase));
299f29dbc25Smrg    else
30004007ebaSmrg        vg_set_display_offset(0);
301f29dbc25Smrg
302c744f008Smrg    /* FIXME: What's up with X and Y?  Does that come into play
303f29dbc25Smrg     * here? */
304f29dbc25Smrg
305f29dbc25Smrg    df_configure_video_source(&vs_odd, &vs_even);
306f29dbc25Smrg
307f29dbc25Smrg    vg_wait_vertical_blank();
308f29dbc25Smrg}
309f29dbc25Smrg
310f29dbc25Smrgstatic void
311f29dbc25Smrglx_crtc_commit(xf86CrtcPtr crtc)
312f29dbc25Smrg{
313f29dbc25Smrg    LXCrtcPrivatePtr lx_crtc = crtc->driver_private;
314f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
315f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
316f29dbc25Smrg
317f29dbc25Smrg    /* Turn back on the sreen */
318f29dbc25Smrg    crtc->funcs->dpms(crtc, DPMSModeOn);
319f29dbc25Smrg
320f29dbc25Smrg    /* Turn on compression */
321f29dbc25Smrg
322f29dbc25Smrg    if (pGeode->Compression) {
32304007ebaSmrg        vg_configure_compression(&(pGeode->CBData));
32404007ebaSmrg        vg_set_compression_enable(1);
325f29dbc25Smrg    }
326f29dbc25Smrg
327f29dbc25Smrg    /* Load the cursor */
328f29dbc25Smrg    if (crtc->scrn->pScreen != NULL) {
329861b9feeSmrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR
330861b9feeSmrg        xf86CursorResetCursor(crtc->scrn->pScreen);
331861b9feeSmrg#else
33204007ebaSmrg        xf86_reload_cursors(crtc->scrn->pScreen);
333861b9feeSmrg#endif
33404007ebaSmrg        crtc->funcs->hide_cursor(crtc);
33504007ebaSmrg        crtc->cursor_shown = FALSE;
336f29dbc25Smrg    }
337f29dbc25Smrg
338f29dbc25Smrg    /* Renable the video */
339f29dbc25Smrg
340f29dbc25Smrg    if (lx_crtc->video_enable)
34104007ebaSmrg        df_set_video_enable(lx_crtc->video_enable, lx_crtc->video_flags);
342f29dbc25Smrg
343f29dbc25Smrg    lx_crtc->video_enable = 0;
344f29dbc25Smrg    lx_crtc->video_flags = 0;
345f29dbc25Smrg}
346f29dbc25Smrg
347f29dbc25Smrgstatic void
34804007ebaSmrglx_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green,
34904007ebaSmrg                  CARD16 *blue, int size)
350f29dbc25Smrg{
351f29dbc25Smrg    unsigned int dcfg;
352f29dbc25Smrg    int i;
353f29dbc25Smrg
354f29dbc25Smrg    assert(size == 256);
355f29dbc25Smrg
356170d5fdcSmrg    /* We need the Gamma Correction for video - fading operation,
357170d5fdcSmrg     * the values address should be plused for every cycle.
358170d5fdcSmrg     * Special for Screensaver Operation.
359170d5fdcSmrg     */
360170d5fdcSmrg
361f29dbc25Smrg    for (i = 0; i < 256; i++) {
36204007ebaSmrg        unsigned int val;
36304007ebaSmrg
364170d5fdcSmrg        (*red) &= 0xff00;
365170d5fdcSmrg        (*green) &= 0xff00;
366170d5fdcSmrg        (*blue) &= 0xff00;
36704007ebaSmrg        val = (*(red++) << 8) | *(green++) | (*(blue++) >> 8);
368f29dbc25Smrg
36904007ebaSmrg        df_set_video_palette_entry(i, val);
370f29dbc25Smrg    }
371f29dbc25Smrg
372f29dbc25Smrg    /* df_set_video_palette_entry automatically turns on
373f29dbc25Smrg     * gamma for video - if this gets called, we assume that
374f29dbc25Smrg     * RandR wants it set for graphics, so reverse cimarron
375f29dbc25Smrg     */
376f29dbc25Smrg
377f29dbc25Smrg    dcfg = READ_VID32(DF_DISPLAY_CONFIG);
378f29dbc25Smrg    dcfg &= ~DF_DCFG_GV_PAL_BYP;
379f29dbc25Smrg    WRITE_VID32(DF_DISPLAY_CONFIG, dcfg);
380f29dbc25Smrg}
381f29dbc25Smrg
382170d5fdcSmrg    /* The Xserver has a scratch pixmap allocation routine that will
383170d5fdcSmrg     * try to use the existing scratch pixmap if possible. When the driver
384170d5fdcSmrg     * or any other user stop using it, it need to clear out any pixmap
385170d5fdcSmrg     * state (private data etc) otherwise the next user may get stale data.
386170d5fdcSmrg     */
387170d5fdcSmrg
388170d5fdcSmrg    /* Use our own wrapper to allocate a pixmap for wrapping a buffer object
389170d5fdcSmrg     * It removes using scratch pixmaps for rotate.
390170d5fdcSmrg     */
391170d5fdcSmrgstatic PixmapPtr
392170d5fdcSmrglx_create_bo_pixmap(ScreenPtr pScreen,
39304007ebaSmrg                    int width, int height,
39404007ebaSmrg                    int depth, int bpp, int pitch, pointer pPixData)
395170d5fdcSmrg{
396170d5fdcSmrg    PixmapPtr pixmap;
397170d5fdcSmrg
3987aef237fSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,0,0,0)
39904007ebaSmrg    pixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0);
4007aef237fSmrg#else
40104007ebaSmrg    pixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth);
4027aef237fSmrg#endif
4037aef237fSmrg
404170d5fdcSmrg    if (!pixmap)
40504007ebaSmrg        return NULL;
40604007ebaSmrg    if (!(*pScreen->ModifyPixmapHeader) (pixmap, width, height,
40704007ebaSmrg                                         depth, bpp, pitch, pPixData)) {
40804007ebaSmrg        /* ModifyPixmapHeader failed, so we can't use it as scratch pixmap
40904007ebaSmrg         */
41004007ebaSmrg        (*pScreen->DestroyPixmap) (pixmap);
41104007ebaSmrg        return NULL;
412170d5fdcSmrg    }
413170d5fdcSmrg
414170d5fdcSmrg    return pixmap;
415170d5fdcSmrg}
416170d5fdcSmrg
417170d5fdcSmrgstatic void
418170d5fdcSmrglx_destory_bo_pixmap(PixmapPtr pixmap)
419170d5fdcSmrg{
420170d5fdcSmrg    ScreenPtr pScreen = pixmap->drawable.pScreen;
421170d5fdcSmrg
42204007ebaSmrg    (*pScreen->DestroyPixmap) (pixmap);
423170d5fdcSmrg}
424170d5fdcSmrg
425170d5fdcSmrg    /* Allocates shadow memory, and allocating a new space for Rotation.
426170d5fdcSmrg     * The size is measured in bytes, and the offset from the beginning
427170d5fdcSmrg     * of card space is returned.
428170d5fdcSmrg     */
429170d5fdcSmrg
430170d5fdcSmrgstatic Bool
431170d5fdcSmrgLXAllocShadow(ScrnInfoPtr pScrni, int size)
432170d5fdcSmrg{
433170d5fdcSmrg    GeodeRec *pGeode = GEODEPTR(pScrni);
434170d5fdcSmrg
435170d5fdcSmrg    if (pGeode->shadowArea) {
43604007ebaSmrg        if (pGeode->shadowArea->size != size) {
43704007ebaSmrg            exaOffscreenFree(pScrni->pScreen, pGeode->shadowArea);
43804007ebaSmrg            pGeode->shadowArea = NULL;
43904007ebaSmrg        }
440170d5fdcSmrg    }
441170d5fdcSmrg
442170d5fdcSmrg    if (pGeode->shadowArea == NULL) {
44304007ebaSmrg        pGeode->shadowArea =
44404007ebaSmrg            exaOffscreenAlloc(pScrni->pScreen, size, 4, TRUE, NULL, NULL);
445170d5fdcSmrg
44604007ebaSmrg        if (pGeode->shadowArea == NULL)
44704007ebaSmrg            return FALSE;
448170d5fdcSmrg    }
449170d5fdcSmrg
450170d5fdcSmrg    pScrni->fbOffset = pGeode->shadowArea->offset;
451170d5fdcSmrg    return TRUE;
452170d5fdcSmrg}
453170d5fdcSmrg
454f29dbc25Smrgstatic void *
455f29dbc25Smrglx_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
456f29dbc25Smrg{
457f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
458f29dbc25Smrg    GeodePtr pGeode = GEODEPTR(pScrni);
459f29dbc25Smrg    unsigned int rpitch, size;
460f29dbc25Smrg
461f29dbc25Smrg    rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8);
462f29dbc25Smrg    size = rpitch * height;
463f29dbc25Smrg
464170d5fdcSmrg    /* Allocate shadow memory */
465170d5fdcSmrg    if (LXAllocShadow(pScrni, size) == FALSE) {
46604007ebaSmrg        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
46704007ebaSmrg                   "Couldn't allocate the shadow memory for rotation\n");
46804007ebaSmrg        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
46904007ebaSmrg                   " You need 0x%x bytes, but only 0x%x bytes are available\n",
47004007ebaSmrg                   size, GeodeOffscreenFreeSize(pGeode));
471f29dbc25Smrg
47204007ebaSmrg        return NULL;
473f29dbc25Smrg    }
474f29dbc25Smrg
475170d5fdcSmrg    memset(pGeode->FBBase + pGeode->shadowArea->offset, 0, size);
476170d5fdcSmrg    return pGeode->FBBase + pGeode->shadowArea->offset;
477f29dbc25Smrg}
478f29dbc25Smrg
479f29dbc25Smrgstatic PixmapPtr
480f29dbc25Smrglx_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
481f29dbc25Smrg{
482f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
483f29dbc25Smrg    PixmapPtr rpixmap;
484170d5fdcSmrg    unsigned int rpitch;
485f29dbc25Smrg
486170d5fdcSmrg    rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8);
487f29dbc25Smrg    if (!data)
48804007ebaSmrg        data = lx_crtc_shadow_allocate(crtc, width, height);
489f29dbc25Smrg
490170d5fdcSmrg    rpixmap = lx_create_bo_pixmap(pScrni->pScreen,
49104007ebaSmrg                                  width, height, pScrni->depth,
49204007ebaSmrg                                  pScrni->bitsPerPixel, rpitch, data);
493f29dbc25Smrg
494f29dbc25Smrg    if (rpixmap == NULL) {
49504007ebaSmrg        xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
49604007ebaSmrg                   "Couldn't allocate shadow pixmap for rotated CRTC\n");
497f29dbc25Smrg    }
498f29dbc25Smrg
499f29dbc25Smrg    return rpixmap;
500f29dbc25Smrg}
501f29dbc25Smrg
502f29dbc25Smrgstatic void
503f29dbc25Smrglx_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rpixmap, void *data)
504f29dbc25Smrg{
505f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
506f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
507f29dbc25Smrg
508f29dbc25Smrg    if (rpixmap)
50904007ebaSmrg        lx_destory_bo_pixmap(rpixmap);
510f29dbc25Smrg
511170d5fdcSmrg    /* Free shadow memory */
512f29dbc25Smrg    if (data) {
51304007ebaSmrg        gp_wait_until_idle();
51404007ebaSmrg        if (pGeode->shadowArea != NULL) {
51504007ebaSmrg            exaOffscreenFree(pScrni->pScreen, pGeode->shadowArea);
51604007ebaSmrg            pGeode->shadowArea = NULL;
51704007ebaSmrg        }
518f29dbc25Smrg    }
519f29dbc25Smrg}
520f29dbc25Smrg
521f29dbc25Smrgstatic void
522f29dbc25Smrglx_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
523f29dbc25Smrg{
524f29dbc25Smrg    vg_set_mono_cursor_colors(bg, fg);
525f29dbc25Smrg}
526f29dbc25Smrg
527f29dbc25Smrgstatic void
528f29dbc25Smrglx_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
529f29dbc25Smrg{
530f29dbc25Smrg    VG_PANNING_COORDINATES panning;
53104007ebaSmrg
532f29dbc25Smrg    vg_set_cursor_position(x, y, &panning);
533f29dbc25Smrg}
534f29dbc25Smrg
535f29dbc25Smrgstatic void
536f29dbc25Smrglx_crtc_show_cursor(xf86CrtcPtr crtc)
537f29dbc25Smrg{
538f29dbc25Smrg    vg_set_cursor_enable(1);
539f29dbc25Smrg}
540f29dbc25Smrg
541f29dbc25Smrgstatic void
542f29dbc25Smrglx_crtc_hide_cursor(xf86CrtcPtr crtc)
543f29dbc25Smrg{
544f29dbc25Smrg    vg_set_cursor_enable(0);
545f29dbc25Smrg}
546f29dbc25Smrg
547f29dbc25Smrgstatic void
548f29dbc25Smrglx_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
549f29dbc25Smrg{
550f29dbc25Smrg    LXLoadARGBCursorImage(crtc->scrn, (unsigned char *) image);
551f29dbc25Smrg}
552f29dbc25Smrg
553f29dbc25Smrgstatic const xf86CrtcFuncsRec lx_crtc_funcs = {
554f29dbc25Smrg    .dpms = lx_crtc_dpms,
555f29dbc25Smrg    .lock = lx_crtc_lock,
556f29dbc25Smrg    .unlock = lx_crtc_unlock,
557f29dbc25Smrg    .mode_fixup = lx_crtc_mode_fixup,
558f29dbc25Smrg    .prepare = lx_crtc_prepare,
559f29dbc25Smrg    .mode_set = lx_crtc_mode_set,
560f29dbc25Smrg    .commit = lx_crtc_commit,
561f29dbc25Smrg    .gamma_set = lx_crtc_gamma_set,
562f29dbc25Smrg    .shadow_create = lx_crtc_shadow_create,
563f29dbc25Smrg    .shadow_allocate = lx_crtc_shadow_allocate,
564f29dbc25Smrg    .shadow_destroy = lx_crtc_shadow_destroy,
565f29dbc25Smrg    .set_cursor_colors = lx_crtc_set_cursor_colors,
566f29dbc25Smrg    .set_cursor_position = lx_crtc_set_cursor_position,
567f29dbc25Smrg    .show_cursor = lx_crtc_show_cursor,
568f29dbc25Smrg    .hide_cursor = lx_crtc_hide_cursor,
569f29dbc25Smrg    .load_cursor_argb = lx_crtc_load_cursor_argb,
570f29dbc25Smrg};
571f29dbc25Smrg
572f29dbc25Smrgvoid
573f29dbc25SmrgLXSetupCrtc(ScrnInfoPtr pScrni)
574f29dbc25Smrg{
575f29dbc25Smrg    xf86CrtcPtr crtc;
576f29dbc25Smrg    LXCrtcPrivatePtr lxpriv;
577f29dbc25Smrg
578f29dbc25Smrg    crtc = xf86CrtcCreate(pScrni, &lx_crtc_funcs);
579f29dbc25Smrg
580f29dbc25Smrg    if (crtc == NULL) {
58104007ebaSmrg        ErrorF("ERROR - failed to create a CRTC\n");
58204007ebaSmrg        return;
583f29dbc25Smrg    }
584f29dbc25Smrg
58504007ebaSmrg    lxpriv = xnfcalloc(1, sizeof(LXCrtcPrivateRec));
586f29dbc25Smrg
587f29dbc25Smrg    if (!lxpriv) {
58804007ebaSmrg        xf86CrtcDestroy(crtc);
58904007ebaSmrg        ErrorF("unable to allocate memory for lxpriv\n");
59004007ebaSmrg        return;
591f29dbc25Smrg    }
592f29dbc25Smrg
593f29dbc25Smrg    crtc->driver_private = lxpriv;
594f29dbc25Smrg}
595