1/* Copyright (c) 2008 Advanced Micro Devices, Inc.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 *
21 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
22 * contributors may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
24 */
25
26/* Reference: Video Graphics Suite Specification:
27 * VG Config Register (0x00) page 16
28 * VG FP Register (0x02) page 18
29 */
30
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#include <stdio.h>
36
37#include "xorg-server.h"
38
39#include "xf86.h"
40#include "compiler.h"
41#include "xf86Modes.h"
42#include "geode.h"
43
44#define LX_READ_VG(reg) \
45                (outw(0xAC1C,0xFC53), outw(0xAC1C,0x0200|(reg)), inw(0xAC1E))
46
47/* This is borrowed from xerver/hw/xfree86/modes */
48
49#define MODEPREFIX NULL, NULL, NULL, 0, M_T_DRIVER
50#define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0
51
52DisplayModeRec lx_panel_modes[] = {
53    {MODEPREFIX, 31200, 320, 354, 384, 400, 0, 240, 249, 253, 260, 0,
54     V_NHSYNC | V_NVSYNC, MODESUFFIX}
55    ,                           /* 320x200@75 */
56    {MODEPREFIX, 25175, 640, 656, 744, 800, 0, 480, 490, 492, 525, 0,
57     V_NHSYNC | V_NVSYNC, MODESUFFIX}
58    ,                           /* 640x480@60 */
59    {MODEPREFIX, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0,
60     V_NHSYNC | V_NVSYNC, MODESUFFIX}
61    ,                           /* 880x600@60 */
62    {MODEPREFIX, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0,
63     V_NHSYNC | V_NVSYNC, MODESUFFIX}
64    ,                           /* 1024x768@60 */
65    {MODEPREFIX, 81600, 1152, 1216, 1336, 1520, 0, 864, 865, 868, 895, 0,
66     V_NHSYNC | V_NVSYNC, MODESUFFIX}
67    ,                           /* 1152x864@60 */
68    {MODEPREFIX, 108000, 1280, 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
69     V_NHSYNC | V_NVSYNC, MODESUFFIX}
70    ,                           /* 1280x1024@60 */
71    {MODEPREFIX, 162000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
72     V_NHSYNC | V_NVSYNC, MODESUFFIX}
73    ,                           /* 1600x1200@60 */
74    {MODEPREFIX, 48960, 1024, 1064, 1168, 1312, 0, 600, 601, 604, 622, 0,
75     V_NHSYNC | V_NVSYNC, MODESUFFIX}
76    ,                           /* 1024x600@60 wide panels */
77};
78
79/* Get the legacy panel size from VSA, and return the associated mode rec */
80
81DisplayModePtr
82LXGetLegacyPanelMode(ScrnInfoPtr pScrni)
83{
84    unsigned short reg = LX_READ_VG(0x00);
85    unsigned char ret = (reg >> 8) & 0x07;
86
87    if ((ret == 1 || ret == 5)) {
88
89        reg = LX_READ_VG(0x02);
90        ret = (reg >> 3) & 0x07;
91
92        /* FIXME: 7 is reserved in default. We use this value to support
93         * wide screen resolution 1024x600@80 now for panel. If you want to use
94         * that resolution, please assign ret to 7 manually here:
95         * "reg = 7"
96         * The user can use this entry for other wide screen resolutions.
97         */
98
99        if (ret < 8) {
100            xf86DrvMsg(pScrni->scrnIndex, X_INFO,
101                       " VSA Panel Mode is: %dx%d, pixel clock freq(kHz) is %d\n",
102                       lx_panel_modes[ret].HDisplay,
103                       lx_panel_modes[ret].VDisplay, lx_panel_modes[ret].Clock);
104            return &lx_panel_modes[ret];
105        }
106
107    }
108
109    return NULL;
110}
111
112/* Construct a moderec from the specified panel mode */
113
114DisplayModePtr
115LXGetManualPanelMode(const char *modestr)
116{
117    int clock;
118    int hactive, hsstart, hsend, htotal;
119    int vactive, vsstart, vsend, vtotal;
120    DisplayModePtr mode;
121    char sname[32];
122
123    int ret = sscanf(modestr, "%d %d %d %d %d %d %d %d %d",
124                     &clock,
125                     &hactive, &hsstart, &hsend, &htotal,
126                     &vactive, &vsstart, &vsend, &vtotal);
127
128    if (ret != 9)
129        return NULL;
130
131    mode = xnfcalloc(1, sizeof(DisplayModeRec));
132
133    if (mode == NULL)
134        return NULL;
135
136    sprintf(sname, "%dx%d", hactive, vactive);
137
138    mode->name = xnfalloc(strlen(sname) + 1);
139    strcpy(mode->name, sname);
140
141    mode->type = M_T_DRIVER | M_T_PREFERRED;
142    mode->Clock = clock;
143    mode->HDisplay = hactive;
144    mode->HSyncStart = hsstart;
145    mode->HSyncEnd = hsend;
146    mode->HTotal = htotal;
147    mode->VDisplay = vactive;
148    mode->VSyncStart = vsstart;
149    mode->VSyncEnd = vsend;
150    mode->VTotal = vtotal;
151
152    mode->prev = mode->next = NULL;
153
154    return mode;
155}
156