r128_crtc.c revision e3d74329
1/*
2 * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
3 *                VA Linux Systems Inc., Fremont, California.
4 *
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation on the rights to use, copy, modify, merge,
11 * publish, distribute, sublicense, and/or sell copies of the Software,
12 * and to permit persons to whom the Software is furnished to do so,
13 * subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial
17 * portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
23 * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <string.h>
34#include <stdio.h>
35
36#include "xf86.h"
37#include "xf86Modes.h"
38#include "X11/extensions/dpmsconst.h"
39
40#include "r128.h"
41#include "r128_probe.h"
42#include "r128_reg.h"
43
44static void r128_crtc_load_lut(xf86CrtcPtr crtc);
45
46static void r128_crtc_dpms(xf86CrtcPtr crtc, int mode)
47{
48    int mask;
49    ScrnInfoPtr pScrn = crtc->scrn;
50    R128InfoPtr info = R128PTR(pScrn);
51    unsigned char *R128MMIO = info->MMIO;
52    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
53
54    /* XXX: The HSYNC and VSYNC bits for CRTC2 don't exist on the r128? */
55    mask = r128_crtc->crtc_id ? R128_CRTC2_DISP_DIS : (R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS | R128_CRTC_VSYNC_DIS);
56
57    switch (mode) {
58    case DPMSModeOn:
59        if (r128_crtc->crtc_id) {
60            OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~mask);
61        } else {
62            OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask);
63        }
64        break;
65    case DPMSModeStandby:
66        if (r128_crtc->crtc_id) {
67            OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask);
68        } else {
69            OUTREGP(R128_CRTC_EXT_CNTL, (R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS), ~mask);
70        }
71        break;
72    case DPMSModeSuspend:
73        if (r128_crtc->crtc_id) {
74            OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask);
75        } else {
76            OUTREGP(R128_CRTC_EXT_CNTL, (R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS), ~mask);
77        }
78        break;
79    case DPMSModeOff:
80        if (r128_crtc->crtc_id) {
81            OUTREGP(R128_CRTC2_GEN_CNTL, mask, ~mask);
82        } else {
83            OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask);
84        }
85        break;
86    }
87
88    if (mode != DPMSModeOn) {
89        if (r128_crtc->crtc_id) {
90            OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_EN);
91        } else {
92            OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_EN);
93        }
94    } else {
95        if (r128_crtc->crtc_id) {
96            OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_EN, ~R128_CRTC2_EN);
97        } else {
98            OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_EN, ~R128_CRTC_EN);
99        }
100    }
101
102    if (mode != DPMSModeOff)
103        r128_crtc_load_lut(crtc);
104}
105
106void r128_crtc_load_lut(xf86CrtcPtr crtc)
107{
108    ScrnInfoPtr pScrn = crtc->scrn;
109    R128InfoPtr info = R128PTR(pScrn);
110    unsigned char *R128MMIO = info->MMIO;
111    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
112    int i;
113
114    if (!crtc->enabled)
115        return;
116
117    PAL_SELECT(r128_crtc->crtc_id);
118
119    for (i = 0; i < 256; i++) {
120        OUTPAL(i, r128_crtc->lut_r[i], r128_crtc->lut_g[i], r128_crtc->lut_b[i]);
121    }
122}
123
124static Bool r128_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode)
125{
126    return TRUE;
127}
128
129static void r128_crtc_mode_prepare(xf86CrtcPtr crtc)
130{
131    r128_crtc_dpms(crtc, DPMSModeOff);
132}
133
134static void r128_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, int x, int y)
135{
136    ScrnInfoPtr pScrn = crtc->scrn;
137    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
138    R128InfoPtr info = R128PTR(pScrn);
139    double dot_clock = adjusted_mode->Clock / 1000.0;
140
141    if (r128_crtc->cursor_offset) r128_crtc_hide_cursor(crtc);
142    xf86PrintModeline(pScrn->scrnIndex, adjusted_mode);
143    R128InitCommonRegisters(&info->ModeReg, info);
144
145    switch (r128_crtc->crtc_id) {
146    case 0:
147        R128InitCrtcRegisters(crtc, &info->ModeReg, adjusted_mode);
148	R128InitCrtcBase(crtc, &info->ModeReg, x, y);
149        if (dot_clock) {
150            R128InitPLLRegisters(crtc, &info->ModeReg, &info->pll, dot_clock);
151            R128InitDDARegisters(crtc, &info->ModeReg, &info->pll, adjusted_mode);
152        } else {
153            info->ModeReg.ppll_ref_div         = info->SavedReg.ppll_ref_div;
154            info->ModeReg.ppll_div_3           = info->SavedReg.ppll_div_3;
155            info->ModeReg.htotal_cntl          = info->SavedReg.htotal_cntl;
156            info->ModeReg.dda_config           = info->SavedReg.dda_config;
157            info->ModeReg.dda_on_off           = info->SavedReg.dda_on_off;
158        }
159        break;
160    case 1:
161        R128InitCrtc2Registers(crtc, &info->ModeReg, adjusted_mode);
162	R128InitCrtc2Base(crtc, &info->ModeReg, x, y);
163        if (dot_clock) {
164            R128InitPLL2Registers(crtc, &info->ModeReg, &info->pll, dot_clock);
165            R128InitDDA2Registers(crtc, &info->ModeReg, &info->pll, adjusted_mode);
166        }
167        break;
168    }
169
170    R128RestoreCommonRegisters(pScrn, &info->ModeReg);
171
172    switch (r128_crtc->crtc_id) {
173    case 0:
174        R128RestoreDDARegisters(pScrn, &info->ModeReg);
175        R128RestoreCrtcRegisters(pScrn, &info->ModeReg);
176        R128RestorePLLRegisters(pScrn, &info->ModeReg);
177        break;
178    case 1:
179        R128RestoreDDA2Registers(pScrn, &info->ModeReg);
180        R128RestoreCrtc2Registers(pScrn, &info->ModeReg);
181        R128RestorePLL2Registers(pScrn, &info->ModeReg);
182	break;
183    }
184
185    if (r128_crtc->cursor_offset) r128_crtc_show_cursor(crtc);
186}
187
188static void r128_crtc_mode_commit(xf86CrtcPtr crtc)
189{
190    r128_crtc_dpms(crtc, DPMSModeOn);
191}
192
193static void r128_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, uint16_t *blue, int size)
194{
195    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
196    int i;
197
198    for (i = 0; i < 256; i++) {
199        r128_crtc->lut_r[i] = red[i] >> 8;
200        r128_crtc->lut_g[i] = green[i] >> 8;
201        r128_crtc->lut_b[i] = blue[i] >> 8;
202    }
203
204    r128_crtc_load_lut(crtc);
205}
206
207static Bool r128_crtc_lock(xf86CrtcPtr crtc)
208{
209    ScrnInfoPtr   pScrn   = crtc->scrn;
210    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
211    R128InfoPtr   info    = R128PTR(pScrn);
212
213#ifdef HAVE_XAA_H
214    if (info->accel) info->accel->Sync(pScrn);
215#endif
216#ifdef USE_EXA
217    if (info->ExaDriver) exaWaitSync(pScreen);
218#endif
219
220    return FALSE;
221}
222
223static void r128_crtc_unlock(xf86CrtcPtr crtc)
224{
225    ScrnInfoPtr   pScrn   = crtc->scrn;
226    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
227    R128InfoPtr   info    = R128PTR(pScrn);
228
229#ifdef HAVE_XAA_H
230    if (info->accel) info->accel->Sync(pScrn);
231#endif
232#ifdef USE_EXA
233    if (info->ExaDriver) exaWaitSync(pScreen);
234#endif
235}
236
237static void *r128_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
238{
239    ScrnInfoPtr   pScrn   = crtc->scrn;
240    R128InfoPtr   info    = R128PTR(pScrn);
241
242    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
243    unsigned long rotate_offset = 0;
244    unsigned long rotate_pitch;
245    int cpp = pScrn->bitsPerPixel / 8;
246    int align = 4096;
247    int size;
248
249    rotate_pitch = pScrn->displayWidth * cpp;
250    size = rotate_pitch * height;
251    rotate_offset = R128AllocateMemory(pScrn, &(r128_crtc->rotate_mem), size, align, TRUE);
252
253    /* If allocations failed or if there was no accel. */
254    if (rotate_offset == 0)
255        return NULL;
256
257    return info->FB + rotate_offset;
258}
259
260static PixmapPtr r128_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
261{
262    ScrnInfoPtr pScrn = crtc->scrn;
263    PixmapPtr rotate_pixmap;
264    unsigned long rotate_pitch;
265    int cpp = pScrn->bitsPerPixel / 8;
266
267    if (!data) data = r128_crtc_shadow_allocate(crtc, width, height);
268
269    rotate_pitch = pScrn->displayWidth * cpp;
270    rotate_pixmap = GetScratchPixmapHeader(xf86ScrnToScreen(pScrn),
271                                           width, height,
272                                           pScrn->depth,
273                                           pScrn->bitsPerPixel,
274                                           rotate_pitch,
275                                           data);
276
277    if (rotate_pixmap == NULL) {
278        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
279                   "Couldn't allocate shadow memory for rotated CRTC\n");
280        return NULL;
281    }
282
283    return rotate_pixmap;
284}
285
286static void r128_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
287{
288    ScrnInfoPtr   pScrn   = crtc->scrn;
289    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
290    R128InfoPtr   info    = R128PTR(pScrn);
291
292    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
293
294    if (rotate_pixmap) FreeScratchPixmapHeader(rotate_pixmap);
295
296    if (data && r128_crtc->rotate_mem != NULL) {
297#ifdef USE_EXA
298        if (info->ExaDriver)
299            exaOffscreenFree(pScreen, (ExaOffscreenArea *) r128_crtc->rotate_mem);
300#endif
301#ifdef HAVE_XAA_H
302        if (info->accel)
303            xf86FreeOffscreenLinear((FBLinearPtr) r128_crtc->rotate_mem);
304#endif
305        r128_crtc->rotate_mem = NULL;
306    }
307}
308
309static const xf86CrtcFuncsRec r128_crtc_funcs = {
310    .dpms = r128_crtc_dpms,
311    .save = NULL,
312    .restore = NULL,
313    .mode_fixup = r128_crtc_mode_fixup,
314    .prepare = r128_crtc_mode_prepare,
315    .mode_set = r128_crtc_mode_set,
316    .commit = r128_crtc_mode_commit,
317    .gamma_set = r128_crtc_gamma_set,
318    .lock = r128_crtc_lock,
319    .unlock = r128_crtc_unlock,
320    .shadow_create = r128_crtc_shadow_create,
321    .shadow_allocate = r128_crtc_shadow_allocate,
322    .shadow_destroy = r128_crtc_shadow_destroy,
323    .set_cursor_colors = r128_crtc_set_cursor_colors,
324    .set_cursor_position = r128_crtc_set_cursor_position,
325    .show_cursor = r128_crtc_show_cursor,
326    .hide_cursor = r128_crtc_hide_cursor,
327    .load_cursor_image = r128_crtc_load_cursor_image,
328    .destroy = NULL,
329};
330
331Bool R128AllocateControllers(ScrnInfoPtr pScrn)
332{
333    R128EntPtr pR128Ent = R128EntPriv(pScrn);
334
335    if (pR128Ent->Controller[0])
336        return TRUE;
337
338    pR128Ent->pCrtc[0] = xf86CrtcCreate(pScrn, &r128_crtc_funcs);
339    if (!pR128Ent->pCrtc[0])
340        return FALSE;
341
342    pR128Ent->Controller[0] = xnfcalloc(sizeof(R128CrtcPrivateRec), 1);
343    if (!pR128Ent->Controller[0])
344        return FALSE;
345
346    pR128Ent->pCrtc[0]->driver_private = pR128Ent->Controller[0];
347    pR128Ent->Controller[0]->crtc_id = 0;
348
349    if (!pR128Ent->HasCRTC2)
350        return TRUE;
351
352    pR128Ent->pCrtc[1] = xf86CrtcCreate(pScrn, &r128_crtc_funcs);
353    if (!pR128Ent->pCrtc[1])
354        return FALSE;
355
356    pR128Ent->Controller[1] = xnfcalloc(sizeof(R128CrtcPrivateRec), 1);
357    if (!pR128Ent->Controller[1]) {
358        free(pR128Ent->Controller[0]);
359        return FALSE;
360    }
361
362    pR128Ent->pCrtc[1]->driver_private = pR128Ent->Controller[1];
363    pR128Ent->Controller[1]->crtc_id = 1;
364
365    return TRUE;
366}
367
368void R128Blank(ScrnInfoPtr pScrn)
369{
370    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
371    xf86OutputPtr output;
372    xf86CrtcPtr crtc;
373    int o, c;
374
375    for (c = 0; c < xf86_config->num_crtc; c++) {
376        crtc = xf86_config->crtc[c];
377        for (o = 0; o < xf86_config->num_output; o++) {
378            output = xf86_config->output[o];
379            if (output->crtc != crtc)
380                continue;
381
382            output->funcs->dpms(output, DPMSModeOff);
383        }
384        crtc->funcs->dpms(crtc, DPMSModeOff);
385    }
386}
387
388void R128Unblank(ScrnInfoPtr pScrn)
389{
390    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
391    xf86OutputPtr output;
392    xf86CrtcPtr crtc;
393    int o, c;
394
395    for (c = 0; c < xf86_config->num_crtc; c++) {
396        crtc = xf86_config->crtc[c];
397        if (!crtc->enabled)
398            continue;
399        crtc->funcs->dpms(crtc, DPMSModeOn);
400        for (o = 0; o < xf86_config->num_output; o++) {
401            output = xf86_config->output[o];
402            if (output->crtc != crtc)
403                continue;
404
405            output->funcs->dpms(output, DPMSModeOn);
406        }
407    }
408}
409