00001
00019
00020
00021
00022
00023 #include "crm.h"
00024 #include "phy.h"
00025 #include "dbg.h"
00026 #include "reg_mac_core.h"
00027 #include "reg_mdm_stat.h"
00028 #include "reg_mdm_cfg.h"
00029 #include "reg_karst_if.h"
00030 #include <string.h>
00031
00032 #ifdef CFG_VIRTEX6
00033 #include "reg_fpgaa.h"
00034 #endif
00035
00036 #if NX_MDM_VER < 20 || NX_MDM_VER >= 30
00037 #error "This version of CRM is valid for modem version 2x only"
00038 #endif
00039
00042 #define MDM_CONF_0_9 1
00043
00044 #if NX_MDM_VER == 20
00045 #undef MDM_CONF_0_9
00046 #define MDM_CONF_0_9 0
00047 #endif
00048
00050 #define CRM_CLKCONF_UNDEFINED ((uint8_t)-1)
00051
00053 struct crm_env_tag
00054 {
00056 uint8_t clk_conf;
00058 uint8_t mac_freq;
00060 uint32_t cpu_freq;
00061 };
00062
00064 static struct crm_env_tag crm_env;
00065
00076 static int reg_poll(uint32_t reg, uint32_t val)
00077 {
00078 int loops = 1 << 20;
00079
00080 while ((REG_PL_RD(reg) & val) != val && --loops)
00081 ;
00082 if (!loops)
00083 {
00084 dbg(D_ERR D_PHY "%s @0x%08x 0x%08x failed\n", __func__, reg, val);
00085 return -1;
00086 }
00087 return !loops;
00088 }
00089
00097 static inline void udelay(uint32_t us)
00098 {
00099 uint32_t e = nxmac_monotonic_counter_2_lo_get() + us;
00100
00101 do {
00102 volatile int n = 1 << 5;
00103 while (n--)
00104 ;
00105 } while ((int32_t)(nxmac_monotonic_counter_2_lo_get() - e) < 0);
00106 }
00107
00108 #ifdef CFG_VIRTEX6
00109 static bool p40m_ok(void)
00110 {
00111 uint32_t pmref40, i;
00112 bool ok;
00113
00114 pmref40 = karst_pmetre_ref40_get();
00115 ok = true;
00116 for (i = 0; i < 2 * sizeof(uint32_t); i++) {
00117 int dig = (pmref40 & ((uint32_t)0xF << (4 * i))) >> (4 * i);
00118 if (dig != 3 && dig != 4) {
00119 ok = false;
00120 break;
00121 }
00122 }
00123 return ok;
00124 }
00125 #endif
00126
00127
00128
00130 #define CLKOUT0 0x08
00132 #define CLKOUT1 0x0A
00134 #define CLKOUT2 0x0C
00136 #define CLKOUT3 0x0E
00138 #define CLKOUT4 0x10
00140 #define CLKOUT5 0x06
00142 #define CLKOUT6 0x12
00144 #define CLKOUTFB 0x14
00145
00146
00150 #define MMCM_REG1(mmcm, out) \
00151 (KARST_DYNCFGMMC_WE_BIT | \
00152 (mmcm << KARST_DYNCFGMMC_SEL_LSB) | \
00153 CLKOUT##out)
00154
00156 #define MMCM_VCO_MULT(clk_ref_freq, vco_freq) \
00157 ((((vco_freq/clk_ref_freq) + 1) / 2) << 6 | \
00158 (((vco_freq/clk_ref_freq)) / 2) | \
00159 0x1000)
00160
00162 #define MMCM_VCO_DIV(vco_freq, target_freq) \
00163 ((((vco_freq/target_freq) + 1) / 2) << 6 | \
00164 (((vco_freq/target_freq)) / 2) | \
00165 0x1000)
00166
00168 #define MMCM_VCO_TO_NUM_DIV(vco_div) (((vco_div & 0x0FC0) >> 6) + (vco_div & 0x3F))
00169
00170 #if defined(CFG_VIRTEX6)
00171
00172 #define FPGAA_MMCM0_CLKIN 200
00173 #define FPGAA_MMCM0_VCO 1200
00174 #define MAC_CORE_CLK_ADDR MMCM_REG1(0, 1)
00175 #define MAC_WT_CLK_ADDR MMCM_REG1(0, 2)
00176 #define LP_120M_CLK_ADDR MMCM_REG1(0, 3)
00177 #define MAC_CORE_DIV(x) MMCM_VCO_DIV(FPGAA_MMCM0_VCO, x)
00178 #define MAC_WT_DIV(x) MMCM_VCO_DIV(FPGAA_MMCM0_VCO, x)
00179 #define LP_120M_DIV(x) MMCM_VCO_DIV(FPGAA_MMCM0_VCO, x)
00180 #define MAC_FREQ(x) (FPGAA_MMCM0_VCO / MMCM_VCO_TO_NUM_DIV(x))
00181
00182
00183 #define FPGAA_MMCM1_CLKIN 30
00184 #define FPGAA_MMCM1_VCO 960
00185 #define MPIF_FPGAA_CLK_ADDR MMCM_REG1(1, 1)
00186 #define LA_CLK_ADDR MMCM_REG1(1, 2)
00187 #define LA_DIV(x) MMCM_VCO_DIV(FPGAA_MMCM1_VCO, x)
00188
00189
00190 #define KARST_MMCM0_CLKIN 30
00191 #define KARST_MMCM0_VCO 960
00192 #define MPIF_CLK_ADDR MMCM_REG1(0, 6)
00193 #define MPIF_DIV(x) MMCM_VCO_DIV(KARST_MMCM0_VCO, x)
00194 #define FE_CLK_ADDR MMCM_REG1(0, 4)
00195 #define FE_DIV(x) MMCM_VCO_DIV(KARST_MMCM0_VCO, x)
00196 #define PHY_CLK_ADDR MMCM_REG1(0, 5)
00197 #define PHY_DIV(x) MMCM_VCO_DIV(KARST_MMCM0_VCO, x)
00198
00199
00200 #define KARST_MMCM1_CLKIN 30
00201 #define KARST_MMCM1_VCO 840
00202 #define BD_CLK_ADDR MMCM_REG1(1, 6)
00203 #define BD_DIV(x) MMCM_VCO_DIV(840, x)
00204 #define KARST_FB_CLK_ADDR MMCM_REG1(1, FB)
00205
00206 #elif defined(CFG_VIRTEX7)
00207
00208
00209 #define KARST_MMCM0_CLKIN 40
00210 #define KARST_MMCM0_VCO 960
00211 #define MPIF_CLK_ADDR MMCM_REG1(0, 6)
00212 #define MPIF_DIV(x) MMCM_VCO_DIV(KARST_MMCM0_VCO, x)
00213 #define FE_CLK_ADDR MMCM_REG1(0, 4)
00214 #define FE_DIV(x) MMCM_VCO_DIV(KARST_MMCM0_VCO, x)
00215 #define PHY_CLK_ADDR MMCM_REG1(0, 5)
00216 #define PHY_DIV(x) MMCM_VCO_DIV(KARST_MMCM0_VCO, x)
00217 #define LA_CLK_ADDR MMCM_REG1(0, 0)
00218 #define LA_DIV(x) MMCM_VCO_DIV(KARST_MMCM0_VCO, x)
00219
00220
00221 #define KARST_MMCM1_CLKIN 40
00222 #define KARST_MMCM1_VCO 840
00223 #define BD_CLK_ADDR MMCM_REG1(1, 6)
00224 #define BD_DIV(x) MMCM_VCO_DIV(840, x)
00225 #define KARST_FB_CLK_ADDR MMCM_REG1(1, FB)
00226
00227
00228 #define KARST_MMCM2_CLKIN 25
00229 #define KARST_MMCM2_VCO 1200
00230 #define MAC_CORE_CLK_ADDR MMCM_REG1(2, 1)
00231 #define MAC_WT_CLK_ADDR MMCM_REG1(2, 2)
00232 #define MAC_CORE_DIV(x) MMCM_VCO_DIV(KARST_MMCM2_VCO, x)
00233 #define MAC_WT_DIV(x) MMCM_VCO_DIV(KARST_MMCM2_VCO, x)
00234 #define MAC_FREQ(x) (KARST_MMCM2_VCO / MMCM_VCO_TO_NUM_DIV(x))
00235
00236 #endif
00237
00239 struct clk_config {
00241 struct mpif_config {
00243 uint16_t mpif_div;
00245 uint16_t la_div;
00247 uint16_t la_clock;
00248 } mpif[2];
00249
00250 struct mac_config {
00252 uint16_t mac_div;
00254 uint16_t wt_div;
00255 } mac[2];
00256
00257 uint16_t fe_div;
00259 uint16_t phy_div;
00261 uint16_t bd_div;
00262 };
00263
00265 static const struct clk_config clk_config[10] = {
00266
00267 {
00268 .mpif[0] = { .mpif_div = MPIF_DIV(30),
00269 .la_div = LA_DIV(60),
00270 .la_clock = 60 },
00271 .mpif[1] = { .mpif_div = MPIF_DIV(30),
00272 .la_div = LA_DIV(60),
00273 .la_clock = 60 },
00274 .mac[0] = { .mac_div = MAC_CORE_DIV(40),
00275 .wt_div = MAC_WT_DIV(80) },
00276 .mac[1] = { .mac_div = MAC_CORE_DIV(40),
00277 .wt_div = MAC_WT_DIV(80) },
00278 .fe_div = FE_DIV(40),
00279 .phy_div = PHY_DIV(60),
00280 .bd_div = BD_DIV(60),
00281 },
00282
00283
00284 {
00285 .mpif[0] = { .mpif_div = MPIF_DIV(30),
00286 .la_div = LA_DIV(60),
00287 .la_clock = 60 },
00288 .mpif[1] = { .mpif_div = MPIF_DIV(30),
00289 .la_div = LA_DIV(60),
00290 .la_clock = 60 },
00291 .mac[0] = { .mac_div = MAC_CORE_DIV(40),
00292 .wt_div = MAC_WT_DIV(80) },
00293 .mac[1] = { .mac_div = MAC_CORE_DIV(40),
00294 .wt_div = MAC_WT_DIV(80) },
00295 .fe_div = FE_DIV(40),
00296 .phy_div = PHY_DIV(60),
00297 .bd_div = BD_DIV(84),
00298 },
00299
00300
00301 {
00302 .mpif[0] = { .mpif_div = MPIF_DIV(60),
00303 .la_div = LA_DIV(120),
00304 .la_clock = 120 },
00305 .mpif[1] = { .mpif_div = MPIF_DIV(60),
00306 .la_div = LA_DIV(120),
00307 .la_clock = 120 },
00308 .mac[0] = { .mac_div = MAC_CORE_DIV(40),
00309 .wt_div = MAC_WT_DIV(80) },
00310 .mac[1] = { .mac_div = MAC_CORE_DIV(40),
00311 .wt_div = MAC_WT_DIV(80) },
00312 .fe_div = FE_DIV(80),
00313 .phy_div = PHY_DIV(120),
00314 .bd_div = BD_DIV(120),
00315 },
00316
00317
00318 {
00319 .mpif[0] = { .mpif_div = MPIF_DIV(60),
00320 .la_div = LA_DIV(120),
00321 .la_clock = 120 },
00322 .mpif[1] = { .mpif_div = MPIF_DIV(60),
00323 .la_div = LA_DIV(120),
00324 .la_clock = 120 },
00325 .mac[0] = { .mac_div = MAC_CORE_DIV(80),
00326 .wt_div = MAC_WT_DIV(80) },
00327 .mac[1] = { .mac_div = MAC_CORE_DIV(40),
00328 .wt_div = MAC_WT_DIV(80) },
00329 .fe_div = FE_DIV(80),
00330 .phy_div = PHY_DIV(120),
00331 .bd_div = BD_DIV(168),
00332 },
00333
00334
00335 {
00336 .mpif[0] = { .mpif_div = MPIF_DIV(60),
00337 .la_div = LA_DIV(120),
00338 .la_clock = 120 },
00339 .mpif[1] = { .mpif_div = MPIF_DIV(60),
00340 .la_div = LA_DIV(120),
00341 .la_clock = 120 },
00342 .mac[0] = { .mac_div = MAC_CORE_DIV(80),
00343 .wt_div = MAC_WT_DIV(80) },
00344 .mac[1] = { .mac_div = MAC_CORE_DIV(40),
00345 .wt_div = MAC_WT_DIV(80) },
00346 .fe_div = FE_DIV(160),
00347 .phy_div = PHY_DIV(120),
00348 .bd_div = BD_DIV(168),
00349 },
00350
00351
00352 {
00353 .mpif[0] = { .mpif_div = MPIF_DIV(120),
00354 .la_div = LA_DIV(120),
00355 .la_clock = 120 },
00356 .mpif[1] = { .mpif_div = MPIF_DIV(80),
00357 .la_div = LA_DIV(160),
00358 .la_clock = 160 },
00359 .mac[0] = { .mac_div = MAC_CORE_DIV(100),
00360 .wt_div = MAC_WT_DIV(100) },
00361 .mac[1] = { .mac_div = MAC_CORE_DIV(40),
00362 .wt_div = MAC_WT_DIV(80) },
00363 .fe_div = FE_DIV(160),
00364 .phy_div = PHY_DIV(120),
00365 #if defined(CFG_VIRTEX6)
00366 .bd_div = BD_DIV(210),
00367 #elif defined(CFG_VIRTEX7)
00368 .bd_div = BD_DIV(168),
00369 #endif
00370 },
00371
00372
00373 {
00374 .mpif[0] = { .mpif_div = MPIF_DIV(120),
00375 .la_div = LA_DIV(120),
00376 .la_clock = 120 },
00377 .mpif[1] = { .mpif_div = MPIF_DIV(80),
00378 .la_div = LA_DIV(160),
00379 .la_clock = 160 },
00380 .mac[0] = { .mac_div = MAC_CORE_DIV(100),
00381 .wt_div = MAC_WT_DIV(100) },
00382 .mac[1] = { .mac_div = MAC_CORE_DIV(40),
00383 .wt_div = MAC_WT_DIV(80) },
00384 .fe_div = FE_DIV(160),
00385 .phy_div = PHY_DIV(120),
00386 #if defined(CFG_VIRTEX6)
00387 .bd_div = BD_DIV(210),
00388 #elif defined(CFG_VIRTEX7)
00389 .bd_div = BD_DIV(168),
00390 #endif
00391 },
00392
00393
00394 {
00395 .mpif[0] = { .mpif_div = MPIF_DIV(120),
00396 .la_div = LA_DIV(120),
00397 .la_clock = 120 },
00398 .mpif[1] = { .mpif_div = MPIF_DIV(80),
00399 .la_div = LA_DIV(160),
00400 .la_clock = 160 },
00401 .mac[0] = { .mac_div = MAC_CORE_DIV(80),
00402 .wt_div = MAC_WT_DIV(80) },
00403 .mac[1] = { .mac_div = MAC_CORE_DIV(40),
00404 .wt_div = MAC_WT_DIV(80) },
00405 .fe_div = FE_DIV(160),
00406 .phy_div = PHY_DIV(120),
00407 .bd_div = BD_DIV(168),
00408 },
00409
00410
00411 {
00412 .mpif[0] = { .mpif_div = MPIF_DIV(60),
00413 .la_div = LA_DIV(120),
00414 .la_clock = 120 },
00415 .mpif[1] = { .mpif_div = MPIF_DIV(60),
00416 .la_div = LA_DIV(120),
00417 .la_clock = 120 },
00418 .mac[0] = { .mac_div = MAC_CORE_DIV(80),
00419 .wt_div = MAC_WT_DIV(80) },
00420 .mac[1] = { .mac_div = MAC_CORE_DIV(40),
00421 .wt_div = MAC_WT_DIV(80) },
00422 .fe_div = FE_DIV(40),
00423 .phy_div = PHY_DIV(60),
00424 .bd_div = BD_DIV(120),
00425 },
00426
00427
00428 {
00429 .mpif[0] = { .mpif_div = MPIF_DIV(120),
00430 .la_div = LA_DIV(120),
00431 .la_clock = 120 },
00432 .mpif[1] = { .mpif_div = MPIF_DIV(80),
00433 .la_div = LA_DIV(160),
00434 .la_clock = 160 },
00435 .mac[0] = { .mac_div = MAC_CORE_DIV(80),
00436 .wt_div = MAC_WT_DIV(80) },
00437 .mac[1] = { .mac_div = MAC_CORE_DIV(40),
00438 .wt_div = MAC_WT_DIV(80) },
00439 .fe_div = FE_DIV(80),
00440 .phy_div = PHY_DIV(120),
00441 #if defined(CFG_VIRTEX6)
00442 .bd_div = BD_DIV(210),
00443 #elif defined(CFG_VIRTEX7)
00444 .bd_div = BD_DIV(168),
00445 #endif
00446 }
00447 };
00448
00449
00458 static void crm_mmc_clk_set(uint32_t addr, uint16_t data)
00459 {
00460 karst_dyncfgmmc_addr_set(addr);
00461 karst_dyncfgmmc_data_set(data);
00462 karst_dyncfgmmc_cntl_set(KARST_DYNCFGMMC_START_BIT);
00463 reg_poll(KARST_DYNCFGMMC_CNTL_ADDR, KARST_DYNCFGMMC_START_BIT | KARST_DYNCFGMMC_DONE_BIT);
00464 karst_dyncfgmmc_cntl_set(0);
00465 }
00466
00467 #ifdef CFG_VIRTEX6
00468 static void fpgaa_mmc_clk_set(uint32_t addr, uint16_t data)
00469 {
00470 fpgaa_dyncfgmmc_addr_set(addr);
00471 fpgaa_dyncfgmmc_data_set(data);
00472 fpgaa_dyncfgmmc_cntl_set(FPGAA_DYNCFGMMC_START_BIT);
00473 reg_poll(FPGAA_DYNCFGMMC_CNTL_ADDR, FPGAA_DYNCFGMMC_START_BIT | FPGAA_DYNCFGMMC_DONE_BIT);
00474 fpgaa_dyncfgmmc_cntl_set(0);
00475 }
00476 #endif
00477
00487 static int crm_clk_conf(uint8_t chan_type)
00488 {
00489 int nss = mdm_nss_getf();
00490 int ldpc = mdm_ldpcdec_getf();
00491 #if MDM_CONF_0_9
00492 bool vht_supp = phy_vht_supported();
00493 #endif
00494 int clkconf = 0;
00495
00496 switch (chan_type)
00497 {
00498 case PHY_CHNL_BW_20:
00499 #if MDM_CONF_0_9
00500 if (ldpc)
00501 clkconf = 8;
00502 else if (nss == 1)
00503 clkconf = 0;
00504 else
00505 clkconf = 1;
00506 #else
00507 if (nss == 1)
00508 clkconf = 0;
00509 else
00510 clkconf = 1;
00511 #endif
00512 break;
00513 case PHY_CHNL_BW_40:
00514 #if MDM_CONF_0_9
00515 if (nss == 1)
00516 clkconf = 2;
00517 else if (!vht_supp)
00518 clkconf = 3;
00519 else
00520 clkconf = 9;
00521 #else
00522 if (nss == 1)
00523 clkconf = 2;
00524 else
00525 clkconf = 3;
00526 #endif
00527 break;
00528 case PHY_CHNL_BW_80:
00529 if (nss == 1)
00530 {
00531 if (ldpc)
00532 clkconf = 7;
00533 else
00534 clkconf = 4;
00535 }
00536 else
00537 {
00538 if (ldpc)
00539 clkconf = 6;
00540 else
00541 clkconf = 5;
00542 }
00543 break;
00544 default:
00545 ASSERT_ERR(0);
00546 break;
00547 }
00548
00549 return clkconf;
00550 }
00551
00552 void crm_clk_set(uint8_t chan_type)
00553 {
00554 int clkconf = crm_clk_conf(chan_type);
00555
00556
00557 if (clkconf == crm_env.clk_conf)
00558 return;
00559
00560 crm_env.clk_conf = clkconf;
00561
00562
00563 crm_mmc_clk_set(KARST_FB_CLK_ADDR, MMCM_VCO_MULT(KARST_MMCM1_CLKIN, KARST_MMCM1_VCO));
00564
00565 crm_mmc_clk_set(FE_CLK_ADDR, clk_config[clkconf].fe_div);
00566 crm_mmc_clk_set(PHY_CLK_ADDR, clk_config[clkconf].phy_div);
00567 crm_mmc_clk_set(BD_CLK_ADDR, clk_config[clkconf].bd_div);
00568
00569 #ifdef CFG_VIRTEX6
00570
00571 karst_dyncfgmmc_addr_set(0);
00572 do
00573 {
00574 karst_dyncfgmmc_cntl_set(KARST_DYNCFGMMC_START_BIT);
00575 reg_poll(KARST_DYNCFGMMC_CNTL_ADDR, KARST_DYNCFGMMC_START_BIT | KARST_DYNCFGMMC_DONE_BIT);
00576
00577 reg_poll(KARST_CLKRST_STAT_ADDR, KARST_MMC_LOCK_MASK);
00578 karst_dyncfgmmc_cntl_set(0);
00579 } while (!p40m_ok() && ({udelay(0); 1;}));
00580 #endif
00581
00582 mdm_mdmconf_setf(clkconf);
00583 }
00584
00585 void crm_init(void)
00586 {
00587 int clkconf = crm_clk_conf(mdm_chbw_getf());
00588 int mac_clck_id;
00589 uint16_t mac_div;
00590
00591 memset(&crm_env, 0, sizeof(crm_env));
00592
00593
00594
00595 mac_clck_id = (nxmac_mac_core_clk_freq_getf() < 60) ? 1 : 0;
00596
00597 crm_mmc_clk_set(MPIF_CLK_ADDR, clk_config[clkconf].mpif[mac_clck_id].mpif_div);
00598
00599 mac_div = clk_config[clkconf].mac[mac_clck_id].mac_div;
00600
00601 #if defined(CFG_VIRTEX6)
00602 fpgaa_mmc_clk_set(MPIF_FPGAA_CLK_ADDR, clk_config[clkconf].mpif[mac_clck_id].mpif_div);
00603 fpgaa_mmc_clk_set(LA_CLK_ADDR, clk_config[clkconf].mpif[mac_clck_id].la_div);
00604 fpgaa_la_sampling_freq_set(clk_config[clkconf].mpif[mac_clck_id].la_clock);
00605
00606 fpgaa_mmc_clk_set(MAC_CORE_CLK_ADDR, mac_div);
00607 fpgaa_mmc_clk_set(MAC_WT_CLK_ADDR, clk_config[clkconf].mac[mac_clck_id].wt_div);
00608
00609 #elif defined(CFG_VIRTEX7)
00610 crm_mmc_clk_set(LA_CLK_ADDR, clk_config[clkconf].mpif[mac_clck_id].la_div);
00611 karst_la_sampling_freq_set(clk_config[clkconf].mpif[mac_clck_id].la_clock);
00612
00613 crm_mmc_clk_set(MAC_CORE_CLK_ADDR, mac_div);
00614 crm_mmc_clk_set(MAC_WT_CLK_ADDR, clk_config[clkconf].mac[mac_clck_id].wt_div);
00615 #endif
00616
00617 crm_env.clk_conf = CRM_CLKCONF_UNDEFINED;
00618 crm_env.mac_freq = MAC_FREQ(mac_div);
00619
00620 #if defined(CFG_VIRTEX6)
00621 crm_env.cpu_freq = 105000000;
00622 #elif defined(CFG_VIRTEX7)
00623 karst_fmetre_start_setf(1);
00624 while(!karst_fmetre_done_getf()) {};
00625 crm_env.cpu_freq = karst_fmetre_plf_getf() * 1000;
00626 karst_dyncfgmmc_cntl_set(0);
00627 #endif
00628 }
00629
00630 bool crm_fe_160m(void)
00631 {
00632 if (crm_env.clk_conf != CRM_CLKCONF_UNDEFINED)
00633 {
00634 return (clk_config[crm_env.clk_conf].fe_div == FE_DIV(160));
00635 }
00636
00637 return false;
00638 }
00639
00640 uint8_t crm_get_mac_freq(void)
00641 {
00642 return (crm_env.mac_freq);
00643 }
00644
00645 uint32_t crm_get_cpu_freq(void)
00646 {
00647 return (crm_env.cpu_freq);
00648 }
00649
00650 void crm_mdm_reset(void)
00651 {
00652 mdm_swreset_set(MDM_AGCSWRESET_BIT | MDM_DSPSWRESET_BIT | MDM_MDMSWRESET_BIT);
00653 udelay(10);
00654 mdm_swreset_set(0x0);
00655 udelay(10);
00656 }
00657
00659