clock.c
来自「底层驱动开发」· C语言 代码 · 共 1,339 行 · 第 1/3 页
C
1,339 行
if (unlikely(clk->flags & RATE_PROPAGATES)) propagate_rate(clk);}long clk_round_rate(struct clk *clk, unsigned long rate){ int dsor_exp; if (clk->flags & RATE_FIXED) return clk->rate; if (clk->flags & RATE_CKCTL) { dsor_exp = calc_dsor_exp(clk, rate); if (dsor_exp < 0) return dsor_exp; if (dsor_exp > 3) dsor_exp = 3; return clk->parent->rate / (1 << dsor_exp); } if(clk->round_rate != 0) return clk->round_rate(clk, rate); return clk->rate;}EXPORT_SYMBOL(clk_round_rate);static void propagate_rate(struct clk * clk){ struct clk ** clkp; for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) { if (likely((*clkp)->parent != clk)) continue; if (likely((*clkp)->recalc)) (*clkp)->recalc(*clkp); }}static int select_table_rate(struct clk * clk, unsigned long rate){ /* Find the highest supported frequency <= rate and switch to it */ struct mpu_rate * ptr; if (clk != &virtual_ck_mpu) return -EINVAL; for (ptr = rate_table; ptr->rate; ptr++) { if (ptr->xtal != ck_ref.rate) continue; /* DPLL1 cannot be reprogrammed without risking system crash */ if (likely(ck_dpll1.rate!=0) && ptr->pll_rate != ck_dpll1.rate) continue; /* Can check only after xtal frequency check */ if (ptr->rate <= rate) break; } if (!ptr->rate) return -EINVAL; /* * In most cases we should not need to reprogram DPLL. * Reprogramming the DPLL is tricky, it must be done from SRAM. */ omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val); ck_dpll1.rate = ptr->pll_rate; propagate_rate(&ck_dpll1); return 0;}static long round_to_table_rate(struct clk * clk, unsigned long rate){ /* Find the highest supported frequency <= rate */ struct mpu_rate * ptr; long highest_rate; if (clk != &virtual_ck_mpu) return -EINVAL; highest_rate = -EINVAL; for (ptr = rate_table; ptr->rate; ptr++) { if (ptr->xtal != ck_ref.rate) continue; highest_rate = ptr->rate; /* Can check only after xtal frequency check */ if (ptr->rate <= rate) break; } return highest_rate;}int clk_set_rate(struct clk *clk, unsigned long rate){ int ret = -EINVAL; int dsor_exp; __u16 regval; unsigned long flags; if (clk->flags & RATE_CKCTL) { dsor_exp = calc_dsor_exp(clk, rate); if (dsor_exp > 3) dsor_exp = -EINVAL; if (dsor_exp < 0) return dsor_exp; spin_lock_irqsave(&clockfw_lock, flags); regval = omap_readw(ARM_CKCTL); regval &= ~(3 << clk->rate_offset); regval |= dsor_exp << clk->rate_offset; regval = verify_ckctl_value(regval); omap_writew(regval, ARM_CKCTL); clk->rate = clk->parent->rate / (1 << dsor_exp); spin_unlock_irqrestore(&clockfw_lock, flags); ret = 0; } else if(clk->set_rate != 0) { spin_lock_irqsave(&clockfw_lock, flags); ret = clk->set_rate(clk, rate); spin_unlock_irqrestore(&clockfw_lock, flags); } if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES))) propagate_rate(clk); return ret;}EXPORT_SYMBOL(clk_set_rate);static unsigned calc_ext_dsor(unsigned long rate){ unsigned dsor; /* MCLK and BCLK divisor selection is not linear: * freq = 96MHz / dsor * * RATIO_SEL range: dsor <-> RATIO_SEL * 0..6: (RATIO_SEL+2) <-> (dsor-2) * 6..48: (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6) * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9 * can not be used. */ for (dsor = 2; dsor < 96; ++dsor) { if ((dsor & 1) && dsor > 8) continue; if (rate >= 96000000 / dsor) break; } return dsor;}/* Only needed on 1510 */static int set_uart_rate(struct clk * clk, unsigned long rate){ unsigned int val; val = omap_readl(clk->enable_reg); if (rate == 12000000) val &= ~(1 << clk->enable_bit); else if (rate == 48000000) val |= (1 << clk->enable_bit); else return -EINVAL; omap_writel(val, clk->enable_reg); clk->rate = rate; return 0;}static int set_ext_clk_rate(struct clk * clk, unsigned long rate){ unsigned dsor; __u16 ratio_bits; dsor = calc_ext_dsor(rate); clk->rate = 96000000 / dsor; if (dsor > 8) ratio_bits = ((dsor - 8) / 2 + 6) << 2; else ratio_bits = (dsor - 2) << 2; ratio_bits |= omap_readw(clk->enable_reg) & ~0xfd; omap_writew(ratio_bits, clk->enable_reg); return 0;}static long round_ext_clk_rate(struct clk * clk, unsigned long rate){ return 96000000 / calc_ext_dsor(rate);}static void init_ext_clk(struct clk * clk){ unsigned dsor; __u16 ratio_bits; /* Determine current rate and ensure clock is based on 96MHz APLL */ ratio_bits = omap_readw(clk->enable_reg) & ~1; omap_writew(ratio_bits, clk->enable_reg); ratio_bits = (ratio_bits & 0xfc) >> 2; if (ratio_bits > 6) dsor = (ratio_bits - 6) * 2 + 8; else dsor = ratio_bits + 2; clk-> rate = 96000000 / dsor;}int clk_register(struct clk *clk){ down(&clocks_sem); list_add(&clk->node, &clocks); if (clk->init) clk->init(clk); up(&clocks_sem); return 0;}EXPORT_SYMBOL(clk_register);void clk_unregister(struct clk *clk){ down(&clocks_sem); list_del(&clk->node); up(&clocks_sem);}EXPORT_SYMBOL(clk_unregister);#ifdef CONFIG_OMAP_RESET_CLOCKS/* * Resets some clocks that may be left on from bootloader, * but leaves serial clocks on. See also omap_late_clk_reset(). */static inline void omap_early_clk_reset(void){ //omap_writel(0x3 << 29, MOD_CONF_CTRL_0);}#else#define omap_early_clk_reset() {}#endifint __init clk_init(void){ struct clk ** clkp; const struct omap_clock_config *info; int crystal_type = 0; /* Default 12 MHz */ omap_early_clk_reset(); for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) { if (((*clkp)->flags &CLOCK_IN_OMAP1510) && cpu_is_omap1510()) { clk_register(*clkp); continue; } if (((*clkp)->flags &CLOCK_IN_OMAP16XX) && cpu_is_omap16xx()) { clk_register(*clkp); continue; } if (((*clkp)->flags &CLOCK_IN_OMAP730) && cpu_is_omap730()) { clk_register(*clkp); continue; } } info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config); if (info != NULL) { if (!cpu_is_omap1510()) crystal_type = info->system_clock_type; }#if defined(CONFIG_ARCH_OMAP730) ck_ref.rate = 13000000;#elif defined(CONFIG_ARCH_OMAP16XX) if (crystal_type == 2) ck_ref.rate = 19200000;#endif printk("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n", omap_readw(ARM_SYSST), omap_readw(DPLL_CTL), omap_readw(ARM_CKCTL)); /* We want to be in syncronous scalable mode */ omap_writew(0x1000, ARM_SYSST);#ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER /* Use values set by bootloader. Determine PLL rate and recalculate * dependent clocks as if kernel had changed PLL or divisors. */ { unsigned pll_ctl_val = omap_readw(DPLL_CTL); ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */ if (pll_ctl_val & 0x10) { /* PLL enabled, apply multiplier and divisor */ if (pll_ctl_val & 0xf80) ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7; ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1; } else { /* PLL disabled, apply bypass divisor */ switch (pll_ctl_val & 0xc) { case 0: break; case 0x4: ck_dpll1.rate /= 2; break; default: ck_dpll1.rate /= 4; break; } } } propagate_rate(&ck_dpll1);#else /* Find the highest supported frequency and enable it */ if (select_table_rate(&virtual_ck_mpu, ~0)) { printk(KERN_ERR "System frequencies not set. Check your config.\n"); /* Guess sane values (60MHz) */ omap_writew(0x2290, DPLL_CTL); omap_writew(0x1005, ARM_CKCTL); ck_dpll1.rate = 60000000; propagate_rate(&ck_dpll1); }#endif /* Cache rates for clocks connected to ck_ref (not dpll1) */ propagate_rate(&ck_ref); printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): " "%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n", ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10, ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10, arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10);#ifdef CONFIG_MACH_OMAP_PERSEUS2 /* Select slicer output as OMAP input clock */ omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL);#endif /* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */ omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL); /* Put DSP/MPUI into reset until needed */ omap_writew(0, ARM_RSTCT1); omap_writew(1, ARM_RSTCT2); omap_writew(0x400, ARM_IDLECT1); /* * According to OMAP5910 Erratum SYS_DMA_1, bit DMACK_REQ (bit 8) * of the ARM_IDLECT2 register must be set to zero. The power-on * default value of this bit is one. */ omap_writew(0x0000, ARM_IDLECT2); /* Turn LCD clock off also */ /* * Only enable those clocks we will need, let the drivers * enable other clocks as necessary */ clk_use(&armper_ck); clk_use(&armxor_ck); clk_use(&armtim_ck); if (cpu_is_omap1510()) clk_enable(&arm_gpio_ck); return 0;}#ifdef CONFIG_OMAP_RESET_CLOCKSstatic int __init omap_late_clk_reset(void){ /* Turn off all unused clocks */ struct clk *p; __u32 regval32; /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */ regval32 = omap_readw(SOFT_REQ_REG) & (1 << 4); omap_writew(regval32, SOFT_REQ_REG); omap_writew(0, SOFT_REQ_REG2); list_for_each_entry(p, &clocks, node) { if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) || p->enable_reg == 0) continue; /* Assume no DSP clocks have been activated by bootloader */ if (p->flags & DSP_DOMAIN_CLOCK) continue; /* Is the clock already disabled? */ if (p->flags & ENABLE_REG_32BIT) { if (p->flags & VIRTUAL_IO_ADDRESS) regval32 = __raw_readl(p->enable_reg); else regval32 = omap_readl(p->enable_reg); } else { if (p->flags & VIRTUAL_IO_ADDRESS) regval32 = __raw_readw(p->enable_reg); else regval32 = omap_readw(p->enable_reg); } if ((regval32 & (1 << p->enable_bit)) == 0) continue; /* FIXME: This clock seems to be necessary but no-one * has asked for its activation. */ if (p == &tc2_ck // FIX: pm.c (SRAM), CCP, Camera || p == &ck_dpll1out // FIX: SoSSI, SSR || p == &arm_gpio_ck // FIX: GPIO code for 1510 ) { printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n", p->name); continue; } printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name); __clk_disable(p); printk(" done\n"); } return 0;}late_initcall(omap_late_clk_reset);#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?