kolibrios/drivers/old/radeonhd/rhd_atompll.c

437 lines
12 KiB
C
Raw Permalink Normal View History

/*
* Copyright 2007, 2008 Luc Verhaegen <lverhaegen@novell.com>
* Copyright 2007, 2008 Matthias Hopf <mhopf@novell.com>
* Copyright 2007, 2008 Egbert Eich <eich@novell.com>
* Copyright 2007, 2008 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xf86.h"
/* for usleep */
#if HAVE_XF86_ANSIC_H
# include "xf86_ansic.h"
#else
# include <unistd.h>
#endif
#include "rhd.h"
#include "rhd_crtc.h"
#include "rhd_pll.h"
#include "rhd_connector.h"
#include "rhd_output.h"
#include "rhd_crtc.h"
#include "rhd_regs.h"
#if defined (ATOM_BIOS) && defined (ATOM_BIOS_PARSER)
# include "rhd_atombios.h"
# include "rhd_biosscratch.h"
struct atomPLLPrivate {
enum atomPxclk Pxclk;
struct atomPixelClockConfig Config;
struct atomCodeTableVersion Version;
CARD32 StoreFBDivFrac;
enum atomDevice StoreDevice;
enum rhdConnectorType StoreConnectorType;
enum rhdOutputType StoreOutputType;
int StoreCrtc;
};
/*
*
*/
static void
getSetPixelClockParameters(struct rhdPLL *PLL, struct atomPixelClockConfig *Config,
enum rhdConnectorType ct, enum rhdOutputType ot, enum atomDevice device)
{
RHDPtr rhdPtr = RHDPTRI(PLL);
struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private;
switch (Private->Version.cref) {
case 1:
break;
case 2:
Config->u.v2.Device = device;
Config->u.v2.Force = TRUE;
break;
case 3:
switch (ct) {
case RHD_CONNECTOR_VGA:
Config->u.v3.EncoderMode = atomNoEncoder;
break;
case RHD_CONNECTOR_DVI:
case RHD_CONNECTOR_DVI_SINGLE:
Config->u.v3.EncoderMode = atomDVI;
break;
case RHD_CONNECTOR_PANEL:
Config->u.v3.EncoderMode = atomLVDS;
break;
#if 0
case RHD_CONNECTOR_DP:
case RHD_CONNECTOR_DP_DUAL:
Config->u.v3.EncoderMode = atomDP;
break;
case RHD_CONNECTOR_HDMI_A:
case RHD_CONNECTOR_HDMI_B:
Config->u.v3.EncoderMode = atomHDMI;
break;
#endif
default:
xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: Unknown connector type: 0x%x\n",__func__,ct);
}
switch (ot) {
case RHD_OUTPUT_DACA:
Config->u.v3.OutputType = atomOutputDacA;
break;
case RHD_OUTPUT_DACB:
Config->u.v3.OutputType = atomOutputDacB;
break;
case RHD_OUTPUT_KLDSKP_LVTMA:
Config->u.v3.OutputType = atomOutputKldskpLvtma;
break;
case RHD_OUTPUT_UNIPHYA:
Config->u.v3.OutputType = atomOutputUniphyA;
break;
case RHD_OUTPUT_UNIPHYB:
Config->u.v3.OutputType = atomOutputUniphyB;
break;
case RHD_OUTPUT_UNIPHYC:
Config->u.v3.OutputType = atomOutputUniphyC;
break;
case RHD_OUTPUT_UNIPHYD:
Config->u.v3.OutputType = atomOutputUniphyD;
break;
case RHD_OUTPUT_UNIPHYE:
Config->u.v3.OutputType = atomOutputUniphyE;
break;
case RHD_OUTPUT_UNIPHYF:
Config->u.v3.OutputType = atomOutputUniphyF;
break;
case RHD_OUTPUT_DVO:
Config->u.v3.OutputType = atomOutputDvo;
break;
default:
xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: Unhandled ouptut type\n",__func__);
break;
}
Config->u.v3.Force = TRUE;
Config->u.v3.UsePpll = FALSE;
break;
default:
xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Unsupported SelectPixelClock version: %i\n",Private->Version.cref);
break;
}
}
/*
*
*/
static void
rhdAtomPLLSave(struct rhdPLL *PLL, CARD32 PllCntl, CARD32 OwnerVal)
{
RHDPtr rhdPtr = RHDPTRI(PLL);
struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private;
CARD32 Crtc1Cntl, Crtc2Cntl;
enum atomCrtc owner;
RHDFUNC(PLL);
Crtc1Cntl = RHDRegRead(PLL, PCLK_CRTC1_CNTL);
Crtc2Cntl = RHDRegRead(PLL, PCLK_CRTC2_CNTL);
if (PllCntl & 0x2)
PLL->StoreActive = FALSE;
else
PLL->StoreActive = TRUE;
if ((Crtc1Cntl & 0x00010000) == OwnerVal)
owner = atomCrtc1;
else if ((Crtc2Cntl & 0x00010000) == OwnerVal)
owner = atomCrtc2;
else {
owner = atomCrtc1; /* whatever... */
PLL->StoreActive = FALSE;
}
Private->StoreCrtc = owner;
Private->StoreDevice = RHDGetDeviceOnCrtc(rhdPtr, owner);
if (Private->StoreDevice != atomNone)
RHDFindConnectorAndOutputTypesForDevice(rhdPtr, Private->StoreDevice,
&Private->StoreOutputType, &Private->StoreConnectorType);
else
PLL->StoreActive = FALSE;
RHDDebug(PLL->scrnIndex, "Saving PLL %i on CRTC: %i %s active - device: 0x%x\n",
(PLL->Id == PLL_ID_PLL1) ? 1 : 2,
(owner == atomCrtc1) ? 1 : 2,
(PLL->StoreActive) ? "" : "not",
Private->StoreDevice);
PLL->Stored = TRUE;
/* Set parameters found at startup for shutdownInactive(). This is somewhat ugly... */
Private->Config.Crtc = Private->StoreCrtc;
Private->Config.Enable = PLL->StoreActive;
if (Private->StoreDevice != atomNone)
getSetPixelClockParameters(PLL, &Private->Config, Private->StoreConnectorType,
Private->StoreOutputType, Private->StoreDevice);
}
/*
*
*/
static void
rhdAtomPLL1Save(struct rhdPLL *PLL)
{
struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private;
CARD32 PllCntl;
RHDFUNC(PLL);
PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P1PLL_INT_SS_CNTL);
PLL->StoreRefDiv = RHDRegRead(PLL, EXT1_PPLL_REF_DIV) & 0x1FF;
PLL->StoreFBDiv = (RHDRegRead(PLL, EXT1_PPLL_FB_DIV) >> 16) & 0x7FF;
Private->StoreFBDivFrac = RHDRegRead(PLL, EXT1_PPLL_FB_DIV) & 0x7;
PLL->StorePostDiv = RHDRegRead(PLL, EXT1_PPLL_POST_DIV) & 0x3F;
PllCntl = RHDRegRead(PLL, P1PLL_CNTL);
RHDDebug(PLL->scrnIndex, "Saving %i kHz clock on PLL1\n",
((PLL->StoreFBDiv * PLL->RefClock * 10)
/ (PLL->StorePostDiv * PLL->StoreRefDiv)));
rhdAtomPLLSave(PLL, PllCntl, 0x00000000);
}
/*
*
*/
static void
rhdAtomPLL2Save(struct rhdPLL *PLL)
{
struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private;
CARD32 PllCntl;
RHDFUNC(PLL);
PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P2PLL_INT_SS_CNTL);
PLL->StoreRefDiv = RHDRegRead(PLL, EXT2_PPLL_REF_DIV) & 0x1FF;
PLL->StoreFBDiv = (RHDRegRead(PLL, EXT2_PPLL_FB_DIV) >> 16) & 0x7FF;
Private->StoreFBDivFrac = RHDRegRead(PLL, EXT2_PPLL_FB_DIV) & 0x7;
PLL->StorePostDiv = RHDRegRead(PLL, EXT2_PPLL_POST_DIV) & 0x3F;
PllCntl = RHDRegRead(PLL, P2PLL_CNTL);
RHDDebug(PLL->scrnIndex, "Saving %i kHz clock on PLL2\n",
((PLL->StoreFBDiv * PLL->RefClock * 10)
/ (PLL->StorePostDiv * PLL->StoreRefDiv)));
rhdAtomPLLSave(PLL, PllCntl, 0x00010000);
}
/*
*
*/
static void
rhdAtomPLLRestore(struct rhdPLL *PLL)
{
RHDPtr rhdPtr = RHDPTRI(PLL);
struct atomPixelClockConfig Config;
struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private;
RHDFUNC(PLL);
if (!PLL->Stored) {
xf86DrvMsg(PLL->scrnIndex, X_ERROR, "%s: %s: trying to restore "
"uninitialized values.\n", __func__, PLL->Name);
return;
}
Config.PixelClock = PLL->StoreActive
? ((PLL->StoreFBDiv * PLL->RefClock * 10) / (PLL->StorePostDiv * PLL->StoreRefDiv))
: 0;
Config.Enable = PLL->StoreActive;
Config.RefDiv = PLL->StoreRefDiv;
Config.FbDiv = PLL->StoreFBDiv;
Config.PostDiv = PLL->StorePostDiv;
Config.FracFbDiv = Private->StoreFBDivFrac;
Config.Crtc = Private->StoreCrtc;
if (Private->StoreDevice != atomNone)
getSetPixelClockParameters(PLL, &Config, Private->StoreConnectorType,
Private->StoreOutputType, Private->StoreDevice);
RHDDebug(PLL->scrnIndex, "Restoring PixelClock %i with %i kHz, (%i * %i) / ( %i * %i )"
" on CRTC %i device: %x\n",
Private->Pxclk, Config.PixelClock, PLL->RefClock, PLL->StoreFBDiv, PLL->StorePostDiv,
PLL->StoreRefDiv, (Config.Crtc == atomCrtc1) ? 1 : 2, Config.u.v2.Device);
/* Restore spread spectrum: AtomBIOS doesn't handle this for us */
RHDRegWrite(PLL, (PLL->Id == PLL_ID_PLL1) ? P1PLL_INT_SS_CNTL : P2PLL_INT_SS_CNTL, PLL->StoreSpreadSpectrum);
rhdAtomSetPixelClock(rhdPtr->atomBIOS, Private->Pxclk, &Config);
}
/*
*
*/
static void
rhdAtomPLLPower(struct rhdPLL *PLL, int Power)
{
RHDPtr rhdPtr = RHDPTRI(PLL);
struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private;
struct atomPixelClockConfig *config = &Private->Config;
RHDFUNC(PLL);
switch (Power) {
case RHD_POWER_ON:
if (config->PixelClock > 0)
config->Enable = TRUE;
else {
xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR,
"%s: cannot enable pixel clock without frequency set\n",__func__);
config->Enable = FALSE;
}
break;
case RHD_POWER_RESET:
case RHD_POWER_SHUTDOWN:
return;
config->Enable = FALSE;
default:
break;
}
rhdAtomSetPixelClock(rhdPtr->atomBIOS, Private->Pxclk, config);
}
/*
*
*/
static void
rhdAtomPLLSet(struct rhdPLL *PLL, int PixelClock, CARD16 ReferenceDivider,
CARD16 FeedbackDivider, CARD8 PostDivider)
{
RHDPtr rhdPtr = RHDPTRI(PLL);
struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private;
struct rhdCrtc *Crtc = NULL;
RHDFUNC(PLL);
RHDDebug(rhdPtr->scrnIndex, "%s: %i kHz RefDiv: %x FeedbackDiv: %x PostDiv: %x\n",
__func__, PixelClock, ReferenceDivider, FeedbackDivider, PostDivider);
Private->Config.PixelClock = PixelClock;
Private->Config.RefDiv = ReferenceDivider;
Private->Config.FbDiv = FeedbackDivider;
Private->Config.PostDiv = PostDivider;
Private->Config.FracFbDiv = 0;
if (rhdPtr->Crtc[0]->PLL == PLL) {
Private->Config.Crtc = atomCrtc1;
Crtc = rhdPtr->Crtc[0];
} else if (rhdPtr->Crtc[1]->PLL == PLL) {
Private->Config.Crtc = atomCrtc2;
Crtc = rhdPtr->Crtc[1];
} else
xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Trying to set an unassigned PLL\n");
if (Crtc && Private->Version.cref > 1) {
struct rhdOutput *Output;
for (Output = rhdPtr->Outputs; Output; Output = Output->Next) {
if (Output->Crtc == Crtc)
break;
}
if (Output)
getSetPixelClockParameters(PLL, &Private->Config,
Output->Connector->Type, Output->Id,
Output->OutputDriverPrivate->Device);
}
/* Disable spread spectrum. AtomBIOS doesn't do this for us */
RHDRegMask(PLL, (PLL->Id == PLL_ID_PLL1) ? P1PLL_INT_SS_CNTL : P2PLL_INT_SS_CNTL, 0, 0x00000001);
Private->Config.Enable = TRUE;
rhdAtomSetPixelClock(rhdPtr->atomBIOS, Private->Pxclk, &Private->Config);
}
/*
*
*/
Bool
RHDAtomPLLsInit(RHDPtr rhdPtr)
{
struct rhdPLL *PLL;
struct atomPLLPrivate *Private;
CARD32 RefClock, IntMin, IntMax, PixMin, PixMax;
int i;
RHDFUNC(rhdPtr);
RHDSetupLimits(rhdPtr, &RefClock, &IntMin, &IntMax, &PixMin, &PixMax);
for (i = 0; i < 2; i++) {
PLL = (struct rhdPLL *) xnfcalloc(sizeof(struct rhdPLL), 1);
Private = (struct atomPLLPrivate *) xnfcalloc(sizeof(struct atomPLLPrivate),1);
PLL->Private = Private;
Private->Version = rhdAtomSetPixelClockVersion(rhdPtr->atomBIOS);
if (Private->Version.cref > 3) {
xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Unsupported SelectPixelClock version; %i\n",
Private->Version.cref);
xfree(PLL->Private);
xfree(PLL);
return FALSE;
}
PLL->scrnIndex = rhdPtr->scrnIndex;
if (i == 0) {
PLL->Name = PLL_NAME_PLL1;
PLL->Id = PLL_ID_PLL1;
PLL->Save = rhdAtomPLL1Save;
Private->Pxclk = atomPclk1;
} else {
PLL->Name = PLL_NAME_PLL2;
PLL->Id = PLL_ID_PLL2;
PLL->Save = rhdAtomPLL2Save;
Private->Pxclk = atomPclk2;
}
PLL->RefClock = RefClock;
PLL->IntMin = IntMin;
PLL->IntMax = IntMax;
PLL->PixMin = PixMin;
PLL->PixMax = PixMax;
PLL->Valid = NULL;
PLL->Set = rhdAtomPLLSet;
PLL->Power = rhdAtomPLLPower;
PLL->Restore = rhdAtomPLLRestore;
rhdPtr->PLLs[i] = PLL;
}
return TRUE;
}
#endif /* ATOM_BIOS && ATOM_BIOS_PARSER */