lx_display.c revision 7aef237f
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;
269170d5fdcSmrg    unsigned int rpitch;
270f29dbc25Smrg
271f29dbc25Smrg    df_get_video_source_configuration(&vs_odd, &vs_even);
272f29dbc25Smrg
273f29dbc25Smrg    /* Note - the memory gets adjusted when virtualX/virtualY
274f29dbc25Smrg     * gets changed - so we don't need to worry about it here
275f29dbc25Smrg     */
276f29dbc25Smrg
277f29dbc25Smrg    if (lx_set_mode(pScrni, adjusted_mode, pScrni->bitsPerPixel))
278f29dbc25Smrg	ErrorF("ERROR!  Unable to set the mode!\n");
279f29dbc25Smrg
280f29dbc25Smrg    /* The output gets turned in in the output code as
281f29dbc25Smrg     * per convention */
282f29dbc25Smrg
283170d5fdcSmrg    /* For rotation, any write to the frame buffer region marks
284170d5fdcSmrg     * the retire frame as dirty.
285170d5fdcSmrg     */
286170d5fdcSmrg    if (crtc->rotatedData != NULL) {
287170d5fdcSmrg	rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8);
288170d5fdcSmrg	vg_set_display_pitch(rpitch);
289170d5fdcSmrg    }
290170d5fdcSmrg    else
291f29dbc25Smrg    vg_set_display_pitch(pGeode->Pitch);
292f29dbc25Smrg    gp_set_bpp(pScrni->bitsPerPixel);
293f29dbc25Smrg
294f29dbc25Smrg    /* Set the acceleration offset if we are drawing to a shadow */
295f29dbc25Smrg    if (crtc->rotatedData != NULL)
296f29dbc25Smrg	vg_set_display_offset((unsigned int)((char *)crtc->rotatedData -
297f29dbc25Smrg		(char *)pGeode->FBBase));
298f29dbc25Smrg    else
299f29dbc25Smrg	vg_set_display_offset(0);
300f29dbc25Smrg
301f29dbc25Smrg    /* FIXME: Whats up with X and Y?  Does that come into play
302f29dbc25Smrg     * here? */
303f29dbc25Smrg
304f29dbc25Smrg    df_configure_video_source(&vs_odd, &vs_even);
305f29dbc25Smrg
306f29dbc25Smrg    vg_wait_vertical_blank();
307f29dbc25Smrg}
308f29dbc25Smrg
309f29dbc25Smrgstatic void
310f29dbc25Smrglx_crtc_commit(xf86CrtcPtr crtc)
311f29dbc25Smrg{
312f29dbc25Smrg    LXCrtcPrivatePtr lx_crtc = crtc->driver_private;
313f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
314f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
315f29dbc25Smrg
316f29dbc25Smrg    /* Turn back on the sreen */
317f29dbc25Smrg    crtc->funcs->dpms(crtc, DPMSModeOn);
318f29dbc25Smrg
319f29dbc25Smrg    /* Turn on compression */
320f29dbc25Smrg
321f29dbc25Smrg    if (pGeode->Compression) {
322f29dbc25Smrg	vg_configure_compression(&(pGeode->CBData));
323f29dbc25Smrg	vg_set_compression_enable(1);
324f29dbc25Smrg    }
325f29dbc25Smrg
326f29dbc25Smrg    /* Load the cursor */
327f29dbc25Smrg    if (crtc->scrn->pScreen != NULL) {
328f29dbc25Smrg	xf86_reload_cursors(crtc->scrn->pScreen);
329f29dbc25Smrg	crtc->funcs->hide_cursor(crtc);
330f29dbc25Smrg	crtc->cursor_shown = FALSE;
331f29dbc25Smrg    }
332f29dbc25Smrg
333f29dbc25Smrg    /* Renable the video */
334f29dbc25Smrg
335f29dbc25Smrg    if (lx_crtc->video_enable)
336f29dbc25Smrg	df_set_video_enable(lx_crtc->video_enable, lx_crtc->video_flags);
337f29dbc25Smrg
338f29dbc25Smrg    lx_crtc->video_enable = 0;
339f29dbc25Smrg    lx_crtc->video_flags = 0;
340f29dbc25Smrg}
341f29dbc25Smrg
342f29dbc25Smrgstatic void
343f29dbc25Smrglx_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 * red, CARD16 * green,
344f29dbc25Smrg    CARD16 * blue, int size)
345f29dbc25Smrg{
346f29dbc25Smrg    unsigned int dcfg;
347f29dbc25Smrg    int i;
348f29dbc25Smrg
349f29dbc25Smrg    assert(size == 256);
350f29dbc25Smrg
351170d5fdcSmrg    /* We need the Gamma Correction for video - fading operation,
352170d5fdcSmrg     * the values address should be plused for every cycle.
353170d5fdcSmrg     * Special for Screensaver Operation.
354170d5fdcSmrg     */
355170d5fdcSmrg
356f29dbc25Smrg    for (i = 0; i < 256; i++) {
357170d5fdcSmrg        (*red) &= 0xff00;
358170d5fdcSmrg        (*green) &= 0xff00;
359170d5fdcSmrg        (*blue) &= 0xff00;
360170d5fdcSmrg        unsigned int val = (*(red++) << 8) | *(green++) | (*(blue++) >> 8);
361f29dbc25Smrg
362f29dbc25Smrg	df_set_video_palette_entry(i, val);
363f29dbc25Smrg    }
364f29dbc25Smrg
365f29dbc25Smrg    /* df_set_video_palette_entry automatically turns on
366f29dbc25Smrg     * gamma for video - if this gets called, we assume that
367f29dbc25Smrg     * RandR wants it set for graphics, so reverse cimarron
368f29dbc25Smrg     */
369f29dbc25Smrg
370f29dbc25Smrg    dcfg = READ_VID32(DF_DISPLAY_CONFIG);
371f29dbc25Smrg    dcfg &= ~DF_DCFG_GV_PAL_BYP;
372f29dbc25Smrg    WRITE_VID32(DF_DISPLAY_CONFIG, dcfg);
373f29dbc25Smrg}
374f29dbc25Smrg
375170d5fdcSmrg    /* The Xserver has a scratch pixmap allocation routine that will
376170d5fdcSmrg     * try to use the existing scratch pixmap if possible. When the driver
377170d5fdcSmrg     * or any other user stop using it, it need to clear out any pixmap
378170d5fdcSmrg     * state (private data etc) otherwise the next user may get stale data.
379170d5fdcSmrg     */
380170d5fdcSmrg
381170d5fdcSmrg    /* Use our own wrapper to allocate a pixmap for wrapping a buffer object
382170d5fdcSmrg     * It removes using scratch pixmaps for rotate.
383170d5fdcSmrg     */
384170d5fdcSmrgstatic PixmapPtr
385170d5fdcSmrglx_create_bo_pixmap(ScreenPtr pScreen,
386170d5fdcSmrg		int width, int height,
387170d5fdcSmrg		int depth, int bpp,
388170d5fdcSmrg		int pitch, pointer pPixData)
389170d5fdcSmrg{
390170d5fdcSmrg    PixmapPtr pixmap;
391170d5fdcSmrg
3927aef237fSmrg
3937aef237fSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,0,0,0)
394170d5fdcSmrg    pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
3957aef237fSmrg#else
3967aef237fSmrg    pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth);
3977aef237fSmrg#endif
3987aef237fSmrg
399170d5fdcSmrg    if (!pixmap)
400170d5fdcSmrg	return NULL;
401170d5fdcSmrg    if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height,
402170d5fdcSmrg					depth, bpp, pitch, pPixData)) {
403170d5fdcSmrg    /* ModifyPixmapHeader failed, so we can't use it as scratch pixmap
404170d5fdcSmrg     */
405170d5fdcSmrg	(*pScreen->DestroyPixmap)(pixmap);
406170d5fdcSmrg	return NULL;
407170d5fdcSmrg    }
408170d5fdcSmrg
409170d5fdcSmrg    return pixmap;
410170d5fdcSmrg}
411170d5fdcSmrg
412170d5fdcSmrgstatic void
413170d5fdcSmrglx_destory_bo_pixmap(PixmapPtr pixmap)
414170d5fdcSmrg{
415170d5fdcSmrg    ScreenPtr pScreen = pixmap->drawable.pScreen;
416170d5fdcSmrg
417170d5fdcSmrg    (*pScreen->DestroyPixmap)(pixmap);
418170d5fdcSmrg}
419170d5fdcSmrg
420170d5fdcSmrg    /* Allocates shadow memory, and allocating a new space for Rotation.
421170d5fdcSmrg     * The size is measured in bytes, and the offset from the beginning
422170d5fdcSmrg     * of card space is returned.
423170d5fdcSmrg     */
424170d5fdcSmrg
425170d5fdcSmrgstatic Bool
426170d5fdcSmrgLXAllocShadow(ScrnInfoPtr pScrni, int size)
427170d5fdcSmrg{
428170d5fdcSmrg    GeodeRec *pGeode = GEODEPTR(pScrni);
429170d5fdcSmrg
430170d5fdcSmrg    if (pGeode->shadowArea) {
431170d5fdcSmrg	if (pGeode->shadowArea->size != size) {
432170d5fdcSmrg		exaOffscreenFree(pScrni->pScreen, pGeode->shadowArea);
433170d5fdcSmrg		pGeode->shadowArea = NULL;
434170d5fdcSmrg	}
435170d5fdcSmrg    }
436170d5fdcSmrg
437170d5fdcSmrg    if (pGeode->shadowArea == NULL) {
438170d5fdcSmrg	pGeode->shadowArea =
439170d5fdcSmrg		exaOffscreenAlloc(pScrni->pScreen, size, 4, TRUE,
440170d5fdcSmrg		NULL, NULL);
441170d5fdcSmrg
442170d5fdcSmrg	if (pGeode->shadowArea == NULL)
443170d5fdcSmrg		return FALSE;
444170d5fdcSmrg    }
445170d5fdcSmrg
446170d5fdcSmrg    pScrni->fbOffset = pGeode->shadowArea->offset;
447170d5fdcSmrg    return TRUE;
448170d5fdcSmrg}
449170d5fdcSmrg
450f29dbc25Smrgstatic void *
451f29dbc25Smrglx_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
452f29dbc25Smrg{
453f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
454f29dbc25Smrg    GeodePtr pGeode = GEODEPTR(pScrni);
455f29dbc25Smrg    unsigned int rpitch, size;
456f29dbc25Smrg
457f29dbc25Smrg    rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8);
458f29dbc25Smrg    size = rpitch * height;
459f29dbc25Smrg
460170d5fdcSmrg    /* Allocate shadow memory */
461170d5fdcSmrg    if (LXAllocShadow(pScrni, size) == FALSE) {
462f29dbc25Smrg	xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
463f29dbc25Smrg	    "Couldn't allocate the shadow memory for rotation\n");
464f29dbc25Smrg	xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
465f29dbc25Smrg	    " You need 0x%x bytes, but only 0x%x bytes are available\n",
466f29dbc25Smrg	    size, GeodeOffscreenFreeSize(pGeode));
467f29dbc25Smrg
468f29dbc25Smrg	return NULL;
469f29dbc25Smrg    }
470f29dbc25Smrg
471170d5fdcSmrg    memset(pGeode->FBBase + pGeode->shadowArea->offset, 0, size);
472170d5fdcSmrg    return pGeode->FBBase + pGeode->shadowArea->offset;
473f29dbc25Smrg}
474f29dbc25Smrg
475f29dbc25Smrgstatic PixmapPtr
476f29dbc25Smrglx_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
477f29dbc25Smrg{
478f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
479f29dbc25Smrg    PixmapPtr rpixmap;
480170d5fdcSmrg    unsigned int rpitch;
481f29dbc25Smrg
482170d5fdcSmrg    rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8);
483f29dbc25Smrg    if (!data)
484f29dbc25Smrg	data = lx_crtc_shadow_allocate(crtc, width, height);
485f29dbc25Smrg
486170d5fdcSmrg    rpixmap = lx_create_bo_pixmap(pScrni->pScreen,
487170d5fdcSmrg	width, height, pScrni->depth, pScrni->bitsPerPixel, rpitch,
488f29dbc25Smrg	data);
489f29dbc25Smrg
490f29dbc25Smrg    if (rpixmap == NULL) {
491f29dbc25Smrg	xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
492f29dbc25Smrg	    "Couldn't allocate shadow pixmap for rotated CRTC\n");
493f29dbc25Smrg    }
494f29dbc25Smrg
495f29dbc25Smrg    return rpixmap;
496f29dbc25Smrg}
497f29dbc25Smrg
498f29dbc25Smrgstatic void
499f29dbc25Smrglx_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rpixmap, void *data)
500f29dbc25Smrg{
501f29dbc25Smrg    ScrnInfoPtr pScrni = crtc->scrn;
502f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
503f29dbc25Smrg
504f29dbc25Smrg    if (rpixmap)
505170d5fdcSmrg	lx_destory_bo_pixmap(rpixmap);
506f29dbc25Smrg
507170d5fdcSmrg    /* Free shadow memory */
508f29dbc25Smrg    if (data) {
509f29dbc25Smrg	gp_wait_until_idle();
510170d5fdcSmrg	if (pGeode->shadowArea != NULL) {
511170d5fdcSmrg	exaOffscreenFree(pScrni->pScreen, pGeode->shadowArea);
512170d5fdcSmrg	pGeode->shadowArea = NULL;
513170d5fdcSmrg	}
514f29dbc25Smrg    }
515f29dbc25Smrg}
516f29dbc25Smrg
517f29dbc25Smrgstatic void
518f29dbc25Smrglx_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
519f29dbc25Smrg{
520f29dbc25Smrg    vg_set_mono_cursor_colors(bg, fg);
521f29dbc25Smrg}
522f29dbc25Smrg
523f29dbc25Smrgstatic void
524f29dbc25Smrglx_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
525f29dbc25Smrg{
526f29dbc25Smrg    VG_PANNING_COORDINATES panning;
527f29dbc25Smrg    vg_set_cursor_position(x, y, &panning);
528f29dbc25Smrg}
529f29dbc25Smrg
530f29dbc25Smrgstatic void
531f29dbc25Smrglx_crtc_show_cursor(xf86CrtcPtr crtc)
532f29dbc25Smrg{
533f29dbc25Smrg    vg_set_cursor_enable(1);
534f29dbc25Smrg}
535f29dbc25Smrg
536f29dbc25Smrgstatic void
537f29dbc25Smrglx_crtc_hide_cursor(xf86CrtcPtr crtc)
538f29dbc25Smrg{
539f29dbc25Smrg    vg_set_cursor_enable(0);
540f29dbc25Smrg}
541f29dbc25Smrg
542f29dbc25Smrgstatic void
543f29dbc25Smrglx_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
544f29dbc25Smrg{
545f29dbc25Smrg    LXLoadARGBCursorImage(crtc->scrn, (unsigned char *) image);
546f29dbc25Smrg}
547f29dbc25Smrg
548f29dbc25Smrgstatic const xf86CrtcFuncsRec lx_crtc_funcs = {
549f29dbc25Smrg    .dpms = lx_crtc_dpms,
550f29dbc25Smrg    .lock = lx_crtc_lock,
551f29dbc25Smrg    .unlock = lx_crtc_unlock,
552f29dbc25Smrg    .mode_fixup = lx_crtc_mode_fixup,
553f29dbc25Smrg    .prepare = lx_crtc_prepare,
554f29dbc25Smrg    .mode_set = lx_crtc_mode_set,
555f29dbc25Smrg    .commit = lx_crtc_commit,
556f29dbc25Smrg    .gamma_set = lx_crtc_gamma_set,
557f29dbc25Smrg    .shadow_create = lx_crtc_shadow_create,
558f29dbc25Smrg    .shadow_allocate = lx_crtc_shadow_allocate,
559f29dbc25Smrg    .shadow_destroy = lx_crtc_shadow_destroy,
560f29dbc25Smrg    .set_cursor_colors = lx_crtc_set_cursor_colors,
561f29dbc25Smrg    .set_cursor_position = lx_crtc_set_cursor_position,
562f29dbc25Smrg    .show_cursor = lx_crtc_show_cursor,
563f29dbc25Smrg    .hide_cursor = lx_crtc_hide_cursor,
564f29dbc25Smrg    .load_cursor_argb = lx_crtc_load_cursor_argb,
565f29dbc25Smrg};
566f29dbc25Smrg
567f29dbc25Smrgvoid
568f29dbc25SmrgLXSetupCrtc(ScrnInfoPtr pScrni)
569f29dbc25Smrg{
570f29dbc25Smrg    xf86CrtcPtr crtc;
571f29dbc25Smrg    LXCrtcPrivatePtr lxpriv;
572f29dbc25Smrg
573f29dbc25Smrg    crtc = xf86CrtcCreate(pScrni, &lx_crtc_funcs);
574f29dbc25Smrg
575f29dbc25Smrg    if (crtc == NULL) {
576f29dbc25Smrg	ErrorF("ERROR - failed to create a CRTC\n");
577f29dbc25Smrg	return;
578f29dbc25Smrg    }
579f29dbc25Smrg
580f29dbc25Smrg    lxpriv = xnfcalloc(sizeof(LXCrtcPrivateRec), 1);
581f29dbc25Smrg
582f29dbc25Smrg    if (!lxpriv) {
583f29dbc25Smrg	xf86CrtcDestroy(crtc);
584f29dbc25Smrg	ErrorF("unable to allocate memory for lxpriv\n");
585f29dbc25Smrg	return;
586f29dbc25Smrg    }
587f29dbc25Smrg
588f29dbc25Smrg    crtc->driver_private = lxpriv;
589f29dbc25Smrg}
590