speed.c 32 KB

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