📄 clock_34xx.c
字号:
ret = -EINVAL; } else if (clk->set_rate != 0) { /*call clk specific rate func*/ ret = clk->set_rate(clk, rate); } } if (ret == 0) clk->recalc(clk); return ret;}/* Change the parent of a clock */static int omap3_clk_set_parent(struct clk *cclk, struct clk *new_parent){ int ret = -EINVAL; DPRINTK("Clock name: %s, Parent name: %s\n", cclk->name, new_parent->name); if ((cclk->flags & VDD1_CONFIG_PARTICIPANT) || (cclk->flags & VDD2_CONFIG_PARTICIPANT)) return ret; if (!(cclk->flags & SRC_SEL)) return ret; if (cclk->usecount > 0) /*if clock is currently active. */ _omap3_clk_disable(cclk); /* shut down clock to stop glitch */ ret = prcm_clk_set_source(cclk->prcmid, new_parent->prcmid); if (ret != PRCM_PASS) ret = -EINVAL; if (cclk->usecount > 0) _omap3_clk_enable(cclk); if (ret == 0) { cclk->parent = new_parent; cclk->recalc(cclk); } return ret;}/* Return the parent of a clock */static struct clk *omap3_clk_get_parent(struct clk *clk){ return clk->parent;}static void omap3_table_recalc(struct clk *clk){ if ((clk != &virt_vdd1_prcm_set) && (clk != &virt_vdd2_prcm_set)) return; if (clk == &virt_vdd1_prcm_set) clk->rate = curr_vdd1_prcm_set->speed; else clk->rate = curr_vdd2_prcm_set->speed; DPRINTK("CLK RATE:%lu\n", clk->rate);}static long omap3_round_to_table_rate(struct clk *clk, unsigned long rate){ struct vdd_prcm_config *ptr; long highest_rate; if ((clk != &virt_vdd1_prcm_set) && (clk != &virt_vdd2_prcm_set)) return -EINVAL; highest_rate = -EINVAL; if (clk == &virt_vdd1_prcm_set) ptr = vdd1_rate_table + MAX_VDD1_OPP; else ptr = vdd2_rate_table + MAX_VDD2_OPP; for (; ptr->speed; ptr--) { highest_rate = ptr->speed; DPRINTK("Highest speed : %lu, rate: %lu\n", highest_rate, rate); if (ptr->speed <= rate) break; } return highest_rate;}static int omap3_select_table_rate(struct clk *clk, unsigned long rate){ u8 cpu_mask = 0; u32 cur_vdd_rate, current_opp; struct vdd_prcm_config *prcm_vdd; unsigned long found_speed = 0; int ret = -EINVAL; int div = 0; if ((clk != &virt_vdd1_prcm_set) && (clk != &virt_vdd2_prcm_set)) return ret; if (cpu_is_omap3430()) cpu_mask = RATE_IN_343X; if (clk == &virt_vdd1_prcm_set) prcm_vdd = vdd1_rate_table + MAX_VDD1_OPP; else prcm_vdd = vdd2_rate_table + MAX_VDD2_OPP; for (; prcm_vdd->speed; prcm_vdd--) { if (!(prcm_vdd->flags & cpu_mask)) continue; if (prcm_vdd->speed <= rate) { found_speed = prcm_vdd->speed; DPRINTK("Found speed = %lu\n", found_speed); break; } } if (!found_speed) { printk(KERN_INFO "Could not set table rate to %luMHz\n", rate / 1000000); return -EINVAL; } if (clk == &virt_vdd1_prcm_set) { ret = prcm_get_processor_speed(clk->parent->prcmid, &cur_vdd_rate); if (ret != PRCM_PASS) return -EINVAL; current_opp = curr_vdd1_prcm_set->opp; } else { ret = prcm_get_dpll_rate(clk->parent->prcmid, &cur_vdd_rate); if (ret != PRCM_PASS) return -EINVAL; /* Now cur_vdd_rate holds value of core_ck */ /* The divider for l3_ck */ ret = prcm_clksel_get_divider((&l3_ck)->prcmid, &div); if ((ret != PRCM_PASS) || (div == 0)) return -EINVAL; cur_vdd_rate /= div; current_opp = curr_vdd2_prcm_set->opp; } cur_vdd_rate *= 1000; DPRINTK("Current rate:%lu\n", cur_vdd_rate); if (cur_vdd_rate != found_speed) { ret = prcm_do_frequency_scaling(prcm_vdd->opp, current_opp); if (ret != PRCM_PASS) return -EINVAL; } if (clk == &virt_vdd1_prcm_set) { curr_vdd1_prcm_set = prcm_vdd; omap3_clk_recalc(&mpu_ck); omap3_propagate_rate(&mpu_ck); omap3_clk_recalc(&iva2_ck); omap3_propagate_rate(&iva2_ck); /*Update loops_per_jiffy if processor speed is being changed*/ loops_per_jiffy = compute_lpj(loops_per_jiffy, (cur_vdd_rate / 1000), (found_speed / 1000)); } else { curr_vdd2_prcm_set = prcm_vdd; omap3_clk_recalc(&core_ck); omap3_propagate_rate(&core_ck); omap3_clk_recalc(&core_x2_ck); omap3_propagate_rate(&core_x2_ck); omap3_clk_recalc(&emul_core_alwon_ck); omap3_propagate_rate(&emul_core_alwon_ck); } return 0;}/*-------------------------------------------------------------------------* * Omap3 clock reset and init functions *-------------------------------------------------------------------------*//* If usecount of clock is 0, disable it */static void omap3_disable_unused_clocks(struct clk *clk){ DPRINTK("Disabling unused clock \"%s\"...\n ", clk->name); _omap3_clk_disable(clk);}/* Get the rate of oscillator by calling PRCM API */static void omap3_get_crystal_rate(struct clk *osc){ osc->rate = prcm_get_crystal_rate() * 1000; DPRINTK("Rate:%d\n", osc->rate);}static struct clk_functions omap3_clk_functions = { .clk_enable = omap3_clk_enable, .clk_disable = omap3_clk_disable, .clk_round_rate = omap3_clk_round_rate, .clk_set_rate = omap3_clk_set_rate, .clk_set_parent = omap3_clk_set_parent, .clk_get_parent = omap3_clk_get_parent, .clk_disable_unused = omap3_disable_unused_clocks,};/* * Set clocks for bypass mode for reboot to work. */void omap3_clk_prepare_for_reboot(void){ /* Will be implemented when frequency change code is in place */ return;}/* Get the parent clocks by reading registers and populate the clock nodes with the correct parent information */static int omap3_update_sources(void){ struct clk **clkptr; struct clk *cp; u32 pid = 0, ret = -EINVAL; for (clkptr = onchip_clks; clkptr < onchip_clks + ARRAY_SIZE(onchip_clks); clkptr++) { cp = *clkptr; if (cp->flags & SRC_SEL) { ret = prcm_clk_get_source(cp->prcmid, &pid); if (ret != PRCM_PASS) { DPRINTK(KERN_ERR "prcm_clk_get_source returned error for %s\n", cp->name); return -EINVAL; } switch (cp->prcmid) { case PRCM_48M_FCLK: if (pid == PRCM_DPLL4_M2X2_CLK) cp->parent = &func_96m_ck; else cp->parent = &sys_alt_ck; break; case PRCM_TVOUT: if (pid == PRCM_DPLL4_M3X2_CLK) cp->parent = &dpll4_m3x2_ck; else cp->parent = &sys_alt_ck; break; case PRCM_USIM: if (pid == PRCM_SYS_CLK) cp->parent = &sys_ck; else if (pid == PRCM_DPLL4_M2X2_CLK) cp->parent = &cm_96m_ck; else cp->parent = &ext_mcbsp_ck; break; case PRCM_SGX_FCLK: if (pid == PRCM_DPLL3_M2_CLK) cp->parent = &core_ck; else cp->parent = &ext_mcbsp_ck; break; case PRCM_96M_CLK: if (pid == PRCM_DPLL4_M2X2_CLK) cp->parent = &cm_96m_ck; else cp->parent = &sys_ck; break; case PRCM_SYS_CLKOUT2: if (pid == PRCM_DPLL3_M2_CLK) cp->parent = &core_ck; else if (pid == PRCM_SYS_CLK) cp->parent = &sys_ck; else if (pid == PRCM_DPLL4_M2X2_CLK) cp->parent = &func_96m_ck; else cp->parent = &dss_tv_fck; break; case PRCM_MCBSP1: case PRCM_MCBSP2: case PRCM_MCBSP3: case PRCM_MCBSP4: case PRCM_MCBSP5: if (pid == PRCM_DPLL4_M2X2_CLK) cp->parent = &func_96m_ck; else cp->parent = &ext_mcbsp_ck; break; case PRCM_GPT1: case PRCM_GPT2: case PRCM_GPT3: case PRCM_GPT4: case PRCM_GPT5: case PRCM_GPT6: case PRCM_GPT7: case PRCM_GPT8: case PRCM_GPT9: case PRCM_GPT10: case PRCM_GPT11: if (pid == PRCM_SYS_32K_CLK) cp->parent = &sys_32k_ck; else cp->parent = &sys_ck; } DPRINTK("Parent updated for clock: %s\n", cp->name); DPRINTK("Parent name: %s\n", cp->parent->name); } } return 0;}/* Arch specific init */static int __init omap3_clk_arch_init(void){ struct vdd_prcm_config *vdd1_prcm; struct vdd_prcm_config *vdd2_prcm; u32 sys_clk_speed, mpu_speed, core_speed, l3_speed = 0; int div; /* Lock DPLL5 */ if (prcm_configure_dpll(DPLL5_PER2, -1, -1, -1)) panic("FATAL ERROR: Unable to Configure DPLL5\n"); if (prcm_enable_dpll(DPLL5_PER2)) panic("FATAL ERROR: Unable to Lock DPLL5\n"); omap3_get_crystal_rate(&osc_ck); omap3_update_sources(); sys_clk_speed = prcm_get_system_clock_speed() * 1000; prcm_get_processor_speed(DOM_MPU, &mpu_speed); mpu_speed = mpu_speed * 1000; prcm_get_dpll_rate((&core_ck)->prcmid, &core_speed); core_speed = core_speed * 1000; prcm_clksel_get_divider((&l3_ck)->prcmid, &div); if (div != 0) l3_speed = core_speed / div; else printk(KERN_ERR"Error: Divider for L3 returned 0 in omap3_clk" "_arch_init\n"); DPRINTK("System clock speed: %lu, mpu speed : %lu, l3_speed : %lu" "\n", sys_clk_speed, mpu_speed, l3_speed); for (vdd1_prcm = vdd1_rate_table+MAX_VDD1_OPP; vdd1_prcm->speed; vdd1_prcm--) { DPRINTK("%lu\n", vdd1_prcm->speed); if (vdd1_prcm->speed <= mpu_speed) break; } curr_vdd1_prcm_set = vdd1_prcm; for (vdd2_prcm = vdd2_rate_table+MAX_VDD2_OPP; vdd2_prcm->speed; vdd2_prcm++) { DPRINTK("%lu\n", vdd2_prcm->speed); if (vdd2_prcm->speed <= l3_speed) break; } curr_vdd2_prcm_set = vdd2_prcm; propagate_rate(&osc_ck); /* update main root fast */ propagate_rate(&sys_32k_ck); /* update main root slow */ propagate_rate(&sys_alt_ck); /* update alt ck tree */ DPRINTK("Rate propagation done for all clocks\n"); return 0;}arch_initcall(omap3_clk_arch_init);int __init omap3_clk_init(void){ struct clk **clkp; resource_init(); clk_init(&omap3_clk_functions); for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks); clkp++) { if ((*clkp)->flags & CLOCK_IN_OMAP343X) { clk_register(*clkp); continue; } } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -