speed.c 33 KB

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