Home | History | Annotate | Line # | Download | only in src
      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 #ifdef HAVE_CONFIG_H
     27 #include "config.h"
     28 #endif
     29 
     30 #include "xorg-server.h"
     31 
     32 #include "xf86.h"
     33 #include "X11/Xatom.h"
     34 #include "geode.h"
     35 #include "xf86Modes.h"
     36 #include "xf86Crtc.h"
     37 #include "cim/cim_defs.h"
     38 #include "cim/cim_regs.h"
     39 
     40 #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
     41 
     42 typedef struct _LXOutputPrivateRec {
     43     I2CBusPtr pDDCBus;
     44 } LXOutputPrivateRec, *LXOutputPrivatePtr;
     45 
     46 static Atom scale_atom;
     47 
     48 static void
     49 lx_create_resources(xf86OutputPtr output)
     50 {
     51     int ret;
     52     char *s;
     53     ScrnInfoPtr pScrni = output->scrn;
     54     GeodeRec *pGeode = GEODEPTR(pScrni);
     55 
     56     /* Scaling is only used for panels */
     57 
     58     if (!(pGeode->Output & OUTPUT_PANEL))
     59         return;
     60 
     61     scale_atom = MAKE_ATOM("scale");
     62     ret = RRConfigureOutputProperty(output->randr_output,
     63                                     scale_atom, FALSE, FALSE, FALSE, 0, NULL);
     64 
     65     if (ret) {
     66         xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
     67                    "RRConfigureOutputProperty error %d\n", ret);
     68     }
     69 
     70     s = "on";
     71     ret = RRChangeOutputProperty(output->randr_output, scale_atom,
     72                                  XA_STRING, 8, PropModeReplace, strlen(s),
     73                                  (pointer) s, FALSE, FALSE);
     74 
     75     if (ret) {
     76         xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
     77                    "RRCharOutputProperty error %d\n", ret);
     78     }
     79 }
     80 
     81 static Bool
     82 lx_output_set_property(xf86OutputPtr output, Atom property,
     83                        RRPropertyValuePtr value)
     84 {
     85     ScrnInfoPtr pScrni = output->scrn;
     86     GeodeRec *pGeode = GEODEPTR(pScrni);
     87     Bool scale = pGeode->Scale;
     88     char *s;
     89     int ret;
     90 
     91     if (property != scale_atom)
     92         return FALSE;
     93 
     94     if (value->type != XA_STRING || value->format != 8)
     95         return FALSE;
     96 
     97     s = (char *) value->data;
     98 
     99     if (value->size == 2 && !strncmp("on", s, 2))
    100         pGeode->Scale = TRUE;
    101     else if (value->size == 3 && !strncmp("off", s, 3))
    102         pGeode->Scale = FALSE;
    103 
    104     if (pGeode->Scale != scale && output->crtc) {
    105         xf86CrtcPtr crtc = output->crtc;
    106 
    107         if (crtc->enabled) {
    108             ret = xf86CrtcSetMode(crtc, &crtc->desiredMode,
    109                                   crtc->desiredRotation, crtc->desiredX,
    110                                   crtc->desiredY);
    111 
    112             if (!ret) {
    113                 xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
    114                            "Failed to set mode after property change!\n");
    115 
    116                 pGeode->Scale = scale;
    117                 return FALSE;
    118             }
    119         }
    120     }
    121 
    122     return TRUE;
    123 }
    124 
    125 static void
    126 lx_output_dpms(xf86OutputPtr output, int mode)
    127 {
    128     /* DPMS is handled by the CRTC */
    129 }
    130 
    131 static void
    132 lx_output_prepare(xf86OutputPtr output)
    133 {
    134     /* Nothing to do */
    135 }
    136 
    137 static void
    138 lx_output_commit(xf86OutputPtr output)
    139 {
    140     /* Nothing to do */
    141 }
    142 
    143 static void
    144 lx_output_save(xf86OutputPtr output)
    145 {
    146     /* Nothing to do */
    147 }
    148 
    149 static void
    150 lx_output_restore(xf86OutputPtr output)
    151 {
    152     /* Nothing to do */
    153 }
    154 
    155 static int
    156 lx_output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
    157 {
    158     ScrnInfoPtr pScrni = output->scrn;
    159     GeodeRec *pGeode = GEODEPTR(pScrni);
    160 
    161     /* DCON Panel specific resolution - OLPC's one */
    162     if (pGeode->Output & OUTPUT_DCON) {
    163         if (pGeode->panelMode->HDisplay == 1200 &&
    164             pGeode->panelMode->VDisplay == 900)
    165             return MODE_OK;
    166     }
    167 
    168     if ((pGeode->Output & OUTPUT_PANEL) &&
    169         gfx_is_panel_mode_supported(pGeode->panelMode->HDisplay,
    170                                     pGeode->panelMode->VDisplay,
    171                                     pMode->HDisplay,
    172                                     pMode->VDisplay,
    173                                     pScrni->bitsPerPixel) != -1) {
    174 
    175         return MODE_OK;
    176     }
    177 
    178     if (gfx_is_display_mode_supported(pMode->HDisplay,
    179                                       pMode->VDisplay,
    180                                       pScrni->bitsPerPixel,
    181                                       GeodeGetRefreshRate(pMode)) != -1) {
    182         return MODE_OK;
    183     }
    184 
    185     if (pMode->type & (M_T_DRIVER | M_T_PREFERRED))
    186         return MODE_OK;
    187 
    188     return MODE_OK;
    189 }
    190 
    191 static Bool
    192 lx_output_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
    193                      DisplayModePtr adjusted_mode)
    194 {
    195     return TRUE;
    196 }
    197 
    198 static void
    199 lx_output_mode_set(xf86OutputPtr output, DisplayModePtr mode,
    200                    DisplayModePtr adjusted_mode)
    201 {
    202     ScrnInfoPtr pScrni = output->scrn;
    203     GeodeRec *pGeode = GEODEPTR(pScrni);
    204 
    205     /* Configure the output path */
    206 
    207     if (pGeode->Output & OUTPUT_PANEL)
    208         df_set_output_path((pGeode->Output & OUTPUT_CRT) ?
    209                            DF_DISPLAY_CRT_FP : DF_DISPLAY_FP);
    210     else
    211         df_set_output_path(DF_DISPLAY_CRT);
    212 }
    213 
    214 static xf86OutputStatus
    215 lx_output_detect(xf86OutputPtr output)
    216 {
    217     /* We assume that there is always something
    218      * out there */
    219 
    220     return XF86OutputStatusConnected;
    221 }
    222 
    223 static DisplayModePtr
    224 lx_output_get_modes(xf86OutputPtr output)
    225 {
    226     ScrnInfoPtr pScrni = output->scrn;
    227     GeodeRec *pGeode = GEODEPTR(pScrni);
    228     LXOutputPrivatePtr lx_output = output->driver_private;
    229 
    230     xf86MonPtr mon;
    231     DisplayModePtr modes;
    232 
    233     if (!(pGeode->Output & OUTPUT_PANEL)) {
    234         mon = xf86OutputGetEDID(output, lx_output->pDDCBus);
    235         xf86OutputSetEDID(output, mon);
    236         modes = xf86OutputGetEDIDModes(output);
    237     }
    238     else {
    239         modes = xf86DuplicateMode(pGeode->panelMode);
    240     }
    241 
    242     return modes;
    243 }
    244 
    245 static void
    246 lx_output_destroy(xf86OutputPtr output)
    247 {
    248     if (output->driver_private)
    249         free(output->driver_private);
    250 
    251     output->driver_private = NULL;
    252 }
    253 
    254 #ifdef RANDR_GET_CRTC_INTERFACE
    255 static xf86CrtcPtr
    256 lx_output_get_crtc(xf86OutputPtr output)
    257 {
    258     return output->crtc;
    259 }
    260 #endif
    261 
    262 static const xf86OutputFuncsRec lx_output_funcs = {
    263     .create_resources = lx_create_resources,
    264     .dpms = lx_output_dpms,
    265     .save = lx_output_save,
    266     .restore = lx_output_restore,
    267     .mode_valid = lx_output_mode_valid,
    268     .mode_fixup = lx_output_mode_fixup,
    269     .prepare = lx_output_prepare,
    270     .mode_set = lx_output_mode_set,
    271     .commit = lx_output_commit,
    272     .detect = lx_output_detect,
    273     .get_modes = lx_output_get_modes,
    274 #ifdef RANDR_GET_CRTC_INTERFACE
    275     .get_crtc = lx_output_get_crtc,
    276 #endif
    277     .set_property = lx_output_set_property,
    278     .destroy = lx_output_destroy,
    279 };
    280 
    281 void
    282 LXSetupOutput(ScrnInfoPtr pScrni)
    283 {
    284     xf86OutputPtr output;
    285     LXOutputPrivatePtr lxpriv;
    286     GeodePtr pGeode = GEODEPTR(pScrni);
    287 
    288     output = xf86OutputCreate(pScrni, &lx_output_funcs, "default");
    289 
    290     lxpriv = xnfcalloc(1, sizeof(LXOutputPrivateRec));
    291 
    292     if (!lxpriv) {
    293         xf86OutputDestroy(output);
    294         return;
    295     }
    296 
    297     output->driver_private = lxpriv;
    298     output->interlaceAllowed = TRUE;
    299     output->doubleScanAllowed = TRUE;
    300 
    301     /* Set up the DDC bus */
    302 
    303     GeodeI2CInit(pScrni, &lxpriv->pDDCBus, "CS5536 DDC");
    304 
    305     if (pScrni->monitor->widthmm && pScrni->monitor->heightmm) {
    306         /* prioritize the admin's screen size */
    307         output->mm_width = pScrni->monitor->widthmm;
    308         output->mm_height = pScrni->monitor->heightmm;
    309     }
    310     else if (pGeode->mm_width && pGeode->mm_height) {
    311         /* if we have a panel that we're certain of the size of, set it */
    312         output->mm_width = pScrni->monitor->widthmm = pGeode->mm_width;
    313         output->mm_height = pScrni->monitor->heightmm = pGeode->mm_height;
    314     }
    315 
    316     /* We only have one CRTC, and this output is tied to it */
    317     output->possible_crtcs = 1;
    318 }
    319