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 + -
显示快捷键?