Home | History | Annotate | Line # | Download | only in src
      1 /**************************************************************************
      2 
      3 Copyright 2006 Dave Airlie <airlied (at) linux.ie>
      4 
      5 All Rights Reserved.
      6 
      7 Permission is hereby granted, free of charge, to any person obtaining a
      8 copy of this software and associated documentation files (the "Software"),
      9 to deal in the Software without restriction, including without limitation
     10 on the rights to use, copy, modify, merge, publish, distribute, sub
     11 license, and/or sell copies of the Software, and to permit persons to whom
     12 the Software is furnished to do so, subject to the following conditions:
     13 The above copyright notice and this permission notice (including the next
     14 paragraph) shall be included in all copies or substantial portions of the
     15 Software.
     16 
     17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     20 THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
     21 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     22 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     23 USE OR OTHER DEALINGS IN THE SOFTWARE.
     24 
     25 ******
     26 ********************************************************************/
     27 
     28 #ifdef HAVE_CONFIG_H
     29 #include "config.h"
     30 #endif
     31 
     32 #include "xf86.h"
     33 #include "i830.h"
     34 #include "i830_display.h"
     35 #include "i810_reg.h"
     36 
     37 #include "sil164/sil164.h"
     38 #include "ch7xxx/ch7xxx.h"
     39 #include "tfp410/tfp410.h"
     40 
     41 /* driver list */
     42 static struct _I830DVODriver i830_dvo_drivers[] =
     43 {
     44     {
     45 	.type = I830_OUTPUT_DVO_TMDS,
     46 	.modulename = "sil164",
     47 	.fntablename = "SIL164VidOutput",
     48 	.dvo_reg = DVOC,
     49 	.address = (SIL164_ADDR_1<<1),
     50     },
     51     {
     52 	.type = I830_OUTPUT_DVO_TMDS,
     53 	.modulename = "ch7xxx",
     54 	.fntablename = "CH7xxxVidOutput",
     55 	.dvo_reg = DVOC,
     56 	.address = (CH7xxx_ADDR_1<<1),
     57     },
     58     {
     59 	.type = I830_OUTPUT_DVO_LVDS,
     60 	.modulename = "ivch",
     61 	.fntablename = "ivch_methods",
     62 	.dvo_reg = DVOA,
     63 	.address = 0x04, /* Might also be 0x44, 0x84, 0xc4 */
     64     },
     65     {
     66 	.type = I830_OUTPUT_DVO_TMDS,
     67 	.modulename = "tfp410",
     68 	.fntablename = "TFP410VidOutput",
     69 	.dvo_reg = DVOC,
     70 	.address = (TFP410_ADDR_1<<1),
     71     },
     72     {
     73 	.type = I830_OUTPUT_DVO_LVDS,
     74 	.modulename = "ch7017",
     75 	.fntablename = "ch7017_methods",
     76 	.dvo_reg = DVOC,
     77 	.address = 0xea,
     78 	.gpio = GPIOE,
     79     }
     80 };
     81 
     82 #define I830_NUM_DVO_DRIVERS (sizeof(i830_dvo_drivers)/sizeof(struct _I830DVODriver))
     83 
     84 static void
     85 i830_dvo_dpms(xf86OutputPtr output, int mode)
     86 {
     87     ScrnInfoPtr		    pScrn = output->scrn;
     88     I830Ptr		    pI830 = I830PTR(pScrn);
     89     I830OutputPrivatePtr    intel_output = output->driver_private;
     90     struct _I830DVODriver   *drv = intel_output->i2c_drv;
     91     void *		    dev_priv = drv->dev_priv;
     92     unsigned int	    dvo_reg = drv->dvo_reg;
     93 
     94     if (mode == DPMSModeOn) {
     95 	OUTREG(dvo_reg, INREG(dvo_reg) | DVO_ENABLE);
     96 	POSTING_READ(dvo_reg);
     97 	(*intel_output->i2c_drv->vid_rec->dpms)(dev_priv, mode);
     98     } else {
     99 	(*intel_output->i2c_drv->vid_rec->dpms)(dev_priv, mode);
    100 	OUTREG(dvo_reg, INREG(dvo_reg) & ~DVO_ENABLE);
    101 	POSTING_READ(dvo_reg);
    102     }
    103 }
    104 
    105 static void
    106 i830_dvo_save(xf86OutputPtr output)
    107 {
    108     ScrnInfoPtr		    pScrn = output->scrn;
    109     I830Ptr		    pI830 = I830PTR(pScrn);
    110     I830OutputPrivatePtr    intel_output = output->driver_private;
    111     void *		    dev_priv = intel_output->i2c_drv->dev_priv;
    112 
    113     /* Each output should probably just save the registers it touches, but for
    114      * now, use more overkill.
    115      */
    116     pI830->saveDVOA = INREG(DVOA);
    117     pI830->saveDVOB = INREG(DVOB);
    118     pI830->saveDVOC = INREG(DVOC);
    119 
    120     (*intel_output->i2c_drv->vid_rec->save)(dev_priv);
    121 }
    122 
    123 static void
    124 i830_dvo_restore(xf86OutputPtr output)
    125 {
    126     ScrnInfoPtr		    pScrn = output->scrn;
    127     I830Ptr		    pI830 = I830PTR(pScrn);
    128     I830OutputPrivatePtr    intel_output = output->driver_private;
    129     void *		    dev_priv = intel_output->i2c_drv->dev_priv;
    130 
    131     (*intel_output->i2c_drv->vid_rec->restore)(dev_priv);
    132 
    133     OUTREG(DVOA, pI830->saveDVOA);
    134     OUTREG(DVOB, pI830->saveDVOB);
    135     OUTREG(DVOC, pI830->saveDVOC);
    136 }
    137 
    138 static int
    139 i830_dvo_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
    140 {
    141     ScrnInfoPtr		    pScrn = output->scrn;
    142     I830Ptr		    pI830 = I830PTR(pScrn);
    143     I830OutputPrivatePtr    intel_output = output->driver_private;
    144     void		    *dev_priv = intel_output->i2c_drv->dev_priv;
    145 
    146     if (pMode->Flags & V_DBLSCAN)
    147 	return MODE_NO_DBLESCAN;
    148 
    149     /* XXX: Validate clock range */
    150 
    151     if (pI830->lvds_fixed_mode) {
    152 	if (pMode->HDisplay > pI830->lvds_fixed_mode->HDisplay)
    153 	    return MODE_PANEL;
    154 	if (pMode->VDisplay > pI830->lvds_fixed_mode->VDisplay)
    155 	    return MODE_PANEL;
    156     }
    157 
    158     return intel_output->i2c_drv->vid_rec->mode_valid(dev_priv, pMode);
    159 }
    160 
    161 static Bool
    162 i830_dvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
    163 		    DisplayModePtr adjusted_mode)
    164 {
    165     ScrnInfoPtr		    pScrn = output->scrn;
    166     I830Ptr		    pI830 = I830PTR(pScrn);
    167     I830OutputPrivatePtr    intel_output = output->driver_private;
    168 
    169     /* If we have timings from the BIOS for the panel, put them in
    170      * to the adjusted mode.  The CRTC will be set up for this mode,
    171      * with the panel scaling set up to source from the H/VDisplay
    172      * of the original mode.
    173      */
    174     if (pI830->lvds_fixed_mode != NULL) {
    175 	adjusted_mode->HDisplay = pI830->lvds_fixed_mode->HDisplay;
    176 	adjusted_mode->HSyncStart = pI830->lvds_fixed_mode->HSyncStart;
    177 	adjusted_mode->HSyncEnd = pI830->lvds_fixed_mode->HSyncEnd;
    178 	adjusted_mode->HTotal = pI830->lvds_fixed_mode->HTotal;
    179 	adjusted_mode->VDisplay = pI830->lvds_fixed_mode->VDisplay;
    180 	adjusted_mode->VSyncStart = pI830->lvds_fixed_mode->VSyncStart;
    181 	adjusted_mode->VSyncEnd = pI830->lvds_fixed_mode->VSyncEnd;
    182 	adjusted_mode->VTotal = pI830->lvds_fixed_mode->VTotal;
    183 	adjusted_mode->Clock = pI830->lvds_fixed_mode->Clock;
    184 	xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V);
    185     }
    186 
    187     if (intel_output->i2c_drv->vid_rec->mode_fixup)
    188 	return intel_output->i2c_drv->vid_rec->mode_fixup (intel_output->i2c_drv->dev_priv,
    189 							   mode, adjusted_mode);
    190     return TRUE;
    191 }
    192 
    193 static void
    194 i830_dvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
    195 		  DisplayModePtr adjusted_mode)
    196 {
    197     ScrnInfoPtr		    pScrn = output->scrn;
    198     I830Ptr		    pI830 = I830PTR(pScrn);
    199     xf86CrtcPtr	    crtc = output->crtc;
    200     I830CrtcPrivatePtr	    intel_crtc = crtc->driver_private;
    201     I830OutputPrivatePtr    intel_output = output->driver_private;
    202     struct _I830DVODriver   *drv = intel_output->i2c_drv;
    203     int			    pipe = intel_crtc->pipe;
    204     uint32_t		    dvo;
    205     unsigned int	    dvo_reg = drv->dvo_reg, dvo_srcdim_reg;
    206     int			    dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
    207 
    208     switch (dvo_reg) {
    209     case DVOA:
    210     default:
    211 	dvo_srcdim_reg = DVOA_SRCDIM;
    212 	break;
    213     case DVOB:
    214 	dvo_srcdim_reg = DVOB_SRCDIM;
    215 	break;
    216     case DVOC:
    217 	dvo_srcdim_reg = DVOC_SRCDIM;
    218 	break;
    219     }
    220 
    221     intel_output->i2c_drv->vid_rec->mode_set(intel_output->i2c_drv->dev_priv,
    222 					     mode, adjusted_mode);
    223 
    224     /* Save the data order, since I don't know what it should be set to. */
    225     dvo = INREG(dvo_reg) & (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
    226     dvo |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE | DVO_BLANK_ACTIVE_HIGH;
    227 
    228     if (pipe == 1)
    229 	dvo |= DVO_PIPE_B_SELECT;
    230     dvo |= DVO_PIPE_STALL;
    231     if (adjusted_mode->Flags & V_PHSYNC)
    232 	dvo |= DVO_HSYNC_ACTIVE_HIGH;
    233     if (adjusted_mode->Flags & V_PVSYNC)
    234 	dvo |= DVO_VSYNC_ACTIVE_HIGH;
    235 
    236     OUTREG(dpll_reg, INREG(dpll_reg) | DPLL_DVO_HIGH_SPEED);
    237 
    238     /*OUTREG(DVOB_SRCDIM,
    239       (adjusted_mode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
    240       (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
    241     OUTREG(dvo_srcdim_reg,
    242 	   (adjusted_mode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
    243 	   (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));
    244     /*OUTREG(DVOB, dvo);*/
    245     OUTREG(dvo_reg, dvo);
    246 }
    247 
    248 /**
    249  * Detect the output connection on our DVO device.
    250  *
    251  * Unimplemented.
    252  */
    253 static xf86OutputStatus
    254 i830_dvo_detect(xf86OutputPtr output)
    255 {
    256     I830OutputPrivatePtr    intel_output = output->driver_private;
    257     void *dev_priv = intel_output->i2c_drv->dev_priv;
    258 
    259     return intel_output->i2c_drv->vid_rec->detect(dev_priv);
    260 }
    261 
    262 static DisplayModePtr
    263 i830_dvo_get_modes(xf86OutputPtr output)
    264 {
    265     ScrnInfoPtr	pScrn = output->scrn;
    266     I830Ptr pI830 = I830PTR(pScrn);
    267     I830OutputPrivatePtr    intel_output = output->driver_private;
    268     DisplayModePtr	    modes;
    269 
    270     /* We should probably have an i2c driver get_modes function for those
    271      * devices which will have a fixed set of modes determined by the chip
    272      * (TV-out, for example), but for now with just TMDS and LVDS, that's not
    273      * the case.
    274      */
    275     modes = i830_ddc_get_modes(output);
    276     if (modes != NULL)
    277 	return modes;
    278 
    279     if (intel_output->i2c_drv->vid_rec->get_modes)
    280     {
    281 	modes = intel_output->i2c_drv->vid_rec->get_modes (intel_output->i2c_drv->dev_priv);
    282 	if (modes != NULL)
    283 	    return modes;
    284     }
    285 
    286     if (pI830->lvds_fixed_mode != NULL)
    287 	return xf86DuplicateMode(pI830->lvds_fixed_mode);
    288 
    289     return NULL;
    290 }
    291 
    292 static void
    293 i830_dvo_destroy (xf86OutputPtr output)
    294 {
    295     I830OutputPrivatePtr    intel_output = output->driver_private;
    296 
    297     if (intel_output)
    298     {
    299 	if (intel_output->i2c_drv->vid_rec->destroy)
    300 	    intel_output->i2c_drv->vid_rec->destroy (intel_output->i2c_drv->dev_priv);
    301 	if (intel_output->pI2CBus)
    302 	    xf86DestroyI2CBusRec (intel_output->pI2CBus, TRUE, TRUE);
    303 	if (intel_output->pDDCBus)
    304 	    xf86DestroyI2CBusRec (intel_output->pDDCBus, TRUE, TRUE);
    305 	xfree (intel_output);
    306     }
    307 }
    308 
    309 #ifdef RANDR_GET_CRTC_INTERFACE
    310 static xf86CrtcPtr
    311 i830_dvo_get_crtc(xf86OutputPtr output)
    312 {
    313     ScrnInfoPtr	pScrn = output->scrn;
    314     I830Ptr pI830 = I830PTR(pScrn);
    315     I830OutputPrivatePtr intel_output = output->driver_private;
    316     struct _I830DVODriver *drv = intel_output->i2c_drv;
    317     int pipe = !!(INREG(drv->dvo_reg) & SDVO_PIPE_B_SELECT);
    318 
    319     return i830_pipe_to_crtc(pScrn, pipe);
    320 }
    321 #endif
    322 
    323 static const xf86OutputFuncsRec i830_dvo_output_funcs = {
    324     .dpms = i830_dvo_dpms,
    325     .save = i830_dvo_save,
    326     .restore = i830_dvo_restore,
    327     .mode_valid = i830_dvo_mode_valid,
    328     .mode_fixup = i830_dvo_mode_fixup,
    329     .prepare = i830_output_prepare,
    330     .mode_set = i830_dvo_mode_set,
    331     .commit = i830_output_commit,
    332     .detect = i830_dvo_detect,
    333     .get_modes = i830_dvo_get_modes,
    334     .destroy = i830_dvo_destroy,
    335 #ifdef RANDR_GET_CRTC_INTERFACE
    336     .get_crtc = i830_dvo_get_crtc,
    337 #endif
    338 };
    339 
    340 /**
    341  * Attempts to get a fixed panel timing for LVDS (currently only the i830).
    342  *
    343  * Other chips with DVO LVDS will need to extend this to deal with the LVDS
    344  * chip being on DVOB/C and having multiple pipes.
    345  */
    346 static DisplayModePtr
    347 i830_dvo_get_current_mode (xf86OutputPtr output)
    348 {
    349     ScrnInfoPtr		    pScrn = output->scrn;
    350     I830OutputPrivatePtr    intel_output = output->driver_private;
    351     I830Ptr		    pI830 = I830PTR(pScrn);
    352     struct _I830DVODriver   *drv = intel_output->i2c_drv;
    353     unsigned int	    dvo_reg = drv->dvo_reg;
    354     uint32_t		    dvo = INREG(dvo_reg);
    355     DisplayModePtr    	    mode = NULL;
    356 
    357     /* If the DVO port is active, that'll be the LVDS, so we can pull out
    358      * its timings to get how the BIOS set up the panel.
    359      */
    360     if (dvo & DVO_ENABLE)
    361     {
    362 	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
    363 	int		    pipe = (dvo & DVO_PIPE_B_SELECT) ? 1 : 0;
    364 	int		    c;
    365 
    366 	for (c = 0; c < xf86_config->num_crtc; c++)
    367 	{
    368 	    xf86CrtcPtr		crtc = xf86_config->crtc[c];
    369 	    I830CrtcPrivatePtr	intel_crtc = crtc->driver_private;
    370 
    371 	    if (intel_crtc->pipe == pipe)
    372 	    {
    373 		mode = i830_crtc_mode_get(pScrn, crtc);
    374 
    375 		if (mode)
    376 		{
    377 		    mode->type |= M_T_PREFERRED;
    378 
    379 		    if (dvo & DVO_HSYNC_ACTIVE_HIGH)
    380 			mode->Flags |= V_PHSYNC;
    381 		    if (dvo & DVO_VSYNC_ACTIVE_HIGH)
    382 			mode->Flags |= V_PVSYNC;
    383 		}
    384 		break;
    385 	    }
    386 	}
    387     }
    388     return mode;
    389 }
    390 
    391 void
    392 i830_dvo_init(ScrnInfoPtr pScrn)
    393 {
    394     I830Ptr pI830 = I830PTR(pScrn);
    395     I830OutputPrivatePtr intel_output;
    396     int ret;
    397     int i;
    398     void *ret_ptr;
    399     struct _I830DVODriver *drv;
    400     int gpio_inited = 0;
    401     I2CBusPtr pI2CBus = NULL;
    402 
    403     intel_output = xnfcalloc (sizeof (I830OutputPrivateRec), 1);
    404     if (!intel_output)
    405 	return;
    406 
    407     /* Set up the DDC bus */
    408     ret = I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOD, "DVODDC_D");
    409     if (!ret) {
    410 	xfree(intel_output);
    411 	return;
    412     }
    413 
    414     /* Now, try to find a controller */
    415     for (i = 0; i < I830_NUM_DVO_DRIVERS; i++) {
    416 	int gpio;
    417 
    418 	drv = &i830_dvo_drivers[i];
    419 	drv->modhandle = xf86LoadSubModule(pScrn, drv->modulename);
    420 	if (drv->modhandle == NULL)
    421 	    continue;
    422 
    423 	ret_ptr = NULL;
    424 	drv->vid_rec = LoaderSymbol(drv->fntablename);
    425 
    426 	if (!strcmp(drv->modulename, "ivch") &&
    427 	    pI830->quirk_flag & QUIRK_IVCH_NEED_DVOB) {
    428 	    drv->dvo_reg = DVOB;
    429 	}
    430 
    431 	/* Allow the I2C driver info to specify the GPIO to be used in
    432 	 * special cases, but otherwise default to what's defined in the spec.
    433 	 */
    434 	if (drv->gpio != 0)
    435 	    gpio = drv->gpio;
    436 	else if (drv->type == I830_OUTPUT_DVO_LVDS)
    437 	    gpio = GPIOB;
    438 	else
    439 	    gpio = GPIOE;
    440 
    441 	/* Set up the I2C bus necessary for the chip we're probing.  It appears
    442 	 * that everything is on GPIOE except for panels on i830 laptops, which
    443 	 * are on GPIOB (DVOA).
    444 	 */
    445 	if (gpio_inited != gpio) {
    446 	    if (pI2CBus != NULL)
    447 		xf86DestroyI2CBusRec(pI2CBus, TRUE, TRUE);
    448 	    if (!I830I2CInit(pScrn, &pI2CBus, gpio,
    449 			     gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E")) {
    450 		continue;
    451 	    }
    452 	}
    453 
    454 	if (drv->vid_rec != NULL)
    455 	    ret_ptr = drv->vid_rec->init(pI2CBus, drv->address);
    456 
    457 	if (ret_ptr != NULL) {
    458 	    xf86OutputPtr output = NULL;
    459 
    460 	    intel_output->type = drv->type;
    461 	    switch (drv->type) {
    462 	    case I830_OUTPUT_DVO_TMDS:
    463 		intel_output->pipe_mask = ((1 << 0) | (1 << 1));
    464 		intel_output->clone_mask = ((1 << I830_OUTPUT_ANALOG) |
    465 					    (1 << I830_OUTPUT_DVO_TMDS));
    466 		output = xf86OutputCreate(pScrn, &i830_dvo_output_funcs,
    467 					  "TMDS");
    468 		break;
    469 	    case I830_OUTPUT_DVO_LVDS:
    470 		intel_output->pipe_mask = ((1 << 0) | (1 << 1));
    471 		intel_output->clone_mask = (1 << I830_OUTPUT_DVO_LVDS);
    472 		output = xf86OutputCreate(pScrn, &i830_dvo_output_funcs,
    473 					  "LVDS");
    474 		break;
    475 	    case I830_OUTPUT_DVO_TVOUT:
    476 		intel_output->pipe_mask = ((1 << 0) | (1 << 1));
    477 		intel_output->clone_mask = (1 << I830_OUTPUT_DVO_TVOUT);
    478 		output = xf86OutputCreate(pScrn, &i830_dvo_output_funcs,
    479 					  "TV");
    480 		break;
    481 	    }
    482 	    if (output == NULL) {
    483 		xf86DestroyI2CBusRec(pI2CBus, TRUE, TRUE);
    484 		xf86DestroyI2CBusRec(intel_output->pDDCBus, TRUE, TRUE);
    485 		xfree(intel_output);
    486 		xf86UnloadSubModule(drv->modhandle);
    487 		return;
    488 	    }
    489 
    490 	    output->driver_private = intel_output;
    491 	    output->subpixel_order = SubPixelHorizontalRGB;
    492 	    output->interlaceAllowed = FALSE;
    493 	    output->doubleScanAllowed = FALSE;
    494 
    495 	    drv->dev_priv = ret_ptr;
    496 	    intel_output->i2c_drv = drv;
    497 	    intel_output->pI2CBus = pI2CBus;
    498 
    499 	    if (intel_output->type == I830_OUTPUT_DVO_LVDS) {
    500 		/* For our LVDS chipsets, we should hopefully be able to
    501 		 * dig the fixed panel mode out of the BIOS data.  However,
    502 		 * it's in a different format from the BIOS data on chipsets
    503 		 * with integrated LVDS (stored in AIM headers, liekly),
    504 		 * so for now, just get the current mode being output through
    505 		 * DVO.
    506 		 */
    507 		pI830->lvds_fixed_mode = i830_dvo_get_current_mode(output);
    508 		pI830->lvds_dither = TRUE;
    509 	    }
    510 
    511 	    return;
    512 	}
    513 	xf86UnloadSubModule(drv->modhandle);
    514     }
    515 
    516     /* Didn't find a chip, so tear down. */
    517     if (pI2CBus != NULL)
    518 	xf86DestroyI2CBusRec(pI2CBus, TRUE, TRUE);
    519     xf86DestroyI2CBusRec(intel_output->pDDCBus, TRUE, TRUE);
    520     xfree(intel_output);
    521 }
    522