lx_display.c revision f29dbc25
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
36f29dbc25Smrgtypedef struct _LXOutputPrivateRec
37f29dbc25Smrg{
38f29dbc25Smrg    int video_enable;
39f29dbc25Smrg    unsigned long video_flags;
40f29dbc25Smrg    GeodeMemPtr rotate_mem;
41f29dbc25Smrg} LXCrtcPrivateRec, *LXCrtcPrivatePtr;
42f29dbc25Smrg
43f29dbc25Smrgstatic void
44f29dbc25Smrglx_enable_dac_power(ScrnInfoPtr pScrni, int option)
45f29dbc25Smrg{
46f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
47f29dbc25Smrg
48f29dbc25Smrg    df_set_crt_enable(DF_CRT_ENABLE);
49f29dbc25Smrg
50f29dbc25Smrg    /* Turn off the DAC if we don't need the CRT */
51f29dbc25Smrg
52f29dbc25Smrg    if (option && (!(pGeode->Output & OUTPUT_CRT))) {
53f29dbc25Smrg	unsigned int misc = READ_VID32(DF_VID_MISC);
54f29dbc25Smrg
55f29dbc25Smrg	misc |= DF_DAC_POWER_DOWN;
56f29dbc25Smrg	WRITE_VID32(DF_VID_MISC, misc);
57f29dbc25Smrg    }
58f29dbc25Smrg
59f29dbc25Smrg    if (pGeode->Output & OUTPUT_PANEL)
60f29dbc25Smrg	df_set_panel_enable(1);
61f29dbc25Smrg}
62f29dbc25Smrg
63f29dbc25Smrgstatic void
64f29dbc25Smrglx_disable_dac_power(ScrnInfoPtr pScrni, int option)
65f29dbc25Smrg{
66f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
67f29dbc25Smrg
68f29dbc25Smrg    if (pGeode->Output & OUTPUT_PANEL)
69f29dbc25Smrg	df_set_panel_enable(0);
70f29dbc25Smrg
71f29dbc25Smrg    if (pGeode->Output & OUTPUT_CRT) {
72f29dbc25Smrg
73f29dbc25Smrg	/* Wait for the panel to finish its procedure */
74f29dbc25Smrg
75f29dbc25Smrg	if (pGeode->Output & OUTPUT_PANEL)
76f29dbc25Smrg	    while ((READ_VID32(DF_POWER_MANAGEMENT) & 2) == 0) ;
77f29dbc25Smrg	df_set_crt_enable(option);
78f29dbc25Smrg    }
79f29dbc25Smrg}
80f29dbc25Smrg
81f29dbc25Smrgstatic void
82f29dbc25Smrglx_set_panel_mode(VG_DISPLAY_MODE * mode, DisplayModePtr pMode)
83f29dbc25Smrg{
84f29dbc25Smrg    int hsync, vsync;
85f29dbc25Smrg
86f29dbc25Smrg    mode->mode_width = mode->panel_width = pMode->HDisplay;
87f29dbc25Smrg    mode->mode_height = mode->panel_height = pMode->VDisplay;
88f29dbc25Smrg
89f29dbc25Smrg    mode->hactive = pMode->HDisplay;
90f29dbc25Smrg    mode->hblankstart = pMode->HDisplay;
91f29dbc25Smrg    mode->hsyncstart = pMode->HSyncStart;
92f29dbc25Smrg    mode->hsyncend = pMode->HSyncEnd;
93f29dbc25Smrg    mode->hblankend = pMode->HTotal;
94f29dbc25Smrg    mode->htotal = pMode->HTotal;
95f29dbc25Smrg
96f29dbc25Smrg    mode->vactive = pMode->VDisplay;
97f29dbc25Smrg    mode->vblankstart = pMode->VDisplay;
98f29dbc25Smrg    mode->vsyncstart = pMode->VSyncStart;
99f29dbc25Smrg    mode->vsyncend = pMode->VSyncEnd;
100f29dbc25Smrg    mode->vblankend = pMode->VTotal;
101f29dbc25Smrg    mode->vtotal = pMode->VTotal;
102f29dbc25Smrg
103f29dbc25Smrg    mode->vactive_even = pMode->VDisplay;
104f29dbc25Smrg    mode->vblankstart_even = pMode->VDisplay;
105f29dbc25Smrg    mode->vsyncstart_even = pMode->VSyncStart;
106f29dbc25Smrg    mode->vsyncend_even = pMode->VSyncEnd;
107f29dbc25Smrg    mode->vblankend_even = pMode->VTotal;
108f29dbc25Smrg    mode->vtotal_even = pMode->VTotal;
109f29dbc25Smrg
110f29dbc25Smrg    mode->frequency = (int)((pMode->Clock / 1000.0) * 0x10000);
111f29dbc25Smrg
112f29dbc25Smrg    /* In panel mode, Cimarron purposely swizzles these,
113f29dbc25Smrg     * so we swizzle them first  */
114f29dbc25Smrg
115f29dbc25Smrg    hsync = (pMode->Flags & V_NHSYNC) ? 0 : 1;
116f29dbc25Smrg    vsync = (pMode->Flags & V_NVSYNC) ? 0 : 1;
117f29dbc25Smrg
118f29dbc25Smrg    mode->flags |= (hsync) ? VG_MODEFLAG_NEG_HSYNC : 0;
119f29dbc25Smrg    mode->flags |= (vsync) ? VG_MODEFLAG_NEG_VSYNC : 0;
120f29dbc25Smrg}
121f29dbc25Smrg
122f29dbc25Smrgstatic void
123f29dbc25Smrglx_set_crt_mode(VG_DISPLAY_MODE * mode, DisplayModePtr pMode)
124f29dbc25Smrg{
125f29dbc25Smrg    int hsync, vsync;
126f29dbc25Smrg
127f29dbc25Smrg    mode->mode_width = mode->panel_width = pMode->HDisplay;
128f29dbc25Smrg    mode->mode_height = mode->panel_height = pMode->VDisplay;
129f29dbc25Smrg
130f29dbc25Smrg    mode->hactive = pMode->CrtcHDisplay;
131f29dbc25Smrg    mode->hblankstart = pMode->CrtcHBlankStart;
132f29dbc25Smrg    mode->hsyncstart = pMode->CrtcHSyncStart;
133f29dbc25Smrg    mode->hsyncend = pMode->CrtcHSyncEnd;
134f29dbc25Smrg    mode->hblankend = pMode->CrtcHBlankEnd;
135f29dbc25Smrg    mode->htotal = pMode->CrtcHTotal;
136f29dbc25Smrg
137f29dbc25Smrg    mode->vactive = pMode->CrtcVDisplay;
138f29dbc25Smrg    mode->vblankstart = pMode->CrtcVBlankStart;
139f29dbc25Smrg    mode->vsyncstart = pMode->CrtcVSyncStart;
140f29dbc25Smrg    mode->vsyncend = pMode->CrtcVSyncEnd;
141f29dbc25Smrg    mode->vblankend = pMode->CrtcVBlankEnd;
142f29dbc25Smrg    mode->vtotal = pMode->CrtcVTotal;
143f29dbc25Smrg
144f29dbc25Smrg    mode->vactive_even = pMode->CrtcVDisplay;
145f29dbc25Smrg    mode->vblankstart_even = pMode->CrtcVBlankStart;
146f29dbc25Smrg    mode->vsyncstart_even = pMode->CrtcVSyncStart;
147f29dbc25Smrg    mode->vsyncend_even = pMode->CrtcVSyncEnd;
148f29dbc25Smrg    mode->vblankend_even = pMode->CrtcVBlankEnd;
149f29dbc25Smrg    mode->vtotal_even = pMode->CrtcVTotal;
150f29dbc25Smrg
151f29dbc25Smrg    mode->frequency = (int)((pMode->Clock / 1000.0) * 0x10000);
152f29dbc25Smrg
153f29dbc25Smrg    hsync = (pMode->Flags & V_NHSYNC) ? 1 : 0;
154f29dbc25Smrg    vsync = (pMode->Flags & V_NVSYNC) ? 1 : 0;
155f29dbc25Smrg
156f29dbc25Smrg    mode->flags |= (hsync) ? VG_MODEFLAG_NEG_HSYNC : 0;
157f29dbc25Smrg    mode->flags |= (vsync) ? VG_MODEFLAG_NEG_VSYNC : 0;
158f29dbc25Smrg}
159f29dbc25Smrg
160f29dbc25Smrgstatic int
161f29dbc25Smrglx_set_mode(ScrnInfoPtr pScrni, DisplayModePtr pMode, int bpp)
162f29dbc25Smrg{
163f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
164f29dbc25Smrg    VG_DISPLAY_MODE mode;
165f29dbc25Smrg    int ret;
166f29dbc25Smrg
167f29dbc25Smrg    memset(&mode, 0, sizeof(mode));
168f29dbc25Smrg
169f29dbc25Smrg    mode.flags |= pGeode->Output & OUTPUT_CRT ? VG_MODEFLAG_CRT_AND_FP : 0;
170f29dbc25Smrg
171f29dbc25Smrg    if (pGeode->Output & OUTPUT_PANEL) {
172f29dbc25Smrg	mode.flags |= VG_MODEFLAG_PANELOUT;
173f29dbc25Smrg	if (pGeode->Output & OUTPUT_CRT)
174f29dbc25Smrg	    mode.flags |= VG_MODEFLAG_CRT_AND_FP;
175f29dbc25Smrg    }
176f29dbc25Smrg
177f29dbc25Smrg    if (pGeode->Output & OUTPUT_PANEL && pGeode->Scale)
178f29dbc25Smrg	lx_set_panel_mode(&mode, pGeode->panelMode);
179f29dbc25Smrg    else
180f29dbc25Smrg	lx_set_crt_mode(&mode, pMode);
181f29dbc25Smrg
182f29dbc25Smrg    mode.src_width = pMode->HDisplay;
183f29dbc25Smrg    mode.src_height = pMode->VDisplay;
184f29dbc25Smrg
185f29dbc25Smrg    /* Set the filter coefficients to the default values */
186f29dbc25Smrg    vg_set_scaler_filter_coefficients(NULL, NULL);
187f29dbc25Smrg
188f29dbc25Smrg    ret = vg_set_custom_mode(&mode, bpp);
189f29dbc25Smrg    return (ret == CIM_STATUS_OK) ? 0 : -1;
190f29dbc25Smrg}
191f29dbc25Smrg
192f29dbc25Smrgstatic void
193f29dbc25Smrglx_crtc_dpms(xf86CrtcPtr crtc, int mode)
194f29dbc25Smrg{
195f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
196f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
197f29dbc25Smrg
198f29dbc25Smrg    if (pGeode->Output & OUTPUT_DCON)
199f29dbc25Smrg	DCONDPMSSet(pScrni, mode);
200f29dbc25Smrg
201f29dbc25Smrg    switch (mode) {
202f29dbc25Smrg    case DPMSModeOn:
203f29dbc25Smrg	lx_enable_dac_power(pScrni, 1);
204f29dbc25Smrg	break;
205f29dbc25Smrg
206f29dbc25Smrg    case DPMSModeStandby:
207f29dbc25Smrg	lx_disable_dac_power(pScrni, DF_CRT_STANDBY);
208f29dbc25Smrg	break;
209f29dbc25Smrg
210f29dbc25Smrg    case DPMSModeSuspend:
211f29dbc25Smrg	lx_disable_dac_power(pScrni, DF_CRT_SUSPEND);
212f29dbc25Smrg	break;
213f29dbc25Smrg
214f29dbc25Smrg    case DPMSModeOff:
215f29dbc25Smrg	lx_disable_dac_power(pScrni, DF_CRT_DISABLE);
216f29dbc25Smrg	break;
217f29dbc25Smrg    }
218f29dbc25Smrg}
219f29dbc25Smrg
220f29dbc25Smrgstatic Bool
221f29dbc25Smrglx_crtc_lock(xf86CrtcPtr crtc)
222f29dbc25Smrg{
223f29dbc25Smrg    /* Wait until the GPU is idle */
224f29dbc25Smrg    gp_wait_until_idle();
225f29dbc25Smrg    return TRUE;
226f29dbc25Smrg}
227f29dbc25Smrg
228f29dbc25Smrgstatic void
229f29dbc25Smrglx_crtc_unlock(xf86CrtcPtr crtc)
230f29dbc25Smrg{
231f29dbc25Smrg    /* Nothing to do here */
232f29dbc25Smrg}
233f29dbc25Smrg
234f29dbc25Smrgstatic void
235f29dbc25Smrglx_crtc_prepare(xf86CrtcPtr crtc)
236f29dbc25Smrg{
237f29dbc25Smrg    LXCrtcPrivatePtr lx_crtc = crtc->driver_private;
238f29dbc25Smrg
239f29dbc25Smrg    /* Disable the video */
240f29dbc25Smrg    df_get_video_enable(&lx_crtc->video_enable, &lx_crtc->video_flags);
241f29dbc25Smrg
242f29dbc25Smrg    if (lx_crtc->video_enable)
243f29dbc25Smrg	df_set_video_enable(0, 0);
244f29dbc25Smrg
245f29dbc25Smrg    /* Turn off compression */
246f29dbc25Smrg    vg_set_compression_enable(0);
247f29dbc25Smrg
248f29dbc25Smrg    /* Hide the cursor */
249f29dbc25Smrg    crtc->funcs->hide_cursor(crtc);
250f29dbc25Smrg
251f29dbc25Smrg    /* Turn off the display */
252f29dbc25Smrg    crtc->funcs->dpms(crtc, DPMSModeOff);
253f29dbc25Smrg}
254f29dbc25Smrg
255f29dbc25Smrgstatic Bool
256f29dbc25Smrglx_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
257f29dbc25Smrg    DisplayModePtr adjusted_mode)
258f29dbc25Smrg{
259f29dbc25Smrg    return TRUE;
260f29dbc25Smrg}
261f29dbc25Smrg
262f29dbc25Smrgstatic void
263f29dbc25Smrglx_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
264f29dbc25Smrg    DisplayModePtr adjusted_mode, int x, int y)
265f29dbc25Smrg{
266f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
267f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
268f29dbc25Smrg    DF_VIDEO_SOURCE_PARAMS vs_odd, vs_even;
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))
277f29dbc25Smrg	ErrorF("ERROR!  Unable to set the mode!\n");
278f29dbc25Smrg
279f29dbc25Smrg    /* The output gets turned in in the output code as
280f29dbc25Smrg     * per convention */
281f29dbc25Smrg
282f29dbc25Smrg    vg_set_display_pitch(pGeode->Pitch);
283f29dbc25Smrg    gp_set_bpp(pScrni->bitsPerPixel);
284f29dbc25Smrg
285f29dbc25Smrg    /* Set the acceleration offset if we are drawing to a shadow */
286f29dbc25Smrg    if (crtc->rotatedData != NULL)
287f29dbc25Smrg	vg_set_display_offset((unsigned int)((char *)crtc->rotatedData -
288f29dbc25Smrg		(char *)pGeode->FBBase));
289f29dbc25Smrg    else
290f29dbc25Smrg	vg_set_display_offset(0);
291f29dbc25Smrg
292f29dbc25Smrg    /* FIXME: Whats up with X and Y?  Does that come into play
293f29dbc25Smrg     * here? */
294f29dbc25Smrg
295f29dbc25Smrg    df_configure_video_source(&vs_odd, &vs_even);
296f29dbc25Smrg
297f29dbc25Smrg    vg_wait_vertical_blank();
298f29dbc25Smrg}
299f29dbc25Smrg
300f29dbc25Smrgstatic void
301f29dbc25Smrglx_crtc_commit(xf86CrtcPtr crtc)
302f29dbc25Smrg{
303f29dbc25Smrg    LXCrtcPrivatePtr lx_crtc = crtc->driver_private;
304f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
305f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
306f29dbc25Smrg
307f29dbc25Smrg    /* Turn back on the sreen */
308f29dbc25Smrg    crtc->funcs->dpms(crtc, DPMSModeOn);
309f29dbc25Smrg
310f29dbc25Smrg    /* Turn on compression */
311f29dbc25Smrg
312f29dbc25Smrg    if (pGeode->Compression) {
313f29dbc25Smrg	vg_configure_compression(&(pGeode->CBData));
314f29dbc25Smrg	vg_set_compression_enable(1);
315f29dbc25Smrg    }
316f29dbc25Smrg
317f29dbc25Smrg    /* Load the cursor */
318f29dbc25Smrg    if (crtc->scrn->pScreen != NULL) {
319f29dbc25Smrg	xf86_reload_cursors(crtc->scrn->pScreen);
320f29dbc25Smrg	crtc->funcs->hide_cursor(crtc);
321f29dbc25Smrg	crtc->cursor_shown = FALSE;
322f29dbc25Smrg    }
323f29dbc25Smrg
324f29dbc25Smrg    /* Renable the video */
325f29dbc25Smrg
326f29dbc25Smrg    if (lx_crtc->video_enable)
327f29dbc25Smrg	df_set_video_enable(lx_crtc->video_enable, lx_crtc->video_flags);
328f29dbc25Smrg
329f29dbc25Smrg    lx_crtc->video_enable = 0;
330f29dbc25Smrg    lx_crtc->video_flags = 0;
331f29dbc25Smrg}
332f29dbc25Smrg
333f29dbc25Smrgstatic void
334f29dbc25Smrglx_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 * red, CARD16 * green,
335f29dbc25Smrg    CARD16 * blue, int size)
336f29dbc25Smrg{
337f29dbc25Smrg    unsigned int dcfg;
338f29dbc25Smrg    int i;
339f29dbc25Smrg
340f29dbc25Smrg    assert(size == 256);
341f29dbc25Smrg
342f29dbc25Smrg    for (i = 0; i < 256; i++) {
343f29dbc25Smrg	unsigned int val = (*red << 8) | *green | (*blue >> 8);
344f29dbc25Smrg
345f29dbc25Smrg	df_set_video_palette_entry(i, val);
346f29dbc25Smrg    }
347f29dbc25Smrg
348f29dbc25Smrg    /* df_set_video_palette_entry automatically turns on
349f29dbc25Smrg     * gamma for video - if this gets called, we assume that
350f29dbc25Smrg     * RandR wants it set for graphics, so reverse cimarron
351f29dbc25Smrg     */
352f29dbc25Smrg
353f29dbc25Smrg    dcfg = READ_VID32(DF_DISPLAY_CONFIG);
354f29dbc25Smrg    dcfg &= ~DF_DCFG_GV_PAL_BYP;
355f29dbc25Smrg    WRITE_VID32(DF_DISPLAY_CONFIG, dcfg);
356f29dbc25Smrg}
357f29dbc25Smrg
358f29dbc25Smrgstatic void *
359f29dbc25Smrglx_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
360f29dbc25Smrg{
361f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
362f29dbc25Smrg    GeodePtr pGeode = GEODEPTR(pScrni);
363f29dbc25Smrg    LXCrtcPrivatePtr lx_crtc = crtc->driver_private;
364f29dbc25Smrg    unsigned int rpitch, size;
365f29dbc25Smrg
366f29dbc25Smrg    rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8);
367f29dbc25Smrg    size = rpitch * height;
368f29dbc25Smrg
369f29dbc25Smrg    lx_crtc->rotate_mem = GeodeAllocOffscreen(pGeode, size, 4);
370f29dbc25Smrg
371f29dbc25Smrg    if (lx_crtc->rotate_mem == NULL) {
372f29dbc25Smrg	xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
373f29dbc25Smrg	    "Couldn't allocate the shadow memory for rotation\n");
374f29dbc25Smrg	xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
375f29dbc25Smrg	    " You need 0x%x bytes, but only 0x%x bytes are available\n",
376f29dbc25Smrg	    size, GeodeOffscreenFreeSize(pGeode));
377f29dbc25Smrg
378f29dbc25Smrg	return NULL;
379f29dbc25Smrg    }
380f29dbc25Smrg
381f29dbc25Smrg    memset(pGeode->FBBase + lx_crtc->rotate_mem->offset, 0, size);
382f29dbc25Smrg    return pGeode->FBBase + lx_crtc->rotate_mem->offset;
383f29dbc25Smrg}
384f29dbc25Smrg
385f29dbc25Smrgstatic PixmapPtr
386f29dbc25Smrglx_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
387f29dbc25Smrg{
388f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
389f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
390f29dbc25Smrg    PixmapPtr rpixmap;
391f29dbc25Smrg
392f29dbc25Smrg    if (!data)
393f29dbc25Smrg	data = lx_crtc_shadow_allocate(crtc, width, height);
394f29dbc25Smrg
395f29dbc25Smrg    rpixmap = GetScratchPixmapHeader(pScrni->pScreen,
396f29dbc25Smrg	width, height, pScrni->depth, pScrni->bitsPerPixel, pGeode->Pitch,
397f29dbc25Smrg	data);
398f29dbc25Smrg
399f29dbc25Smrg    if (rpixmap == NULL) {
400f29dbc25Smrg	xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
401f29dbc25Smrg	    "Couldn't allocate shadow pixmap for rotated CRTC\n");
402f29dbc25Smrg    }
403f29dbc25Smrg
404f29dbc25Smrg    return rpixmap;
405f29dbc25Smrg}
406f29dbc25Smrg
407f29dbc25Smrgstatic void
408f29dbc25Smrglx_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rpixmap, void *data)
409f29dbc25Smrg{
410f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
411f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
412f29dbc25Smrg    LXCrtcPrivatePtr lx_crtc = crtc->driver_private;
413f29dbc25Smrg
414f29dbc25Smrg    if (rpixmap)
415f29dbc25Smrg	FreeScratchPixmapHeader(rpixmap);
416f29dbc25Smrg
417f29dbc25Smrg    if (data) {
418f29dbc25Smrg	gp_wait_until_idle();
419f29dbc25Smrg	GeodeFreeOffscreen(pGeode, lx_crtc->rotate_mem);
420f29dbc25Smrg	lx_crtc->rotate_mem = NULL;
421f29dbc25Smrg    }
422f29dbc25Smrg}
423f29dbc25Smrg
424f29dbc25Smrgstatic void
425f29dbc25Smrglx_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
426f29dbc25Smrg{
427f29dbc25Smrg    vg_set_mono_cursor_colors(bg, fg);
428f29dbc25Smrg}
429f29dbc25Smrg
430f29dbc25Smrgstatic void
431f29dbc25Smrglx_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
432f29dbc25Smrg{
433f29dbc25Smrg    VG_PANNING_COORDINATES panning;
434f29dbc25Smrg    vg_set_cursor_position(x, y, &panning);
435f29dbc25Smrg}
436f29dbc25Smrg
437f29dbc25Smrgstatic void
438f29dbc25Smrglx_crtc_show_cursor(xf86CrtcPtr crtc)
439f29dbc25Smrg{
440f29dbc25Smrg    vg_set_cursor_enable(1);
441f29dbc25Smrg}
442f29dbc25Smrg
443f29dbc25Smrgstatic void
444f29dbc25Smrglx_crtc_hide_cursor(xf86CrtcPtr crtc)
445f29dbc25Smrg{
446f29dbc25Smrg    vg_set_cursor_enable(0);
447f29dbc25Smrg}
448f29dbc25Smrg
449f29dbc25Smrgstatic void
450f29dbc25Smrglx_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
451f29dbc25Smrg{
452f29dbc25Smrg    LXLoadARGBCursorImage(crtc->scrn, (unsigned char *) image);
453f29dbc25Smrg}
454f29dbc25Smrg
455f29dbc25Smrgstatic const xf86CrtcFuncsRec lx_crtc_funcs = {
456f29dbc25Smrg    .dpms = lx_crtc_dpms,
457f29dbc25Smrg    .lock = lx_crtc_lock,
458f29dbc25Smrg    .unlock = lx_crtc_unlock,
459f29dbc25Smrg    .mode_fixup = lx_crtc_mode_fixup,
460f29dbc25Smrg    .prepare = lx_crtc_prepare,
461f29dbc25Smrg    .mode_set = lx_crtc_mode_set,
462f29dbc25Smrg    .commit = lx_crtc_commit,
463f29dbc25Smrg    .gamma_set = lx_crtc_gamma_set,
464f29dbc25Smrg    .shadow_create = lx_crtc_shadow_create,
465f29dbc25Smrg    .shadow_allocate = lx_crtc_shadow_allocate,
466f29dbc25Smrg    .shadow_destroy = lx_crtc_shadow_destroy,
467f29dbc25Smrg    .set_cursor_colors = lx_crtc_set_cursor_colors,
468f29dbc25Smrg    .set_cursor_position = lx_crtc_set_cursor_position,
469f29dbc25Smrg    .show_cursor = lx_crtc_show_cursor,
470f29dbc25Smrg    .hide_cursor = lx_crtc_hide_cursor,
471f29dbc25Smrg    .load_cursor_argb = lx_crtc_load_cursor_argb,
472f29dbc25Smrg};
473f29dbc25Smrg
474f29dbc25Smrgvoid
475f29dbc25SmrgLXSetupCrtc(ScrnInfoPtr pScrni)
476f29dbc25Smrg{
477f29dbc25Smrg    xf86CrtcPtr crtc;
478f29dbc25Smrg    LXCrtcPrivatePtr lxpriv;
479f29dbc25Smrg
480f29dbc25Smrg    crtc = xf86CrtcCreate(pScrni, &lx_crtc_funcs);
481f29dbc25Smrg
482f29dbc25Smrg    if (crtc == NULL) {
483f29dbc25Smrg	ErrorF("ERROR - failed to create a CRTC\n");
484f29dbc25Smrg	return;
485f29dbc25Smrg    }
486f29dbc25Smrg
487f29dbc25Smrg    lxpriv = xnfcalloc(sizeof(LXCrtcPrivateRec), 1);
488f29dbc25Smrg
489f29dbc25Smrg    if (!lxpriv) {
490f29dbc25Smrg	xf86CrtcDestroy(crtc);
491f29dbc25Smrg	ErrorF("unable to allocate memory for lxpriv\n");
492f29dbc25Smrg	return;
493f29dbc25Smrg    }
494f29dbc25Smrg
495f29dbc25Smrg    crtc->driver_private = lxpriv;
496f29dbc25Smrg}
497