speed.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230
  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(ccr1) & 0x0080) { /* External Clock, assume same as SYS_CLK */
  341. temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
  342. if (CONFIG_SYS_CLK_FREQ > temp)
  343. sysInfo->freqTmrClk = temp;
  344. else
  345. sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
  346. }
  347. else /* Internal clock */
  348. sysInfo->freqTmrClk = sysInfo->freqProcessor;
  349. }
  350. /********************************************
  351. * get_PCI_freq
  352. * return PCI bus freq in Hz
  353. *********************************************/
  354. ulong get_PCI_freq (void)
  355. {
  356. sys_info_t sys_info;
  357. get_sys_info (&sys_info);
  358. return sys_info.freqPCI;
  359. }
  360. #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
  361. && !defined(CONFIG_XILINX_440)
  362. void get_sys_info (sys_info_t * sysInfo)
  363. {
  364. unsigned long strp0;
  365. unsigned long temp;
  366. unsigned long m;
  367. /* Extract configured divisors */
  368. strp0 = mfdcr( cpc0_strp0 );
  369. sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
  370. sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
  371. temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
  372. sysInfo->pllFbkDiv = temp ? temp : 16;
  373. sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
  374. sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
  375. /* Calculate 'M' based on feedback source */
  376. if( strp0 & PLLSYS0_EXTSL_MASK )
  377. m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
  378. else
  379. m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
  380. /* Now calculate the individual clocks */
  381. sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
  382. sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
  383. sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
  384. if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
  385. sysInfo->freqPLB >>= 1;
  386. sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
  387. sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
  388. sysInfo->freqUART = sysInfo->freqPLB;
  389. }
  390. #else
  391. #if !defined(CONFIG_XILINX_440)
  392. void get_sys_info (sys_info_t * sysInfo)
  393. {
  394. unsigned long strp0;
  395. unsigned long strp1;
  396. unsigned long temp;
  397. unsigned long temp1;
  398. unsigned long lfdiv;
  399. unsigned long m;
  400. unsigned long prbdv0;
  401. #if defined(CONFIG_YUCCA)
  402. unsigned long sys_freq;
  403. unsigned long sys_per=0;
  404. unsigned long msr;
  405. unsigned long pci_clock_per;
  406. unsigned long sdr_ddrpll;
  407. /*-------------------------------------------------------------------------+
  408. | Get the system clock period.
  409. +-------------------------------------------------------------------------*/
  410. sys_per = determine_sysper();
  411. msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
  412. /*-------------------------------------------------------------------------+
  413. | Calculate the system clock speed from the period.
  414. +-------------------------------------------------------------------------*/
  415. sys_freq = (ONE_BILLION / sys_per) * 1000;
  416. #endif
  417. /* Extract configured divisors */
  418. mfsdr( sdr_sdstp0,strp0 );
  419. mfsdr( sdr_sdstp1,strp1 );
  420. temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
  421. sysInfo->pllFwdDivA = temp ? temp : 16 ;
  422. temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
  423. sysInfo->pllFwdDivB = temp ? temp: 8 ;
  424. temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
  425. sysInfo->pllFbkDiv = temp ? temp : 32;
  426. temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
  427. sysInfo->pllOpbDiv = temp ? temp : 4;
  428. temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
  429. sysInfo->pllExtBusDiv = temp ? temp : 4;
  430. prbdv0 = (strp0 >> 2) & 0x7;
  431. /* Calculate 'M' based on feedback source */
  432. temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
  433. temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
  434. lfdiv = temp1 ? temp1 : 64;
  435. if (temp == 0) { /* PLL output */
  436. /* Figure which pll to use */
  437. temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
  438. if (!temp)
  439. m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
  440. else
  441. m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
  442. }
  443. else if (temp == 1) /* CPU output */
  444. m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
  445. else /* PerClk */
  446. m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
  447. /* Now calculate the individual clocks */
  448. #if defined(CONFIG_YUCCA)
  449. sysInfo->freqVCOMhz = (m * sys_freq) ;
  450. #else
  451. sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
  452. #endif
  453. sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
  454. sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
  455. sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
  456. sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
  457. #if defined(CONFIG_YUCCA)
  458. /* Determine PCI Clock Period */
  459. pci_clock_per = determine_pci_clock_per();
  460. sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
  461. mfsdr(sdr_ddr0, sdr_ddrpll);
  462. sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
  463. #endif
  464. sysInfo->freqUART = sysInfo->freqPLB;
  465. }
  466. #endif
  467. #endif /* CONFIG_XILINX_440 */
  468. #if defined(CONFIG_YUCCA)
  469. unsigned long determine_sysper(void)
  470. {
  471. unsigned int fpga_clocking_reg;
  472. unsigned int master_clock_selection;
  473. unsigned long master_clock_per = 0;
  474. unsigned long fb_div_selection;
  475. unsigned int vco_div_reg_value;
  476. unsigned long vco_div_selection;
  477. unsigned long sys_per = 0;
  478. int extClkVal;
  479. /*-------------------------------------------------------------------------+
  480. | Read FPGA reg 0 and reg 1 to get FPGA reg information
  481. +-------------------------------------------------------------------------*/
  482. fpga_clocking_reg = in16(FPGA_REG16);
  483. /* Determine Master Clock Source Selection */
  484. master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
  485. switch(master_clock_selection) {
  486. case FPGA_REG16_MASTER_CLK_66_66:
  487. master_clock_per = PERIOD_66_66MHZ;
  488. break;
  489. case FPGA_REG16_MASTER_CLK_50:
  490. master_clock_per = PERIOD_50_00MHZ;
  491. break;
  492. case FPGA_REG16_MASTER_CLK_33_33:
  493. master_clock_per = PERIOD_33_33MHZ;
  494. break;
  495. case FPGA_REG16_MASTER_CLK_25:
  496. master_clock_per = PERIOD_25_00MHZ;
  497. break;
  498. case FPGA_REG16_MASTER_CLK_EXT:
  499. if ((extClkVal==EXTCLK_33_33)
  500. && (extClkVal==EXTCLK_50)
  501. && (extClkVal==EXTCLK_66_66)
  502. && (extClkVal==EXTCLK_83)) {
  503. /* calculate master clock period from external clock value */
  504. master_clock_per=(ONE_BILLION/extClkVal) * 1000;
  505. } else {
  506. /* Unsupported */
  507. DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
  508. hang();
  509. }
  510. break;
  511. default:
  512. /* Unsupported */
  513. DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
  514. hang();
  515. break;
  516. }
  517. /* Determine FB divisors values */
  518. if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
  519. if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
  520. fb_div_selection = FPGA_FB_DIV_6;
  521. else
  522. fb_div_selection = FPGA_FB_DIV_12;
  523. } else {
  524. if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
  525. fb_div_selection = FPGA_FB_DIV_10;
  526. else
  527. fb_div_selection = FPGA_FB_DIV_20;
  528. }
  529. /* Determine VCO divisors values */
  530. vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
  531. switch(vco_div_reg_value) {
  532. case FPGA_REG16_VCO_DIV_4:
  533. vco_div_selection = FPGA_VCO_DIV_4;
  534. break;
  535. case FPGA_REG16_VCO_DIV_6:
  536. vco_div_selection = FPGA_VCO_DIV_6;
  537. break;
  538. case FPGA_REG16_VCO_DIV_8:
  539. vco_div_selection = FPGA_VCO_DIV_8;
  540. break;
  541. case FPGA_REG16_VCO_DIV_10:
  542. default:
  543. vco_div_selection = FPGA_VCO_DIV_10;
  544. break;
  545. }
  546. if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
  547. switch(master_clock_per) {
  548. case PERIOD_25_00MHZ:
  549. if (fb_div_selection == FPGA_FB_DIV_12) {
  550. if (vco_div_selection == FPGA_VCO_DIV_4)
  551. sys_per = PERIOD_75_00MHZ;
  552. if (vco_div_selection == FPGA_VCO_DIV_6)
  553. sys_per = PERIOD_50_00MHZ;
  554. }
  555. break;
  556. case PERIOD_33_33MHZ:
  557. if (fb_div_selection == FPGA_FB_DIV_6) {
  558. if (vco_div_selection == FPGA_VCO_DIV_4)
  559. sys_per = PERIOD_50_00MHZ;
  560. if (vco_div_selection == FPGA_VCO_DIV_6)
  561. sys_per = PERIOD_33_33MHZ;
  562. }
  563. if (fb_div_selection == FPGA_FB_DIV_10) {
  564. if (vco_div_selection == FPGA_VCO_DIV_4)
  565. sys_per = PERIOD_83_33MHZ;
  566. if (vco_div_selection == FPGA_VCO_DIV_10)
  567. sys_per = PERIOD_33_33MHZ;
  568. }
  569. if (fb_div_selection == FPGA_FB_DIV_12) {
  570. if (vco_div_selection == FPGA_VCO_DIV_4)
  571. sys_per = PERIOD_100_00MHZ;
  572. if (vco_div_selection == FPGA_VCO_DIV_6)
  573. sys_per = PERIOD_66_66MHZ;
  574. if (vco_div_selection == FPGA_VCO_DIV_8)
  575. sys_per = PERIOD_50_00MHZ;
  576. }
  577. break;
  578. case PERIOD_50_00MHZ:
  579. if (fb_div_selection == FPGA_FB_DIV_6) {
  580. if (vco_div_selection == FPGA_VCO_DIV_4)
  581. sys_per = PERIOD_75_00MHZ;
  582. if (vco_div_selection == FPGA_VCO_DIV_6)
  583. sys_per = PERIOD_50_00MHZ;
  584. }
  585. if (fb_div_selection == FPGA_FB_DIV_10) {
  586. if (vco_div_selection == FPGA_VCO_DIV_6)
  587. sys_per = PERIOD_83_33MHZ;
  588. if (vco_div_selection == FPGA_VCO_DIV_10)
  589. sys_per = PERIOD_50_00MHZ;
  590. }
  591. if (fb_div_selection == FPGA_FB_DIV_12) {
  592. if (vco_div_selection == FPGA_VCO_DIV_6)
  593. sys_per = PERIOD_100_00MHZ;
  594. if (vco_div_selection == FPGA_VCO_DIV_8)
  595. sys_per = PERIOD_75_00MHZ;
  596. }
  597. break;
  598. case PERIOD_66_66MHZ:
  599. if (fb_div_selection == FPGA_FB_DIV_6) {
  600. if (vco_div_selection == FPGA_VCO_DIV_4)
  601. sys_per = PERIOD_100_00MHZ;
  602. if (vco_div_selection == FPGA_VCO_DIV_6)
  603. sys_per = PERIOD_66_66MHZ;
  604. if (vco_div_selection == FPGA_VCO_DIV_8)
  605. sys_per = PERIOD_50_00MHZ;
  606. }
  607. if (fb_div_selection == FPGA_FB_DIV_10) {
  608. if (vco_div_selection == FPGA_VCO_DIV_8)
  609. sys_per = PERIOD_83_33MHZ;
  610. if (vco_div_selection == FPGA_VCO_DIV_10)
  611. sys_per = PERIOD_66_66MHZ;
  612. }
  613. if (fb_div_selection == FPGA_FB_DIV_12) {
  614. if (vco_div_selection == FPGA_VCO_DIV_8)
  615. sys_per = PERIOD_100_00MHZ;
  616. }
  617. break;
  618. default:
  619. break;
  620. }
  621. if (sys_per == 0) {
  622. /* Other combinations are not supported */
  623. DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
  624. hang();
  625. }
  626. } else {
  627. /* calcul system clock without cheking */
  628. /* if engineering option clock no check is selected */
  629. /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
  630. sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
  631. }
  632. return(sys_per);
  633. }
  634. /*-------------------------------------------------------------------------+
  635. | determine_pci_clock_per.
  636. +-------------------------------------------------------------------------*/
  637. unsigned long determine_pci_clock_per(void)
  638. {
  639. unsigned long pci_clock_selection, pci_period;
  640. /*-------------------------------------------------------------------------+
  641. | Read FPGA reg 6 to get PCI 0 FPGA reg information
  642. +-------------------------------------------------------------------------*/
  643. pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
  644. pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
  645. switch (pci_clock_selection) {
  646. case FPGA_REG16_PCI0_CLK_133_33:
  647. pci_period = PERIOD_133_33MHZ;
  648. break;
  649. case FPGA_REG16_PCI0_CLK_100:
  650. pci_period = PERIOD_100_00MHZ;
  651. break;
  652. case FPGA_REG16_PCI0_CLK_66_66:
  653. pci_period = PERIOD_66_66MHZ;
  654. break;
  655. default:
  656. pci_period = PERIOD_33_33MHZ;;
  657. break;
  658. }
  659. return(pci_period);
  660. }
  661. #endif
  662. ulong get_OPB_freq (void)
  663. {
  664. sys_info_t sys_info;
  665. get_sys_info (&sys_info);
  666. return sys_info.freqOPB;
  667. }
  668. #elif defined(CONFIG_XILINX_405)
  669. extern void get_sys_info (sys_info_t * sysInfo);
  670. extern ulong get_PCI_freq (void);
  671. #elif defined(CONFIG_AP1000)
  672. void get_sys_info (sys_info_t * sysInfo)
  673. {
  674. sysInfo->freqProcessor = 240 * 1000 * 1000;
  675. sysInfo->freqPLB = 80 * 1000 * 1000;
  676. sysInfo->freqPCI = 33 * 1000 * 1000;
  677. }
  678. #elif defined(CONFIG_405)
  679. void get_sys_info (sys_info_t * sysInfo)
  680. {
  681. sysInfo->freqVCOMhz=3125000;
  682. sysInfo->freqProcessor=12*1000*1000;
  683. sysInfo->freqPLB=50*1000*1000;
  684. sysInfo->freqPCI=66*1000*1000;
  685. }
  686. #elif defined(CONFIG_405EP)
  687. void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
  688. {
  689. unsigned long pllmr0;
  690. unsigned long pllmr1;
  691. unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
  692. unsigned long m;
  693. unsigned long pllmr0_ccdv;
  694. /*
  695. * Read PLL Mode registers
  696. */
  697. pllmr0 = mfdcr (cpc0_pllmr0);
  698. pllmr1 = mfdcr (cpc0_pllmr1);
  699. /*
  700. * Determine forward divider A
  701. */
  702. sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
  703. /*
  704. * Determine forward divider B (should be equal to A)
  705. */
  706. sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
  707. /*
  708. * Determine FBK_DIV.
  709. */
  710. sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
  711. if (sysInfo->pllFbkDiv == 0)
  712. sysInfo->pllFbkDiv = 16;
  713. /*
  714. * Determine PLB_DIV.
  715. */
  716. sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
  717. /*
  718. * Determine PCI_DIV.
  719. */
  720. sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
  721. /*
  722. * Determine EXTBUS_DIV.
  723. */
  724. sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
  725. /*
  726. * Determine OPB_DIV.
  727. */
  728. sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
  729. /*
  730. * Determine the M factor
  731. */
  732. m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
  733. /*
  734. * Determine VCO clock frequency
  735. */
  736. sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
  737. (unsigned long long)sysClkPeriodPs;
  738. /*
  739. * Determine CPU clock frequency
  740. */
  741. pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
  742. if (pllmr1 & PLLMR1_SSCS_MASK) {
  743. /*
  744. * This is true if FWDVA == FWDVB:
  745. * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
  746. * / pllmr0_ccdv;
  747. */
  748. sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
  749. / sysInfo->pllFwdDiv / pllmr0_ccdv;
  750. } else {
  751. sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
  752. }
  753. /*
  754. * Determine PLB clock frequency
  755. */
  756. sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
  757. sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
  758. sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
  759. }
  760. /********************************************
  761. * get_OPB_freq
  762. * return OPB bus freq in Hz
  763. *********************************************/
  764. ulong get_OPB_freq (void)
  765. {
  766. ulong val = 0;
  767. PPC4xx_SYS_INFO sys_info;
  768. get_sys_info (&sys_info);
  769. val = sys_info.freqPLB / sys_info.pllOpbDiv;
  770. return val;
  771. }
  772. /********************************************
  773. * get_PCI_freq
  774. * return PCI bus freq in Hz
  775. *********************************************/
  776. ulong get_PCI_freq (void)
  777. {
  778. ulong val;
  779. PPC4xx_SYS_INFO sys_info;
  780. get_sys_info (&sys_info);
  781. val = sys_info.freqPLB / sys_info.pllPciDiv;
  782. return val;
  783. }
  784. #elif defined(CONFIG_405EZ)
  785. void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
  786. {
  787. unsigned long cpr_plld;
  788. unsigned long cpr_pllc;
  789. unsigned long cpr_primad;
  790. unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
  791. unsigned long primad_cpudv;
  792. unsigned long m;
  793. /*
  794. * Read PLL Mode registers
  795. */
  796. mfcpr(cprplld, cpr_plld);
  797. mfcpr(cprpllc, cpr_pllc);
  798. /*
  799. * Determine forward divider A
  800. */
  801. sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
  802. /*
  803. * Determine forward divider B
  804. */
  805. sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
  806. if (sysInfo->pllFwdDivB == 0)
  807. sysInfo->pllFwdDivB = 8;
  808. /*
  809. * Determine FBK_DIV.
  810. */
  811. sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
  812. if (sysInfo->pllFbkDiv == 0)
  813. sysInfo->pllFbkDiv = 256;
  814. /*
  815. * Read CPR_PRIMAD register
  816. */
  817. mfcpr(cprprimad, cpr_primad);
  818. /*
  819. * Determine PLB_DIV.
  820. */
  821. sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
  822. if (sysInfo->pllPlbDiv == 0)
  823. sysInfo->pllPlbDiv = 16;
  824. /*
  825. * Determine EXTBUS_DIV.
  826. */
  827. sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
  828. if (sysInfo->pllExtBusDiv == 0)
  829. sysInfo->pllExtBusDiv = 16;
  830. /*
  831. * Determine OPB_DIV.
  832. */
  833. sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
  834. if (sysInfo->pllOpbDiv == 0)
  835. sysInfo->pllOpbDiv = 16;
  836. /*
  837. * Determine the M factor
  838. */
  839. if (cpr_pllc & PLLC_SRC_MASK)
  840. m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
  841. else
  842. m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
  843. /*
  844. * Determine VCO clock frequency
  845. */
  846. sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
  847. (unsigned long long)sysClkPeriodPs;
  848. /*
  849. * Determine CPU clock frequency
  850. */
  851. primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
  852. if (primad_cpudv == 0)
  853. primad_cpudv = 16;
  854. sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
  855. sysInfo->pllFwdDiv / primad_cpudv;
  856. /*
  857. * Determine PLB clock frequency
  858. */
  859. sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
  860. sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
  861. sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
  862. sysInfo->pllExtBusDiv;
  863. sysInfo->freqUART = sysInfo->freqVCOHz;
  864. }
  865. /********************************************
  866. * get_OPB_freq
  867. * return OPB bus freq in Hz
  868. *********************************************/
  869. ulong get_OPB_freq (void)
  870. {
  871. ulong val = 0;
  872. PPC4xx_SYS_INFO sys_info;
  873. get_sys_info (&sys_info);
  874. val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
  875. return val;
  876. }
  877. #elif defined(CONFIG_405EX)
  878. /*
  879. * TODO: We need to get the CPR registers and calculate these values correctly!!!!
  880. * We need the specs!!!!
  881. */
  882. static unsigned char get_fbdv(unsigned char index)
  883. {
  884. unsigned char ret = 0;
  885. /* This is table should be 256 bytes.
  886. * Only take first 52 values.
  887. */
  888. unsigned char fbdv_tb[] = {
  889. 0x00, 0xff, 0x7f, 0xfd,
  890. 0x7a, 0xf5, 0x6a, 0xd5,
  891. 0x2a, 0xd4, 0x29, 0xd3,
  892. 0x26, 0xcc, 0x19, 0xb3,
  893. 0x67, 0xce, 0x1d, 0xbb,
  894. 0x77, 0xee, 0x5d, 0xba,
  895. 0x74, 0xe9, 0x52, 0xa5,
  896. 0x4b, 0x96, 0x2c, 0xd8,
  897. 0x31, 0xe3, 0x46, 0x8d,
  898. 0x1b, 0xb7, 0x6f, 0xde,
  899. 0x3d, 0xfb, 0x76, 0xed,
  900. 0x5a, 0xb5, 0x6b, 0xd6,
  901. 0x2d, 0xdb, 0x36, 0xec,
  902. };
  903. if ((index & 0x7f) == 0)
  904. return 1;
  905. while (ret < sizeof (fbdv_tb)) {
  906. if (fbdv_tb[ret] == index)
  907. break;
  908. ret++;
  909. }
  910. ret++;
  911. return ret;
  912. }
  913. #define PLL_FBK_PLL_LOCAL 0
  914. #define PLL_FBK_CPU 1
  915. #define PLL_FBK_PERCLK 5
  916. void get_sys_info (sys_info_t * sysInfo)
  917. {
  918. unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
  919. unsigned long m = 1;
  920. unsigned int tmp;
  921. unsigned char fwdva[16] = {
  922. 1, 2, 14, 9, 4, 11, 16, 13,
  923. 12, 5, 6, 15, 10, 7, 8, 3,
  924. };
  925. unsigned char sel, cpudv0, plb2xDiv;
  926. mfcpr(cpr0_plld, tmp);
  927. /*
  928. * Determine forward divider A
  929. */
  930. sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
  931. /*
  932. * Determine FBK_DIV.
  933. */
  934. sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
  935. /*
  936. * Determine PLBDV0
  937. */
  938. sysInfo->pllPlbDiv = 2;
  939. /*
  940. * Determine PERDV0
  941. */
  942. mfcpr(cpr0_perd, tmp);
  943. tmp = (tmp >> 24) & 0x03;
  944. sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
  945. /*
  946. * Determine OPBDV0
  947. */
  948. mfcpr(cpr0_opbd, tmp);
  949. tmp = (tmp >> 24) & 0x03;
  950. sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
  951. /* Determine PLB2XDV0 */
  952. mfcpr(cpr0_plbd, tmp);
  953. tmp = (tmp >> 16) & 0x07;
  954. plb2xDiv = (tmp == 0) ? 8 : tmp;
  955. /* Determine CPUDV0 */
  956. mfcpr(cpr0_cpud, tmp);
  957. tmp = (tmp >> 24) & 0x07;
  958. cpudv0 = (tmp == 0) ? 8 : tmp;
  959. /* Determine SEL(5:7) in CPR0_PLLC */
  960. mfcpr(cpr0_pllc, tmp);
  961. sel = (tmp >> 24) & 0x07;
  962. /*
  963. * Determine the M factor
  964. * PLL local: M = FBDV
  965. * CPU clock: M = FBDV * FWDVA * CPUDV0
  966. * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
  967. *
  968. */
  969. switch (sel) {
  970. case PLL_FBK_CPU:
  971. m = sysInfo->pllFwdDiv * cpudv0;
  972. break;
  973. case PLL_FBK_PERCLK:
  974. m = sysInfo->pllFwdDiv * plb2xDiv * 2
  975. * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
  976. break;
  977. case PLL_FBK_PLL_LOCAL:
  978. break;
  979. default:
  980. printf("%s unknown m\n", __FUNCTION__);
  981. return;
  982. }
  983. m *= sysInfo->pllFbkDiv;
  984. /*
  985. * Determine VCO clock frequency
  986. */
  987. sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
  988. (unsigned long long)sysClkPeriodPs;
  989. /*
  990. * Determine CPU clock frequency
  991. */
  992. sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
  993. /*
  994. * Determine PLB clock frequency, ddr1x should be the same
  995. */
  996. sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
  997. sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
  998. sysInfo->freqDDR = sysInfo->freqPLB;
  999. sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
  1000. sysInfo->freqUART = sysInfo->freqPLB;
  1001. }
  1002. /********************************************
  1003. * get_OPB_freq
  1004. * return OPB bus freq in Hz
  1005. *********************************************/
  1006. ulong get_OPB_freq (void)
  1007. {
  1008. ulong val = 0;
  1009. PPC4xx_SYS_INFO sys_info;
  1010. get_sys_info (&sys_info);
  1011. val = sys_info.freqPLB / sys_info.pllOpbDiv;
  1012. return val;
  1013. }
  1014. #endif
  1015. int get_clocks (void)
  1016. {
  1017. #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
  1018. defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
  1019. defined(CONFIG_405EX) || defined(CONFIG_405) || \
  1020. defined(CONFIG_440)
  1021. sys_info_t sys_info;
  1022. get_sys_info (&sys_info);
  1023. gd->cpu_clk = sys_info.freqProcessor;
  1024. gd->bus_clk = sys_info.freqPLB;
  1025. #endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
  1026. #ifdef CONFIG_IOP480
  1027. gd->cpu_clk = 66000000;
  1028. gd->bus_clk = 66000000;
  1029. #endif
  1030. return (0);
  1031. }
  1032. /********************************************
  1033. * get_bus_freq
  1034. * return PLB bus freq in Hz
  1035. *********************************************/
  1036. ulong get_bus_freq (ulong dummy)
  1037. {
  1038. ulong val;
  1039. #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
  1040. defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
  1041. defined(CONFIG_405EX) || defined(CONFIG_405) || \
  1042. defined(CONFIG_440)
  1043. sys_info_t sys_info;
  1044. get_sys_info (&sys_info);
  1045. val = sys_info.freqPLB;
  1046. #elif defined(CONFIG_IOP480)
  1047. val = 66;
  1048. #else
  1049. # error get_bus_freq() not implemented
  1050. #endif
  1051. return val;
  1052. }