#include "asm/avalanche/sangam/sangam_clk_cntl.h" #include #include #include /***************************************************************************** * Debug *****************************************************************************/ //#define CDebugClock //#define CDebugClockCalcSteps //#define CDebugGpio6Output /***************************************************************************** * Debug *****************************************************************************/ #if defined(CDebugClock) //#define DBGCLK(...) prom_printf(__VA_ARGS__) #define DBGCLK(...) printk(__VA_ARGS__) #else /* defined(CDebugClock) */ #define DBGCLK(...) #endif /* defined(CDebugClock) */ /***************************************************************************** * Funktionen *****************************************************************************/ #define ABS(x) (((signed)(x) > 0) ? (x) : (-(x))) #define CEIL(x,y) (((x) + (y) / 2) / (y)) /***************************************************************************** * Adressen *****************************************************************************/ #define CClock_RegisterBase(ClockId) (AVALANCHE_CLOCK_CONTROL_BASE + ClkControllOffset[ClockId]) #define CClock_PllscrRegAdr(ClockId) (CClock_RegisterBase(ClockId) + 0x00) #define CClock_PllmRegAdr(ClockId) (CClock_RegisterBase(ClockId) + 0x10) #define CClock_PreDivRegAdr(ClockId) (CClock_RegisterBase(ClockId) + 0x14) #define CClock_PostDivRegAdr(ClockId) (CClock_RegisterBase(ClockId) + 0x18) #define CClock_PllCmdRegAdr(ClockId) (CClock_RegisterBase(ClockId) + 0x38) #define CClock_PllStatRegAdr(ClockId) (CClock_RegisterBase(ClockId) + 0x3c) #define CClock_PllCmdEnRegAdr(ClockId)(CClock_RegisterBase(ClockId) + 0x40) /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ #define MClock_IsOhioChip() ((REG32_DATA(0xA8610914) & 0xffff) == 0x2b) /***************************************************************************** * Registermasken PLLM, PREDIV und POSTDIV *****************************************************************************/ #define CClock_PreDivRegRatioMask 0x0000001f #define CClock_PostDivRegRatioMask 0x0000001f #define CClock_PreDivRegPreDivEnBit (1 << 15) #define CClock_PostDivRegPostDivEnBit (1 << 15) #define CClock_PllmRegMultiplicatorMask 0x0000000f /***************************************************************************** * Bits *****************************************************************************/ #define CClock_PllStatRegGostatBit 0x01 #define CClock_PllCmdEnRegGosetBit 0x01 #define CClock_PllCmdRegGosetBit 0x01 #define CClock_PllscrRegPllEnBit 0x01 /***************************************************************************** * Registermasken AVALANCHE_DCL_BOOTCR *****************************************************************************/ #define CClock_BootCrPllBypassBit (1 << 5) #define CClock_BootCrMipsAsyncBit (1 << 25) #define CClock_BootCrMips2To1Bit (1 << 15) /***************************************************************************** * Registermasken VSERCLKSELR *****************************************************************************/ #define CClock_VSerClkSelR_Ohio250ModeBit (1 << 8) #define CClock_VSerClkSelR_VlynqClkSel211MhzBit (1 << 0) /***************************************************************************** * Erlaubte Frequenzbereiche 1..Max *****************************************************************************/ #define CClock_MinFrequency CLK_MHZ(1) #define CClock_SysMaxFrequency2To1 CLK_MHZ(106) #define CClock_SysMaxFrequencyAsyncOr2To1 CLK_MHZ(125) #define CClock_MipsMaxFrequencyAsyncOr2To1 CLK_MHZ(212) #define CClock_MipsMaxFrequencySync CLK_MHZ(125) #define CClock_UsbMaxFrequency CLK_MHZ(48) #define CClock_AdslssMaxFrequency CLK_MHZ(250) /***************************************************************************** * *****************************************************************************/ #define CClock_DividerLockTime 10100 /***************************************************************************** * *****************************************************************************/ #define KSEG1_BASE 0xa0000000 #ifndef KSEG_INV_MASK #define KSEG_INV_MASK 0x1FFFFFFF /* Inverted mask for kseg address */ #endif /***************************************************************************** * *****************************************************************************/ #ifndef PHYS_ADDR #define PHYS_ADDR(addr) ((addr) & KSEG_INV_MASK) #endif /***************************************************************************** * *****************************************************************************/ #ifndef PHYS_TO_K1 #define PHYS_TO_K1(addr) (PHYS_ADDR(addr)|KSEG1_BASE) #endif /***************************************************************************** * *****************************************************************************/ #ifndef REG32_ADDR #define REG32_ADDR(addr) (volatile unsigned int *)(PHYS_TO_K1(addr)) #define REG32_DATA(addr) (*(volatile unsigned int *)(PHYS_TO_K1(addr))) #define REG32_WRITE(addr, data) REG32_DATA(addr) = data; #define REG32_READ(addr, data) data = (unsigned int) REG32_DATA(addr); #endif /*-------------------------------------------------------------------------*\ * Forward References \*-------------------------------------------------------------------------*/ typedef enum { CClock_OhioMips = 0, CClock_OhioSys = 1, CClock_OhioUsb = 2, CClock_OhioVBus = 3, /* pseudo */ CClock_OhioAdslss = 4, CClock_OhioCountIds = 5, /*--- letzter, nicht wirklich vorhanden ---*/ } TClock_OhioIds; /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ typedef struct { UINT32 Multiplier; UINT32 PreDivider; UINT32 PostDivider; UINT32 BaseFrequency; UINT32 OutputFrequency; } TClockOhioInfo; /*-------------------------------------------------------------------------*\ * PRIVATE Variables \*-------------------------------------------------------------------------*/ static UINT32 InitialBaseFrequency[CClock_OhioCountIds]; static unsigned int ClkControllOffset[CClock_OhioCountIds]; /*-------------------------------------------------------------------------*\ * Forward References \*-------------------------------------------------------------------------*/ static unsigned int GetDividerFromPll(TClock_OhioIds OhioClockId); /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ #if defined(CDebugClock) static char *ShowInt ( UINT32 Value ) { /* 6*3 Stellig + (6-1) Dezimalpunkte + \0 */ static char OutBuffer[10][(6*3) + (6-1) + 1]; static unsigned Current = 0; char *Next; unsigned Stellen; if (Value == 0) { return "0"; } Next = &OutBuffer[Current++][sizeof(OutBuffer[0]) - 1]; if (Current >= 10) { Current = 0; } *Next = '\0'; Stellen = 0; while (Value > 0) { Next--; *Next = (Value % 10) + '0'; if ((++Stellen == 3) && (Value > 9)) { Next--; *Next = '.'; Stellen = 0; } Value /= 10; } return Next; } #endif /* defined(CDebugClock) */ /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ #if defined(CDebugClock) static char *OhioClockIdName ( TClock_OhioIds OhioClockId ) { switch (OhioClockId) { case CClock_OhioMips : return "Mips"; case CClock_OhioSys : return "Sys"; case CClock_OhioUsb : return "Usb"; case CClock_OhioVBus : return "VBus"; case CClock_OhioAdslss : return "Adslss"; default : return "???"; } } #endif /* defined(CDebugClock) */ /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ static TClock_OhioIds ExternToInternClkId ( AVALANCHE_CLKC_ID_T clk_id ) { switch (clk_id) { case CLKC_MIPS : return CClock_OhioMips; case CLKC_USB : return CClock_OhioUsb; case CLKC_SYS : return CClock_OhioSys; case CLKC_VBUS : return CClock_OhioVBus; case CLKC_ADSLSS : return CClock_OhioAdslss; default : return 0; } } /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ static void GetMulDivValue ( TClockOhioInfo *Info, unsigned int MinPostDivider, unsigned int MaxPostDivider ) { #define CClock_MinInFrequencyApll CLK_MHZ(8) #define CClock_MaxInFrequencyApll CLK_MHZ(200) TClockOhioInfo Fixed; TClockOhioInfo Current; TClockOhioInfo Best; Fixed.OutputFrequency = Info->OutputFrequency; Fixed.BaseFrequency = Info->BaseFrequency; Best.PreDivider = CLK_MHZ(1); Best.Multiplier = CLK_MHZ(1); Best.PostDivider = CLK_MHZ(1); Best.OutputFrequency = Fixed.BaseFrequency; for (Current.PreDivider = 1; Current.PreDivider <= CClock_PreDivRegRatioMask; Current.PreDivider++) { for (Current.Multiplier = 1; Current.Multiplier <= CClock_PllmRegMultiplicatorMask; Current.Multiplier++) { for ( Current.PostDivider = MinPostDivider; Current.PostDivider <= MaxPostDivider; Current.PostDivider++ ) { Current.OutputFrequency = CEIL(Fixed.BaseFrequency, Current.PreDivider); /* 5.13 / 29: Inputfrequenz für Apll in 8..200 */ if ( (Current.OutputFrequency < CClock_MinInFrequencyApll) || (Current.OutputFrequency > CClock_MaxInFrequencyApll) ) { continue; } Current.OutputFrequency = CEIL ((Current.OutputFrequency * Current.Multiplier), Current.PostDivider); if ( ABS(Fixed.OutputFrequency - Current.OutputFrequency) < ABS(Fixed.OutputFrequency - Best.OutputFrequency) ) { Best.PreDivider = Current.PreDivider; Best.Multiplier = Current.Multiplier; Best.PostDivider = Current.PostDivider; Best.OutputFrequency = Current.OutputFrequency; /* Der exakte Wert gerade ermittelt ? */ if (Best.OutputFrequency == Fixed.OutputFrequency) { /* Das wars dann */ Info->PreDivider = Best.PreDivider; Info->Multiplier = Best.Multiplier; Info->PostDivider = Best.PostDivider; #if defined(CDebugClockCalcSteps) DBGCLK ( "%s->%s: Exact gefunden=%s*%s/%s BestFreq=%s Probe=%s\n", ShowInt(Fixed.BaseFrequency), ShowInt(Fixed.OutputFrequency), ShowInt(Best.PreDivider), ShowInt(Best.Multiplier), ShowInt(Best.PostDivider), ShowInt(Best.OutputFrequency), ShowInt (CEIL((Fixed.OutputFrequency * Best.PostDivider), Best.Multiplier) * Best.PreDivider) ); #endif /* defined(CDebugClock) */ return; } #if defined(CDebugClockCalcSteps) DBGCLK ( "Vorläufig bestes Ergebnis..%s->%s: Best=%s*%s/%s BestFreq=%s Probe=%s\n", ShowInt(Fixed.BaseFrequency), ShowInt(Fixed.OutputFrequency), ShowInt(Best.PreDivider), ShowInt(Best.Multiplier), ShowInt(Best.PostDivider), ShowInt(Best.OutputFrequency), ShowInt(CEIL((Fixed.OutputFrequency * Best.PostDivider), Best.Multiplier) * Best.PreDivider) ); #endif /* defined(CDebugClock) */ } } } } #if defined(CDebugClockCalcSteps) DBGCLK ( "%s->%s: Best=%s*%s/%s BestFreq=%s Probe=%s\n", ShowInt(Fixed.BaseFrequency), ShowInt(Fixed.OutputFrequency), ShowInt(Best.PreDivider), ShowInt(Best.Multiplier), ShowInt(Best.PostDivider), ShowInt(Best.OutputFrequency), ShowInt(CEIL((Fixed.OutputFrequency * Best.PostDivider), Best.Multiplier) * Best.PreDivider) ); #endif /* defined(CDebugClock) */ Info->PreDivider = Best.PreDivider; Info->Multiplier = Best.Multiplier; Info->PostDivider = Best.PostDivider; #undef CClock_MinInFrequencyApll #undef CClock_MaxInFrequencyApll } /*-------------------------------------------------------------------------*\ * The above routine is called to get base frequency of the clocks. \*-------------------------------------------------------------------------*/ static unsigned int GetBaseFrequency ( TClock_OhioIds OhioClockId ) { if (OhioClockId >= CClock_OhioCountIds) { DBGCLK("GetBaseFrequency OhioClockId=%d >= CClock_OhioCountIds\n", OhioClockId); return 0; } switch (OhioClockId) { case CClock_OhioMips : return InitialBaseFrequency[CClock_OhioMips]; case CClock_OhioSys : case CClock_OhioAdslss : return InitialBaseFrequency[CClock_OhioSys]; case CClock_OhioUsb : return GetDividerFromPll(CClock_OhioSys); case CClock_OhioVBus : return InitialBaseFrequency[CClock_OhioSys] / 2; default : return 0; } } /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ static unsigned int GetDividerFromPll ( TClock_OhioIds OhioClockId ) { unsigned int BaseFrequency; unsigned int PreDiv; unsigned int PostDiv; unsigned int Divider; unsigned int Multiplier; DBGCLK("GetDividerFromPll enter. ClockId=%s\n", OhioClockIdName(OhioClockId)); BaseFrequency = GetBaseFrequency(OhioClockId); DBGCLK("GetDividerFromPll Read POSTDIV(%p)\n", (char *) CClock_PostDivRegAdr(OhioClockId)); PostDiv = REG32_DATA(CClock_PostDivRegAdr(OhioClockId)); /* POSTDIV enabled ? */ if (CClock_PostDivRegPostDivEnBit & PostDiv) { Divider = (CClock_PostDivRegRatioMask & PostDiv) + 1; } else { Divider = 1; } DBGCLK ( "GetDividerFromPll Postdiv=%s(+1) -> Divider=%s Check Bypass DCL_BOOTCR(%p) PostDivEnable=%x\n", ShowInt(CClock_PostDivRegRatioMask & PostDiv), ShowInt(Divider), (char *) AVALANCHE_DCL_BOOTCR, CClock_PostDivRegPostDivEnBit == (CClock_PostDivRegPostDivEnBit & PostDiv) ); /* Zugriff auf PREDIV und PLLM nur bei PLLCSR(PLLEN)=0. Pin DCL(PLL_BYPASS) steuert PLLCSR(PLLEN). */ if (CClock_BootCrPllBypassBit & REG32_DATA(AVALANCHE_DCL_BOOTCR)) { DBGCLK ( "GetDividerFromPll leave bypass BaseFreq=%s PostDiv=%s(+1) Divider=%s Return=%s\n", ShowInt(BaseFrequency), ShowInt(CClock_PostDivRegRatioMask & PostDiv), ShowInt(Divider), ShowInt(CEIL(BaseFrequency, Divider)) ); return CEIL(BaseFrequency, Divider); } DBGCLK("GetDividerFromPll Read PREDIV(%p)\n", (char *) CClock_PreDivRegAdr(OhioClockId)); PreDiv = ( (CClock_PreDivRegRatioMask | CClock_PreDivRegPreDivEnBit) & REG32_DATA(CClock_PreDivRegAdr(OhioClockId)) ) + 1; if (CClock_PreDivRegPreDivEnBit & PreDiv) { Divider *= (CClock_PreDivRegRatioMask & PreDiv); } DBGCLK ( "GetDividerFromPll PreDiv=%s PreDivEnable=%x\n", ShowInt(CClock_PreDivRegRatioMask & PreDiv), CClock_PreDivRegPreDivEnBit == (CClock_PreDivRegPreDivEnBit & PreDiv) ); DBGCLK("GetDividerFromPll Read PLLM(%p)\n", (char *) CClock_PllmRegAdr(OhioClockId)); /* Get the PLL multiplication factor */ Multiplier = (CClock_PllmRegMultiplicatorMask & REG32_DATA(CClock_PllmRegAdr(OhioClockId))) + 1; DBGCLK ( "GetDividerFromPll leave BaseFreq=%s [PreDiv=%s Multiplier=%s PostDiv=%s(+1)] -> Divider=%s Return=%s\n", ShowInt(BaseFrequency), ShowInt(CClock_PreDivRegRatioMask & PreDiv), ShowInt(Multiplier), ShowInt(CClock_PostDivRegRatioMask & PostDiv), ShowInt(Divider), ShowInt(CEIL((BaseFrequency * Multiplier), Divider)) ); return CEIL((BaseFrequency * Multiplier), Divider); } /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ static void SetOhioClockPll ( TClockOhioInfo *Info, TClock_OhioIds OhioClockId ) { volatile unsigned int TimeIndex; UINT32 PllscrRegister; DBGCLK ( "SetOhioClockPll enter. ClockId=%s PreDivider=%s Multiplier=%s PostDivider=%s\n", OhioClockIdName(OhioClockId), ShowInt(Info->PreDivider), ShowInt(Info->Multiplier), ShowInt(Info->PostDivider) ); if (CClock_OhioVBus == OhioClockId) { DBGCLK("SetOhioClockPll VBus: DRAM to hold mode\n"); /* but before writing put DRAM to hold mode */ REG32_DATA(AVALANCHE_EMIF_SDRAM_CFG) |= 0x80000000; } DBGCLK("SetOhioClockPll Disable PLLSCR(%p)\n", (char *) CClock_PllscrRegAdr(OhioClockId)); /* disable Pll 18.2.5 /63 */ REG32_WRITE(CClock_PllscrRegAdr(OhioClockId), 0); DBGCLK ( "SetOhioClockPll Prediv(%p)=%s(d) | 0x%x ablegen\n", (char *) CClock_PreDivRegAdr(OhioClockId), ShowInt(CClock_PreDivRegRatioMask & (Info->PreDivider - 1)), CClock_PreDivRegPreDivEnBit ); /* prediv ablegen 18.2.7 / 64 */ REG32_WRITE ( CClock_PreDivRegAdr(OhioClockId), (CClock_PreDivRegRatioMask & (Info->PreDivider - 1)) | CClock_PreDivRegPreDivEnBit ); DBGCLK ( "SetOhioClockPll PLLM(%p)=Multiplier=%s ablegen\n", (char *) CClock_PllmRegAdr(OhioClockId), ShowInt(CClock_PllmRegMultiplicatorMask & (Info->Multiplier - 1)) ); /* mult ablegen 18.2.6 / 64 */ REG32_WRITE(CClock_PllmRegAdr(OhioClockId), CClock_PllmRegMultiplicatorMask & (Info->Multiplier - 1)); /* wait for divider output to stabilise */ for (TimeIndex = 0; TimeIndex < CClock_DividerLockTime; TimeIndex++); DBGCLK("SetOhioClockPll Warte bis GOSET-Bit in PLLSTAT(%p)=0\n", (char *) CClock_PllStatRegAdr(OhioClockId)); /* warte bis GOSET-Bit=0. Ist 1 solange PLL output clock arbeitet. 18.2.10 / 66 */ while (CClock_PllStatRegGostatBit & REG32_DATA(CClock_PllStatRegAdr(OhioClockId))); DBGCLK ( "SetOhioClockPll PostDiv(%p)=%s(d) | 0x%x ablegen\n", (char *) CClock_PostDivRegAdr(OhioClockId), ShowInt((Info->PostDivider - 1) & CClock_PostDivRegRatioMask), CClock_PostDivRegPostDivEnBit ); /* PostDivider ablegen 18.2.8 / 65 */ REG32_WRITE ( CClock_PostDivRegAdr(OhioClockId), ((Info->PostDivider - 1) & CClock_PostDivRegRatioMask) | CClock_PostDivRegPostDivEnBit ); DBGCLK("SetOhioClockPll PLLCMDEN(%p)=0x01 (GOSET-Bit)\n", (char *) CClock_PllCmdEnRegAdr(OhioClockId)); /* set GOSET-Bit in PLLCMDEN-Register 18.2.11 / 66 */ REG32_WRITE(CClock_PllCmdEnRegAdr(OhioClockId), CClock_PllCmdEnRegGosetBit); /* set GOSET-Bit in PLLCMD-Register 18.2.9 / 65 */ DBGCLK ("SetOhioClockPll PLLCMD(%p)=0x01 (GOSET-Bit)\n", (char *) CClock_PllCmdRegAdr(OhioClockId)); REG32_WRITE(CClock_PllCmdRegAdr(OhioClockId), CClock_PllCmdRegGosetBit); DBGCLK ( "SetOhioClockPll Warte bis GOSET-Bit in PLLSTAT(%p)=0\n", (char *) CClock_PllStatRegAdr(OhioClockId) ); /* warte bis GOSET-Bit=0. Ist 1 solange PLL output clock arbeitet. 18.2.10 / 66 */ while (CClock_PllStatRegGostatBit & REG32_DATA(CClock_PllStatRegAdr(OhioClockId))); DBGCLK ("SetOhioClockPll Read PLLSCR(%p) für PLL-Enable\n", (char *) CClock_PllscrRegAdr(OhioClockId)); /* enable Pll 18.2.5 /63 */ PllscrRegister = REG32_DATA(CClock_PllscrRegAdr(OhioClockId)); DBGCLK ( "SetOhioClockPll Enable PLL in PLLSCR(%p) mit %x | 0x01\n", (char *) CClock_PllscrRegAdr(OhioClockId), PllscrRegister ); /* enable Pll 18.2.5 /63 */ REG32_WRITE(CClock_PllscrRegAdr(OhioClockId), CClock_PllscrRegPllEnBit | PllscrRegister); DBGCLK("SetOhioClockPll Done Enable PLL\n"); if (OhioClockId == CClock_OhioVBus) { DBGCLK("SetOhioClockPll VBus: DRAM out of hold mode\n"); /* Bring DRAM out of hold */ REG32_DATA(AVALANCHE_EMIF_SDRAM_CFG) &= ~0x80000000; } DBGCLK("SetOhioClockPll leave. ClockId=%s\n", OhioClockIdName(OhioClockId)); } /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ static int ValidateFrequency ( TClock_OhioIds OhioClockId, unsigned int OutputFrequency ) { unsigned int BootCrRegister; unsigned int MaxFrequency; DBGCLK ( "ValidateFrequency enter. ClockId=%s OutputFrequency=%s\n", OhioClockIdName(OhioClockId), ShowInt(OutputFrequency) ); BootCrRegister = REG32_DATA(AVALANCHE_DCL_BOOTCR); /* check if PLLs are bypassed */ if (BootCrRegister & CClock_BootCrPllBypassBit) { DBGCLK("ValidateFrequency leave - bypass.\n"); return 1; } /* check if the requested OutputFrequency is in valid range */ switch (OhioClockId) { case CClock_OhioSys : /* 5.3 / 27 */ if ( ((CClock_BootCrMipsAsyncBit | CClock_BootCrMips2To1Bit) & BootCrRegister) == CClock_BootCrMips2To1Bit ) { MaxFrequency = CClock_SysMaxFrequency2To1; } else { MaxFrequency = CClock_SysMaxFrequencyAsyncOr2To1; } break; case CClock_OhioVBus : /* 5.3 / 27 */ if ( ((CClock_BootCrMipsAsyncBit | CClock_BootCrMips2To1Bit) & BootCrRegister) == CClock_BootCrMips2To1Bit ) { MaxFrequency = CClock_SysMaxFrequency2To1 / 2; } else { MaxFrequency = CClock_SysMaxFrequencyAsyncOr2To1 / 2; } break; case CClock_OhioMips : /* 5.2 / 27 */ if (((CClock_BootCrMipsAsyncBit | CClock_BootCrMips2To1Bit) & BootCrRegister) == 0) { MaxFrequency = CClock_MipsMaxFrequencySync; } else { MaxFrequency = CClock_MipsMaxFrequencyAsyncOr2To1; } break; case CClock_OhioUsb : MaxFrequency = CClock_UsbMaxFrequency; break; case CClock_OhioAdslss : MaxFrequency = CClock_AdslssMaxFrequency; break; default: return 1; } DBGCLK ( "ValidateFrequency leave. %s ClockId=%s OutputFrequency=%s MaxFrequency=%s\n", ((OutputFrequency < CClock_MinFrequency) || (OutputFrequency > MaxFrequency)) ? "Out of Range!" : "Okay", OhioClockIdName(OhioClockId), ShowInt(OutputFrequency), ShowInt(MaxFrequency) ); /* Wenn ausserhalb der Wertebereich, return 1=Fehler */ return (OutputFrequency < CClock_MinFrequency) || (OutputFrequency > MaxFrequency); } /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ static void Clock_CalcAndStore ( TClockOhioInfo Info[CClock_OhioCountIds], TClock_OhioIds OhioClockId, unsigned int UsedPostDivider ) { TClockOhioInfo *Current; Current = &Info[OhioClockId]; Current->BaseFrequency = GetBaseFrequency(OhioClockId); if (UsedPostDivider != 0) { /* PostDivider MUSS 1 sein */ GetMulDivValue(Current, UsedPostDivider, UsedPostDivider); } else { GetMulDivValue(Current, 1, CClock_PostDivRegRatioMask); } DBGCLK ( "avalanche_clkc_init:%s OutputFrequency=%s BaseFrequency=%s PreDiv=%s Mult=%s PostDiv=%s\n", OhioClockIdName(OhioClockId), ShowInt(Current->OutputFrequency), ShowInt(Current->BaseFrequency), ShowInt(Current->PreDivider), ShowInt(Current->Multiplier), ShowInt(Current->PostDivider) ); SetOhioClockPll(Current, OhioClockId); } /*-------------------------------------------------------------------------*\ * The routine initializes the internal variables depending on * on the sources selected for different clocks. \*-------------------------------------------------------------------------*/ void avalanche_clkc_init ( unsigned int afeclk, unsigned int refclk, unsigned int dummy_xtal3in ) { UINT32 Mode; UINT32 Index; TClockOhioInfo Info[CClock_OhioCountIds]; #if defined(CDebugGpio6Output) UINT32 GpioBits; #endif /* defined(CDebugGpio6Output) */ if (! MClock_IsOhioChip()) { DBGCLK("avalanche_clkc_init: Not Ohio Chip(afeclk=%s, refclk=%s)\n", ShowInt(afeclk), ShowInt(refclk)); return; } DBGCLK("avalanche_clkc_init: afeclk=%s, refclk=%s\n", ShowInt(afeclk), ShowInt(refclk)); dummy_xtal3in = dummy_xtal3in; InitialBaseFrequency[CClock_OhioMips] = afeclk; InitialBaseFrequency[CClock_OhioSys] = refclk; for (Index = 0; Index < CClock_OhioCountIds; Index++) { Info[Index].OutputFrequency = 0; } ClkControllOffset[CClock_OhioMips] = 0x80; ClkControllOffset[CClock_OhioSys] = 0x100; ClkControllOffset[CClock_OhioUsb] = 0x180; Mode = (CClock_BootCrMipsAsyncBit | CClock_BootCrMips2To1Bit) & REG32_DATA(AVALANCHE_DCL_BOOTCR); DBGCLK ( "avalanche_clkc_init: Mode(%x:%s %s) Bypass=%x\n", Mode, (Mode & CClock_BootCrMipsAsyncBit) ? "Async" : "Sync", (Mode & CClock_BootCrMips2To1Bit) ? "2:1" : "1:1", CClock_BootCrPllBypassBit & REG32_DATA(AVALANCHE_DCL_BOOTCR) ); if (Mode & CClock_BootCrPllBypassBit) { DBGCLK ("avalanche_clkc_init: Bypass! Mips=AFE_XTAL=%s, SYS&USB=REF_XTAL=%s\n", ShowInt(afeclk), ShowInt(refclk)); Info[CClock_OhioMips].OutputFrequency = InitialBaseFrequency[CClock_OhioMips]; Info[CClock_OhioSys].OutputFrequency = InitialBaseFrequency[CClock_OhioSys]; Info[CClock_OhioUsb].OutputFrequency = InitialBaseFrequency[CClock_OhioSys]; return; } /* VerSerClkSelR Bit(8)=1:Ohio250_mode und VLYNQ_CLK_SEL=125Mhz selekted */ REG32_WRITE ( AVALANCHE_DCL_BOOTCR + 0x10, CClock_VSerClkSelR_Ohio250ModeBit /* | CClock_VSerClkSelR_VlynqClkSel211MhzBit*/ ); /* Synchron ? */ switch (Mode) { case (! CClock_BootCrMipsAsyncBit) | CClock_BootCrMips2To1Bit : DBGCLK("avalanche_clkc_init(2:1&Sync:Mips-PLL steuert mips & system clock)\n"); Info[CClock_OhioMips].OutputFrequency = 211968000; break; case (! CClock_BootCrMipsAsyncBit) | (! CClock_BootCrMips2To1Bit) : DBGCLK("avalanche_clkc_init(1:1&Sync:SYS-PLL steuert mips & system clock)\n"); Info[CClock_OhioMips].OutputFrequency = CLK_MHZ(125); break; case CClock_BootCrMipsAsyncBit | CClock_BootCrMips2To1Bit : case CClock_BootCrMipsAsyncBit : DBGCLK("avalanche_clkc_init(ASync/Getrennte PLL für mips & system clock)\n"); Info[CClock_OhioMips].OutputFrequency = 211968000; break; } Info[CClock_OhioSys].OutputFrequency = CLK_MHZ(125); Info[CClock_OhioUsb].OutputFrequency = 48076900; Clock_CalcAndStore(Info, CClock_OhioMips, 0); /* System Pll mit PostDivider == 2. Annahme, Postdivider nach Reset für ADSL-Ausgang == 1! */ Clock_CalcAndStore(Info, CClock_OhioSys, 2); Clock_CalcAndStore(Info, CClock_OhioUsb, 0); #if defined(CDebugGpio6Output) /* Seite 84. Bit 0 und Bit 6 setzten. Dazu alten Wert auslesen. */ GpioBits = REG32_DATA(AVALANCHE_GPIO_BASE + 0x0c); REG32_WRITE(AVALANCHE_GPIO_BASE + 0x0c, GpioBits & 0x81); /* PLL Test Register. GPIO6=PLL_OU_ENABLE=1, MIPS->GPIO6, Div by 4 */ REG32_WRITE(AVALANCHE_DCL_BOOTCR + 0x0c, (1 << 0) | (0x01 << 1) | (1 << 3)); #endif /* defined(CDebugGpio6Output) */ } /*-------------------------------------------------------------------------*\ * The above routine is called to get the OutputFrequency of the * selected clock( clk_id) * Returns Frequency of the requested clock in case of valid argument * A value of 0 is returned otherwise. \*-------------------------------------------------------------------------*/ unsigned int avalanche_clkc_get_freq ( AVALANCHE_CLKC_ID_T clk_id ) { UINT32 Mode; if (! MClock_IsOhioChip()) { DBGCLK ( "avalanche_clkc_get_freq leave. Not Ohio chip. Clk_id=%s\n", OhioClockIdName(ExternToInternClkId(clk_id)) ); return 0; } DBGCLK("avalanche_clkc_get_freq enter. Clk_id=%s\n", OhioClockIdName(ExternToInternClkId(clk_id))); Mode = (CClock_BootCrMipsAsyncBit | CClock_BootCrMips2To1Bit) & REG32_DATA(AVALANCHE_DCL_BOOTCR); switch (clk_id) { case CLKC_MIPS : /* default CLK_MHZ(211); */ if (Mode == ((! CClock_BootCrMipsAsyncBit) | (! CClock_BootCrMips2To1Bit))) { /* Sync / 1:1 */ return GetDividerFromPll(CClock_OhioSys); } return GetDividerFromPll(CClock_OhioMips); case CLKC_USB : /* default CLK_MHZ(48); */ if (CClock_BootCrPllBypassBit & REG32_DATA(AVALANCHE_DCL_BOOTCR)) { return InitialBaseFrequency[CClock_OhioSys]; } return GetDividerFromPll(CClock_OhioUsb); case CLKC_SYS : /* default CLK_MHZ(125); */ if (CClock_BootCrPllBypassBit & REG32_DATA(AVALANCHE_DCL_BOOTCR)) { return InitialBaseFrequency[CClock_OhioSys]; } if (Mode == ((! CClock_BootCrMipsAsyncBit) | CClock_BootCrMips2To1Bit)) { return GetDividerFromPll(CClock_OhioMips)/2; } return GetDividerFromPll(CClock_OhioSys); case CLKC_VBUS : /* default CLK_MHZ(125) / 2 */ if (CClock_BootCrPllBypassBit & REG32_DATA(AVALANCHE_DCL_BOOTCR)) { return InitialBaseFrequency[CClock_OhioSys] / 2; } if (Mode == ((! CClock_BootCrMipsAsyncBit) | CClock_BootCrMips2To1Bit)) { return GetDividerFromPll(CClock_OhioMips) / 4; } return GetDividerFromPll(CClock_OhioSys) / 2; case CLKC_ADSLSS : if (CClock_BootCrPllBypassBit & REG32_DATA(AVALANCHE_DCL_BOOTCR)) { return GetDividerFromPll(CClock_OhioMips); } /* Solange Pll für ADSL im SystemPll nicht umprogrammiert wurde und die Annahme vorliegt, */ /* er sei nach Reset = 1 ist der Sys-Pll-Output des ADSL das Doppelte. */ return GetDividerFromPll(CClock_OhioSys) * 2; default : DBGCLK ("avalanche_clkc_get_freq leave. clk_id=%s invalid\n", OhioClockIdName(ExternToInternClkId(clk_id))); return 0; } } /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ static int SetFrequencyToPll ( TClock_OhioIds OhioClockId, unsigned int OutputFrequency ) { TClockOhioInfo Info; Info.OutputFrequency = OutputFrequency; DBGCLK ( "SetFrequencyToPll enter. ClockId=%s OutputFrequency=%s\n", OhioClockIdName(OhioClockId), ShowInt(Info.OutputFrequency) ); if (ValidateFrequency(OhioClockId, Info.OutputFrequency) == 1) { DBGCLK("SetFrequencyToPll leave. Invalid Frequency ClockId=%s\n", OhioClockIdName(OhioClockId)); return -1; } Info.BaseFrequency = GetBaseFrequency(OhioClockId); GetMulDivValue(&Info, 1, CClock_PostDivRegRatioMask); DBGCLK ( "SetFrequencyToPll: SetOhioClockPll(PreDiv=%s, Multiplier=%s, PostDiv=%s)\n", ShowInt(Info.PreDivider), ShowInt(Info.Multiplier), ShowInt(Info.PostDivider) ); SetOhioClockPll(&Info, OhioClockId); if ((Info.BaseFrequency * Info.Multiplier) != (Info.OutputFrequency * Info.PreDivider * Info.PostDivider)) { DBGCLK("SetFrequencyToPll: Approximate frequency value is set\n"); return 1; /* Approximate frequency value is set */ } DBGCLK("SetFrequencyToPll: Exact frequency value is set\n"); return 0; } /*-------------------------------------------------------------------------*\ * The above routine is called to set the OutputFrequency of the * selected clock(using clk_id) to the required value given * by the variable OutputFrequency. * Returns 0 if the required frequency is set exactly * 1 if the frequency set is not exact but an approximate value * of the requested frequency * -1 In case of an error. \*-------------------------------------------------------------------------*/ int avalanche_clkc_set_freq ( AVALANCHE_CLKC_ID_T clk_id, unsigned int OutputFrequency ) { if (! MClock_IsOhioChip()) { DBGCLK ( "avalanche_clkc_set_freq leave. Not Ohio chip. clk_id=%s\n", OhioClockIdName(ExternToInternClkId(clk_id)) ); return -1; } if (clk_id >= CLKC_NUM) { DBGCLK ("avalanche_clkc_set_freq leave. clk_id=%s invalid\n", OhioClockIdName(ExternToInternClkId(clk_id))); return -1; } if (clk_id == CLKC_ADSLSS) { DBGCLK ("avalanche_clkc_set_freq leave. clk_id=%s invalid\n", OhioClockIdName(ExternToInternClkId(clk_id))); return -1; } DBGCLK ( "avalanche_clkc_set_freq enter. clk_id=%s Frequency=%s)\n", OhioClockIdName(ExternToInternClkId(clk_id)), ShowInt(OutputFrequency) ); if (CClock_BootCrPllBypassBit & REG32_DATA(AVALANCHE_DCL_BOOTCR)) { DBGCLK("avalanche_clkc_set_freq leave. Bypass!!\n"); return -1; } return SetFrequencyToPll(ExternToInternClkId(clk_id), OutputFrequency); } /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ enum _sangam_reset_cause sangam_reset_status(void) { volatile unsigned int *reset_ctrl; DBGCLK("sangam_reset_status\n"); reset_ctrl = (volatile unsigned int *) (AVALANCHE_RESET_CONTROL_BASE + 0x08); return (enum _sangam_reset_cause) (*reset_ctrl & 0x03); } /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ EXPORT_SYMBOL(sangam_reset_status); EXPORT_SYMBOL(avalanche_clkc_init); EXPORT_SYMBOL(avalanche_clkc_set_freq); EXPORT_SYMBOL(avalanche_clkc_get_freq);