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