speed.c 30 KB

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