speed.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223
  1. /*
  2. * (C) Copyright 2000-2008
  3. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. #include <common.h>
  24. #include <ppc_asm.tmpl>
  25. #include <ppc4xx.h>
  26. #include <asm/processor.h>
  27. DECLARE_GLOBAL_DATA_PTR;
  28. #define ONE_BILLION 1000000000
  29. #ifdef DEBUG
  30. #define DEBUGF(fmt,args...) printf(fmt ,##args)
  31. #else
  32. #define DEBUGF(fmt,args...)
  33. #endif
  34. #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  35. #if defined(CONFIG_405GP) || defined(CONFIG_405CR)
  36. void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
  37. {
  38. unsigned long pllmr;
  39. unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
  40. uint pvr = get_pvr();
  41. unsigned long psr;
  42. unsigned long m;
  43. /*
  44. * Read PLL Mode register
  45. */
  46. pllmr = mfdcr (pllmd);
  47. /*
  48. * Read Pin Strapping register
  49. */
  50. psr = mfdcr (strap);
  51. /*
  52. * Determine FWD_DIV.
  53. */
  54. sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
  55. /*
  56. * Determine FBK_DIV.
  57. */
  58. sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
  59. if (sysInfo->pllFbkDiv == 0) {
  60. sysInfo->pllFbkDiv = 16;
  61. }
  62. /*
  63. * Determine PLB_DIV.
  64. */
  65. sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
  66. /*
  67. * Determine PCI_DIV.
  68. */
  69. sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
  70. /*
  71. * Determine EXTBUS_DIV.
  72. */
  73. sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
  74. /*
  75. * Determine OPB_DIV.
  76. */
  77. sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
  78. /*
  79. * Check if PPC405GPr used (mask minor revision field)
  80. */
  81. if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
  82. /*
  83. * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
  84. */
  85. sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
  86. /*
  87. * Determine factor m depending on PLL feedback clock source
  88. */
  89. if (!(psr & PSR_PCI_ASYNC_EN)) {
  90. if (psr & PSR_NEW_MODE_EN) {
  91. /*
  92. * sync pci clock used as feedback (new mode)
  93. */
  94. m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
  95. } else {
  96. /*
  97. * sync pci clock used as feedback (legacy mode)
  98. */
  99. m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
  100. }
  101. } else if (psr & PSR_NEW_MODE_EN) {
  102. if (psr & PSR_PERCLK_SYNC_MODE_EN) {
  103. /*
  104. * PerClk used as feedback (new mode)
  105. */
  106. m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
  107. } else {
  108. /*
  109. * CPU clock used as feedback (new mode)
  110. */
  111. m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
  112. }
  113. } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
  114. /*
  115. * PerClk used as feedback (legacy mode)
  116. */
  117. m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
  118. } else {
  119. /*
  120. * PLB clock used as feedback (legacy mode)
  121. */
  122. m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
  123. }
  124. sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
  125. (unsigned long long)sysClkPeriodPs;
  126. sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
  127. sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
  128. } else {
  129. /*
  130. * Check pllFwdDiv to see if running in bypass mode where the CPU speed
  131. * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
  132. * to make sure it is within the proper range.
  133. * spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
  134. * Note freqVCO is calculated in Mhz to avoid errors introduced by rounding.
  135. */
  136. if (sysInfo->pllFwdDiv == 1) {
  137. sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
  138. sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
  139. } else {
  140. sysInfo->freqVCOHz = ( 1000000000000LL *
  141. (unsigned long long)sysInfo->pllFwdDiv *
  142. (unsigned long long)sysInfo->pllFbkDiv *
  143. (unsigned long long)sysInfo->pllPlbDiv
  144. ) / (unsigned long long)sysClkPeriodPs;
  145. sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) /
  146. sysInfo->pllFbkDiv)) * 10000;
  147. sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
  148. }
  149. }
  150. sysInfo->freqUART = sysInfo->freqProcessor;
  151. }
  152. /********************************************
  153. * get_OPB_freq
  154. * return OPB bus freq in Hz
  155. *********************************************/
  156. ulong get_OPB_freq (void)
  157. {
  158. ulong val = 0;
  159. PPC4xx_SYS_INFO sys_info;
  160. get_sys_info (&sys_info);
  161. val = sys_info.freqPLB / sys_info.pllOpbDiv;
  162. return val;
  163. }
  164. /********************************************
  165. * get_PCI_freq
  166. * return PCI bus freq in Hz
  167. *********************************************/
  168. ulong get_PCI_freq (void)
  169. {
  170. ulong val;
  171. PPC4xx_SYS_INFO sys_info;
  172. get_sys_info (&sys_info);
  173. val = sys_info.freqPLB / sys_info.pllPciDiv;
  174. return val;
  175. }
  176. #elif defined(CONFIG_440)
  177. #if defined(CONFIG_460EX) || defined(CONFIG_460GT)
  178. static u8 pll_fwdv_multi_bits[] = {
  179. /* values for: 1 - 16 */
  180. 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
  181. 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
  182. };
  183. u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
  184. {
  185. u32 index;
  186. for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
  187. if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
  188. return index + 1;
  189. return 0;
  190. }
  191. static u8 pll_fbdv_multi_bits[] = {
  192. /* values for: 1 - 100 */
  193. 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
  194. 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
  195. 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
  196. 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
  197. 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
  198. 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
  199. 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
  200. 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
  201. 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
  202. 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
  203. /* values for: 101 - 200 */
  204. 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
  205. 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
  206. 0x20, 0xc0, 0x01, 0x83, 0x77, 0xff, 0x1f, 0xbf, 0x7f, 0xfe,
  207. 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
  208. 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
  209. 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
  210. 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
  211. 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
  212. 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
  213. 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
  214. /* values for: 201 - 255 */
  215. 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
  216. 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
  217. 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
  218. 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
  219. 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
  220. 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
  221. };
  222. u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
  223. {
  224. u32 index;
  225. for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
  226. if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
  227. return index + 1;
  228. return 0;
  229. }
  230. /*
  231. * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
  232. * with latest EAS
  233. */
  234. void get_sys_info (sys_info_t * sysInfo)
  235. {
  236. unsigned long strp0;
  237. unsigned long strp1;
  238. unsigned long temp;
  239. unsigned long m;
  240. unsigned long plbedv0;
  241. /* Extract configured divisors */
  242. mfsdr(sdr_sdstp0, strp0);
  243. mfsdr(sdr_sdstp1, strp1);
  244. temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
  245. sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
  246. temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
  247. sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
  248. temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
  249. sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
  250. temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
  251. sysInfo->pllOpbDiv = temp ? temp : 4;
  252. /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
  253. temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
  254. sysInfo->pllExtBusDiv = temp ? temp : 4;
  255. temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
  256. plbedv0 = temp ? temp: 8;
  257. /* Calculate 'M' based on feedback source */
  258. temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
  259. if (temp == 0) {
  260. /* PLL internal feedback */
  261. m = sysInfo->pllFbkDiv;
  262. } else {
  263. /* PLL PerClk feedback */
  264. m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
  265. sysInfo->pllExtBusDiv;
  266. }
  267. /* Now calculate the individual clocks */
  268. sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
  269. sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
  270. sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
  271. sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
  272. sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
  273. sysInfo->freqDDR = sysInfo->freqPLB;
  274. sysInfo->freqUART = sysInfo->freqPLB;
  275. return;
  276. }
  277. #elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
  278. defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
  279. void get_sys_info (sys_info_t *sysInfo)
  280. {
  281. unsigned long temp;
  282. unsigned long reg;
  283. unsigned long lfdiv;
  284. unsigned long m;
  285. unsigned long prbdv0;
  286. /*
  287. WARNING: ASSUMES the following:
  288. ENG=1
  289. PRADV0=1
  290. PRBDV0=1
  291. */
  292. /* Decode CPR0_PLLD0 for divisors */
  293. mfcpr(clk_plld, reg);
  294. temp = (reg & PLLD_FWDVA_MASK) >> 16;
  295. sysInfo->pllFwdDivA = temp ? temp : 16;
  296. temp = (reg & PLLD_FWDVB_MASK) >> 8;
  297. sysInfo->pllFwdDivB = temp ? temp: 8 ;
  298. temp = (reg & PLLD_FBDV_MASK) >> 24;
  299. sysInfo->pllFbkDiv = temp ? temp : 32;
  300. lfdiv = reg & PLLD_LFBDV_MASK;
  301. mfcpr(clk_opbd, reg);
  302. temp = (reg & OPBDDV_MASK) >> 24;
  303. sysInfo->pllOpbDiv = temp ? temp : 4;
  304. mfcpr(clk_perd, reg);
  305. temp = (reg & PERDV_MASK) >> 24;
  306. sysInfo->pllExtBusDiv = temp ? temp : 8;
  307. mfcpr(clk_primbd, reg);
  308. temp = (reg & PRBDV_MASK) >> 24;
  309. prbdv0 = temp ? temp : 8;
  310. mfcpr(clk_spcid, reg);
  311. temp = (reg & SPCID_MASK) >> 24;
  312. sysInfo->pllPciDiv = temp ? temp : 4;
  313. /* Calculate 'M' based on feedback source */
  314. mfsdr(sdr_sdstp0, reg);
  315. temp = (reg & PLLSYS0_SEL_MASK) >> 27;
  316. if (temp == 0) { /* PLL output */
  317. /* Figure which pll to use */
  318. mfcpr(clk_pllc, reg);
  319. temp = (reg & PLLC_SRC_MASK) >> 29;
  320. if (!temp) /* PLLOUTA */
  321. m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
  322. else /* PLLOUTB */
  323. m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
  324. }
  325. else if (temp == 1) /* CPU output */
  326. m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
  327. else /* PerClk */
  328. m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
  329. /* Now calculate the individual clocks */
  330. sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
  331. sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
  332. sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
  333. sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
  334. sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
  335. sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
  336. sysInfo->freqUART = sysInfo->freqPLB;
  337. /* Figure which timer source to use */
  338. if (mfspr(ccr1) & 0x0080) { /* External Clock, assume same as SYS_CLK */
  339. temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
  340. if (CONFIG_SYS_CLK_FREQ > temp)
  341. sysInfo->freqTmrClk = temp;
  342. else
  343. sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
  344. }
  345. else /* Internal clock */
  346. sysInfo->freqTmrClk = sysInfo->freqProcessor;
  347. }
  348. /********************************************
  349. * get_PCI_freq
  350. * return PCI bus freq in Hz
  351. *********************************************/
  352. ulong get_PCI_freq (void)
  353. {
  354. sys_info_t sys_info;
  355. get_sys_info (&sys_info);
  356. return sys_info.freqPCI;
  357. }
  358. #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)
  359. void get_sys_info (sys_info_t * sysInfo)
  360. {
  361. unsigned long strp0;
  362. unsigned long temp;
  363. unsigned long m;
  364. /* Extract configured divisors */
  365. strp0 = mfdcr( cpc0_strp0 );
  366. sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
  367. sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
  368. temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
  369. sysInfo->pllFbkDiv = temp ? temp : 16;
  370. sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
  371. sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
  372. /* Calculate 'M' based on feedback source */
  373. if( strp0 & PLLSYS0_EXTSL_MASK )
  374. m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
  375. else
  376. m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
  377. /* Now calculate the individual clocks */
  378. sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
  379. sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
  380. sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
  381. if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
  382. sysInfo->freqPLB >>= 1;
  383. sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
  384. sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
  385. sysInfo->freqUART = sysInfo->freqPLB;
  386. }
  387. #else
  388. void get_sys_info (sys_info_t * sysInfo)
  389. {
  390. unsigned long strp0;
  391. unsigned long strp1;
  392. unsigned long temp;
  393. unsigned long temp1;
  394. unsigned long lfdiv;
  395. unsigned long m;
  396. unsigned long prbdv0;
  397. #if defined(CONFIG_YUCCA)
  398. unsigned long sys_freq;
  399. unsigned long sys_per=0;
  400. unsigned long msr;
  401. unsigned long pci_clock_per;
  402. unsigned long sdr_ddrpll;
  403. /*-------------------------------------------------------------------------+
  404. | Get the system clock period.
  405. +-------------------------------------------------------------------------*/
  406. sys_per = determine_sysper();
  407. msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
  408. /*-------------------------------------------------------------------------+
  409. | Calculate the system clock speed from the period.
  410. +-------------------------------------------------------------------------*/
  411. sys_freq = (ONE_BILLION / sys_per) * 1000;
  412. #endif
  413. /* Extract configured divisors */
  414. mfsdr( sdr_sdstp0,strp0 );
  415. mfsdr( sdr_sdstp1,strp1 );
  416. temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
  417. sysInfo->pllFwdDivA = temp ? temp : 16 ;
  418. temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
  419. sysInfo->pllFwdDivB = temp ? temp: 8 ;
  420. temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
  421. sysInfo->pllFbkDiv = temp ? temp : 32;
  422. temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
  423. sysInfo->pllOpbDiv = temp ? temp : 4;
  424. temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
  425. sysInfo->pllExtBusDiv = temp ? temp : 4;
  426. prbdv0 = (strp0 >> 2) & 0x7;
  427. /* Calculate 'M' based on feedback source */
  428. temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
  429. temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
  430. lfdiv = temp1 ? temp1 : 64;
  431. if (temp == 0) { /* PLL output */
  432. /* Figure which pll to use */
  433. temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
  434. if (!temp)
  435. m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
  436. else
  437. m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
  438. }
  439. else if (temp == 1) /* CPU output */
  440. m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
  441. else /* PerClk */
  442. m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
  443. /* Now calculate the individual clocks */
  444. #if defined(CONFIG_YUCCA)
  445. sysInfo->freqVCOMhz = (m * sys_freq) ;
  446. #else
  447. sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
  448. #endif
  449. sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
  450. sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
  451. sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
  452. sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
  453. #if defined(CONFIG_YUCCA)
  454. /* Determine PCI Clock Period */
  455. pci_clock_per = determine_pci_clock_per();
  456. sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
  457. mfsdr(sdr_ddr0, sdr_ddrpll);
  458. sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
  459. #endif
  460. sysInfo->freqUART = sysInfo->freqPLB;
  461. }
  462. #endif
  463. #if defined(CONFIG_YUCCA)
  464. unsigned long determine_sysper(void)
  465. {
  466. unsigned int fpga_clocking_reg;
  467. unsigned int master_clock_selection;
  468. unsigned long master_clock_per = 0;
  469. unsigned long fb_div_selection;
  470. unsigned int vco_div_reg_value;
  471. unsigned long vco_div_selection;
  472. unsigned long sys_per = 0;
  473. int extClkVal;
  474. /*-------------------------------------------------------------------------+
  475. | Read FPGA reg 0 and reg 1 to get FPGA reg information
  476. +-------------------------------------------------------------------------*/
  477. fpga_clocking_reg = in16(FPGA_REG16);
  478. /* Determine Master Clock Source Selection */
  479. master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
  480. switch(master_clock_selection) {
  481. case FPGA_REG16_MASTER_CLK_66_66:
  482. master_clock_per = PERIOD_66_66MHZ;
  483. break;
  484. case FPGA_REG16_MASTER_CLK_50:
  485. master_clock_per = PERIOD_50_00MHZ;
  486. break;
  487. case FPGA_REG16_MASTER_CLK_33_33:
  488. master_clock_per = PERIOD_33_33MHZ;
  489. break;
  490. case FPGA_REG16_MASTER_CLK_25:
  491. master_clock_per = PERIOD_25_00MHZ;
  492. break;
  493. case FPGA_REG16_MASTER_CLK_EXT:
  494. if ((extClkVal==EXTCLK_33_33)
  495. && (extClkVal==EXTCLK_50)
  496. && (extClkVal==EXTCLK_66_66)
  497. && (extClkVal==EXTCLK_83)) {
  498. /* calculate master clock period from external clock value */
  499. master_clock_per=(ONE_BILLION/extClkVal) * 1000;
  500. } else {
  501. /* Unsupported */
  502. DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
  503. hang();
  504. }
  505. break;
  506. default:
  507. /* Unsupported */
  508. DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
  509. hang();
  510. break;
  511. }
  512. /* Determine FB divisors values */
  513. if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
  514. if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
  515. fb_div_selection = FPGA_FB_DIV_6;
  516. else
  517. fb_div_selection = FPGA_FB_DIV_12;
  518. } else {
  519. if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
  520. fb_div_selection = FPGA_FB_DIV_10;
  521. else
  522. fb_div_selection = FPGA_FB_DIV_20;
  523. }
  524. /* Determine VCO divisors values */
  525. vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
  526. switch(vco_div_reg_value) {
  527. case FPGA_REG16_VCO_DIV_4:
  528. vco_div_selection = FPGA_VCO_DIV_4;
  529. break;
  530. case FPGA_REG16_VCO_DIV_6:
  531. vco_div_selection = FPGA_VCO_DIV_6;
  532. break;
  533. case FPGA_REG16_VCO_DIV_8:
  534. vco_div_selection = FPGA_VCO_DIV_8;
  535. break;
  536. case FPGA_REG16_VCO_DIV_10:
  537. default:
  538. vco_div_selection = FPGA_VCO_DIV_10;
  539. break;
  540. }
  541. if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
  542. switch(master_clock_per) {
  543. case PERIOD_25_00MHZ:
  544. if (fb_div_selection == FPGA_FB_DIV_12) {
  545. if (vco_div_selection == FPGA_VCO_DIV_4)
  546. sys_per = PERIOD_75_00MHZ;
  547. if (vco_div_selection == FPGA_VCO_DIV_6)
  548. sys_per = PERIOD_50_00MHZ;
  549. }
  550. break;
  551. case PERIOD_33_33MHZ:
  552. if (fb_div_selection == FPGA_FB_DIV_6) {
  553. if (vco_div_selection == FPGA_VCO_DIV_4)
  554. sys_per = PERIOD_50_00MHZ;
  555. if (vco_div_selection == FPGA_VCO_DIV_6)
  556. sys_per = PERIOD_33_33MHZ;
  557. }
  558. if (fb_div_selection == FPGA_FB_DIV_10) {
  559. if (vco_div_selection == FPGA_VCO_DIV_4)
  560. sys_per = PERIOD_83_33MHZ;
  561. if (vco_div_selection == FPGA_VCO_DIV_10)
  562. sys_per = PERIOD_33_33MHZ;
  563. }
  564. if (fb_div_selection == FPGA_FB_DIV_12) {
  565. if (vco_div_selection == FPGA_VCO_DIV_4)
  566. sys_per = PERIOD_100_00MHZ;
  567. if (vco_div_selection == FPGA_VCO_DIV_6)
  568. sys_per = PERIOD_66_66MHZ;
  569. if (vco_div_selection == FPGA_VCO_DIV_8)
  570. sys_per = PERIOD_50_00MHZ;
  571. }
  572. break;
  573. case PERIOD_50_00MHZ:
  574. if (fb_div_selection == FPGA_FB_DIV_6) {
  575. if (vco_div_selection == FPGA_VCO_DIV_4)
  576. sys_per = PERIOD_75_00MHZ;
  577. if (vco_div_selection == FPGA_VCO_DIV_6)
  578. sys_per = PERIOD_50_00MHZ;
  579. }
  580. if (fb_div_selection == FPGA_FB_DIV_10) {
  581. if (vco_div_selection == FPGA_VCO_DIV_6)
  582. sys_per = PERIOD_83_33MHZ;
  583. if (vco_div_selection == FPGA_VCO_DIV_10)
  584. sys_per = PERIOD_50_00MHZ;
  585. }
  586. if (fb_div_selection == FPGA_FB_DIV_12) {
  587. if (vco_div_selection == FPGA_VCO_DIV_6)
  588. sys_per = PERIOD_100_00MHZ;
  589. if (vco_div_selection == FPGA_VCO_DIV_8)
  590. sys_per = PERIOD_75_00MHZ;
  591. }
  592. break;
  593. case PERIOD_66_66MHZ:
  594. if (fb_div_selection == FPGA_FB_DIV_6) {
  595. if (vco_div_selection == FPGA_VCO_DIV_4)
  596. sys_per = PERIOD_100_00MHZ;
  597. if (vco_div_selection == FPGA_VCO_DIV_6)
  598. sys_per = PERIOD_66_66MHZ;
  599. if (vco_div_selection == FPGA_VCO_DIV_8)
  600. sys_per = PERIOD_50_00MHZ;
  601. }
  602. if (fb_div_selection == FPGA_FB_DIV_10) {
  603. if (vco_div_selection == FPGA_VCO_DIV_8)
  604. sys_per = PERIOD_83_33MHZ;
  605. if (vco_div_selection == FPGA_VCO_DIV_10)
  606. sys_per = PERIOD_66_66MHZ;
  607. }
  608. if (fb_div_selection == FPGA_FB_DIV_12) {
  609. if (vco_div_selection == FPGA_VCO_DIV_8)
  610. sys_per = PERIOD_100_00MHZ;
  611. }
  612. break;
  613. default:
  614. break;
  615. }
  616. if (sys_per == 0) {
  617. /* Other combinations are not supported */
  618. DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
  619. hang();
  620. }
  621. } else {
  622. /* calcul system clock without cheking */
  623. /* if engineering option clock no check is selected */
  624. /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
  625. sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
  626. }
  627. return(sys_per);
  628. }
  629. /*-------------------------------------------------------------------------+
  630. | determine_pci_clock_per.
  631. +-------------------------------------------------------------------------*/
  632. unsigned long determine_pci_clock_per(void)
  633. {
  634. unsigned long pci_clock_selection, pci_period;
  635. /*-------------------------------------------------------------------------+
  636. | Read FPGA reg 6 to get PCI 0 FPGA reg information
  637. +-------------------------------------------------------------------------*/
  638. pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
  639. pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
  640. switch (pci_clock_selection) {
  641. case FPGA_REG16_PCI0_CLK_133_33:
  642. pci_period = PERIOD_133_33MHZ;
  643. break;
  644. case FPGA_REG16_PCI0_CLK_100:
  645. pci_period = PERIOD_100_00MHZ;
  646. break;
  647. case FPGA_REG16_PCI0_CLK_66_66:
  648. pci_period = PERIOD_66_66MHZ;
  649. break;
  650. default:
  651. pci_period = PERIOD_33_33MHZ;;
  652. break;
  653. }
  654. return(pci_period);
  655. }
  656. #endif
  657. ulong get_OPB_freq (void)
  658. {
  659. sys_info_t sys_info;
  660. get_sys_info (&sys_info);
  661. return sys_info.freqOPB;
  662. }
  663. #elif defined(CONFIG_XILINX_ML300)
  664. extern void get_sys_info (sys_info_t * sysInfo);
  665. extern ulong get_PCI_freq (void);
  666. #elif defined(CONFIG_AP1000)
  667. void get_sys_info (sys_info_t * sysInfo)
  668. {
  669. sysInfo->freqProcessor = 240 * 1000 * 1000;
  670. sysInfo->freqPLB = 80 * 1000 * 1000;
  671. sysInfo->freqPCI = 33 * 1000 * 1000;
  672. }
  673. #elif defined(CONFIG_405)
  674. void get_sys_info (sys_info_t * sysInfo)
  675. {
  676. sysInfo->freqVCOMhz=3125000;
  677. sysInfo->freqProcessor=12*1000*1000;
  678. sysInfo->freqPLB=50*1000*1000;
  679. sysInfo->freqPCI=66*1000*1000;
  680. }
  681. #elif defined(CONFIG_405EP)
  682. void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
  683. {
  684. unsigned long pllmr0;
  685. unsigned long pllmr1;
  686. unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
  687. unsigned long m;
  688. unsigned long pllmr0_ccdv;
  689. /*
  690. * Read PLL Mode registers
  691. */
  692. pllmr0 = mfdcr (cpc0_pllmr0);
  693. pllmr1 = mfdcr (cpc0_pllmr1);
  694. /*
  695. * Determine forward divider A
  696. */
  697. sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
  698. /*
  699. * Determine forward divider B (should be equal to A)
  700. */
  701. sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
  702. /*
  703. * Determine FBK_DIV.
  704. */
  705. sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
  706. if (sysInfo->pllFbkDiv == 0)
  707. sysInfo->pllFbkDiv = 16;
  708. /*
  709. * Determine PLB_DIV.
  710. */
  711. sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
  712. /*
  713. * Determine PCI_DIV.
  714. */
  715. sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
  716. /*
  717. * Determine EXTBUS_DIV.
  718. */
  719. sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
  720. /*
  721. * Determine OPB_DIV.
  722. */
  723. sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
  724. /*
  725. * Determine the M factor
  726. */
  727. m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
  728. /*
  729. * Determine VCO clock frequency
  730. */
  731. sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
  732. (unsigned long long)sysClkPeriodPs;
  733. /*
  734. * Determine CPU clock frequency
  735. */
  736. pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
  737. if (pllmr1 & PLLMR1_SSCS_MASK) {
  738. /*
  739. * This is true if FWDVA == FWDVB:
  740. * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
  741. * / pllmr0_ccdv;
  742. */
  743. sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
  744. / sysInfo->pllFwdDiv / pllmr0_ccdv;
  745. } else {
  746. sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
  747. }
  748. /*
  749. * Determine PLB clock frequency
  750. */
  751. sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
  752. sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
  753. sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
  754. }
  755. /********************************************
  756. * get_OPB_freq
  757. * return OPB bus freq in Hz
  758. *********************************************/
  759. ulong get_OPB_freq (void)
  760. {
  761. ulong val = 0;
  762. PPC4xx_SYS_INFO sys_info;
  763. get_sys_info (&sys_info);
  764. val = sys_info.freqPLB / sys_info.pllOpbDiv;
  765. return val;
  766. }
  767. /********************************************
  768. * get_PCI_freq
  769. * return PCI bus freq in Hz
  770. *********************************************/
  771. ulong get_PCI_freq (void)
  772. {
  773. ulong val;
  774. PPC4xx_SYS_INFO sys_info;
  775. get_sys_info (&sys_info);
  776. val = sys_info.freqPLB / sys_info.pllPciDiv;
  777. return val;
  778. }
  779. #elif defined(CONFIG_405EZ)
  780. void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
  781. {
  782. unsigned long cpr_plld;
  783. unsigned long cpr_pllc;
  784. unsigned long cpr_primad;
  785. unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
  786. unsigned long primad_cpudv;
  787. unsigned long m;
  788. /*
  789. * Read PLL Mode registers
  790. */
  791. mfcpr(cprplld, cpr_plld);
  792. mfcpr(cprpllc, cpr_pllc);
  793. /*
  794. * Determine forward divider A
  795. */
  796. sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
  797. /*
  798. * Determine forward divider B
  799. */
  800. sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
  801. if (sysInfo->pllFwdDivB == 0)
  802. sysInfo->pllFwdDivB = 8;
  803. /*
  804. * Determine FBK_DIV.
  805. */
  806. sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
  807. if (sysInfo->pllFbkDiv == 0)
  808. sysInfo->pllFbkDiv = 256;
  809. /*
  810. * Read CPR_PRIMAD register
  811. */
  812. mfcpr(cprprimad, cpr_primad);
  813. /*
  814. * Determine PLB_DIV.
  815. */
  816. sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
  817. if (sysInfo->pllPlbDiv == 0)
  818. sysInfo->pllPlbDiv = 16;
  819. /*
  820. * Determine EXTBUS_DIV.
  821. */
  822. sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
  823. if (sysInfo->pllExtBusDiv == 0)
  824. sysInfo->pllExtBusDiv = 16;
  825. /*
  826. * Determine OPB_DIV.
  827. */
  828. sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
  829. if (sysInfo->pllOpbDiv == 0)
  830. sysInfo->pllOpbDiv = 16;
  831. /*
  832. * Determine the M factor
  833. */
  834. if (cpr_pllc & PLLC_SRC_MASK)
  835. m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
  836. else
  837. m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
  838. /*
  839. * Determine VCO clock frequency
  840. */
  841. sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
  842. (unsigned long long)sysClkPeriodPs;
  843. /*
  844. * Determine CPU clock frequency
  845. */
  846. primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
  847. if (primad_cpudv == 0)
  848. primad_cpudv = 16;
  849. sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
  850. sysInfo->pllFwdDiv / primad_cpudv;
  851. /*
  852. * Determine PLB clock frequency
  853. */
  854. sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
  855. sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
  856. sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
  857. sysInfo->pllExtBusDiv;
  858. sysInfo->freqUART = sysInfo->freqVCOHz;
  859. }
  860. /********************************************
  861. * get_OPB_freq
  862. * return OPB bus freq in Hz
  863. *********************************************/
  864. ulong get_OPB_freq (void)
  865. {
  866. ulong val = 0;
  867. PPC4xx_SYS_INFO sys_info;
  868. get_sys_info (&sys_info);
  869. val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
  870. return val;
  871. }
  872. #elif defined(CONFIG_405EX)
  873. /*
  874. * TODO: We need to get the CPR registers and calculate these values correctly!!!!
  875. * We need the specs!!!!
  876. */
  877. static unsigned char get_fbdv(unsigned char index)
  878. {
  879. unsigned char ret = 0;
  880. /* This is table should be 256 bytes.
  881. * Only take first 52 values.
  882. */
  883. unsigned char fbdv_tb[] = {
  884. 0x00, 0xff, 0x7f, 0xfd,
  885. 0x7a, 0xf5, 0x6a, 0xd5,
  886. 0x2a, 0xd4, 0x29, 0xd3,
  887. 0x26, 0xcc, 0x19, 0xb3,
  888. 0x67, 0xce, 0x1d, 0xbb,
  889. 0x77, 0xee, 0x5d, 0xba,
  890. 0x74, 0xe9, 0x52, 0xa5,
  891. 0x4b, 0x96, 0x2c, 0xd8,
  892. 0x31, 0xe3, 0x46, 0x8d,
  893. 0x1b, 0xb7, 0x6f, 0xde,
  894. 0x3d, 0xfb, 0x76, 0xed,
  895. 0x5a, 0xb5, 0x6b, 0xd6,
  896. 0x2d, 0xdb, 0x36, 0xec,
  897. };
  898. if ((index & 0x7f) == 0)
  899. return 1;
  900. while (ret < sizeof (fbdv_tb)) {
  901. if (fbdv_tb[ret] == index)
  902. break;
  903. ret++;
  904. }
  905. ret++;
  906. return ret;
  907. }
  908. #define PLL_FBK_PLL_LOCAL 0
  909. #define PLL_FBK_CPU 1
  910. #define PLL_FBK_PERCLK 5
  911. void get_sys_info (sys_info_t * sysInfo)
  912. {
  913. unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
  914. unsigned long m = 1;
  915. unsigned int tmp;
  916. unsigned char fwdva[16] = {
  917. 1, 2, 14, 9, 4, 11, 16, 13,
  918. 12, 5, 6, 15, 10, 7, 8, 3,
  919. };
  920. unsigned char sel, cpudv0, plb2xDiv;
  921. mfcpr(cpr0_plld, tmp);
  922. /*
  923. * Determine forward divider A
  924. */
  925. sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
  926. /*
  927. * Determine FBK_DIV.
  928. */
  929. sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
  930. /*
  931. * Determine PLBDV0
  932. */
  933. sysInfo->pllPlbDiv = 2;
  934. /*
  935. * Determine PERDV0
  936. */
  937. mfcpr(cpr0_perd, tmp);
  938. tmp = (tmp >> 24) & 0x03;
  939. sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
  940. /*
  941. * Determine OPBDV0
  942. */
  943. mfcpr(cpr0_opbd, tmp);
  944. tmp = (tmp >> 24) & 0x03;
  945. sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
  946. /* Determine PLB2XDV0 */
  947. mfcpr(cpr0_plbd, tmp);
  948. tmp = (tmp >> 16) & 0x07;
  949. plb2xDiv = (tmp == 0) ? 8 : tmp;
  950. /* Determine CPUDV0 */
  951. mfcpr(cpr0_cpud, tmp);
  952. tmp = (tmp >> 24) & 0x07;
  953. cpudv0 = (tmp == 0) ? 8 : tmp;
  954. /* Determine SEL(5:7) in CPR0_PLLC */
  955. mfcpr(cpr0_pllc, tmp);
  956. sel = (tmp >> 24) & 0x07;
  957. /*
  958. * Determine the M factor
  959. * PLL local: M = FBDV
  960. * CPU clock: M = FBDV * FWDVA * CPUDV0
  961. * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
  962. *
  963. */
  964. switch (sel) {
  965. case PLL_FBK_CPU:
  966. m = sysInfo->pllFwdDiv * cpudv0;
  967. break;
  968. case PLL_FBK_PERCLK:
  969. m = sysInfo->pllFwdDiv * plb2xDiv * 2
  970. * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
  971. break;
  972. case PLL_FBK_PLL_LOCAL:
  973. break;
  974. default:
  975. printf("%s unknown m\n", __FUNCTION__);
  976. return;
  977. }
  978. m *= sysInfo->pllFbkDiv;
  979. /*
  980. * Determine VCO clock frequency
  981. */
  982. sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
  983. (unsigned long long)sysClkPeriodPs;
  984. /*
  985. * Determine CPU clock frequency
  986. */
  987. sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
  988. /*
  989. * Determine PLB clock frequency, ddr1x should be the same
  990. */
  991. sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
  992. sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
  993. sysInfo->freqDDR = sysInfo->freqPLB;
  994. sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
  995. sysInfo->freqUART = sysInfo->freqPLB;
  996. }
  997. /********************************************
  998. * get_OPB_freq
  999. * return OPB bus freq in Hz
  1000. *********************************************/
  1001. ulong get_OPB_freq (void)
  1002. {
  1003. ulong val = 0;
  1004. PPC4xx_SYS_INFO sys_info;
  1005. get_sys_info (&sys_info);
  1006. val = sys_info.freqPLB / sys_info.pllOpbDiv;
  1007. return val;
  1008. }
  1009. #endif
  1010. int get_clocks (void)
  1011. {
  1012. #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
  1013. defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
  1014. defined(CONFIG_405EX) || defined(CONFIG_405) || \
  1015. defined(CONFIG_440)
  1016. sys_info_t sys_info;
  1017. get_sys_info (&sys_info);
  1018. gd->cpu_clk = sys_info.freqProcessor;
  1019. gd->bus_clk = sys_info.freqPLB;
  1020. #endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
  1021. #ifdef CONFIG_IOP480
  1022. gd->cpu_clk = 66000000;
  1023. gd->bus_clk = 66000000;
  1024. #endif
  1025. return (0);
  1026. }
  1027. /********************************************
  1028. * get_bus_freq
  1029. * return PLB bus freq in Hz
  1030. *********************************************/
  1031. ulong get_bus_freq (ulong dummy)
  1032. {
  1033. ulong val;
  1034. #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
  1035. defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
  1036. defined(CONFIG_405EX) || defined(CONFIG_405) || \
  1037. defined(CONFIG_440)
  1038. sys_info_t sys_info;
  1039. get_sys_info (&sys_info);
  1040. val = sys_info.freqPLB;
  1041. #elif defined(CONFIG_IOP480)
  1042. val = 66;
  1043. #else
  1044. # error get_bus_freq() not implemented
  1045. #endif
  1046. return val;
  1047. }