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