speed.c 34 KB

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