⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clock.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
		/* Can check only after xtal frequency check */		if (ptr->mpu_speed <= rate)			break;	}	return highest_rate;}/* * omap2_convert_field_to_div() - turn field value into integer divider */static u32 omap2_clksel_to_divisor(u32 div_sel, u32 field_val){	u32 i;	u32 clkout_array[] = {1, 2, 4, 8, 16};	if ((div_sel & SRC_RATE_SEL_MASK) == CM_SYSCLKOUT_SEL1) {		for (i = 0; i < 5; i++) {			if (field_val == i)				return clkout_array[i];		}		return ~0;	} else		return field_val;}/* * Returns the CLKSEL divider register value * REVISIT: This should be cleaned up to work nicely with void __iomem * */static u32 omap2_get_clksel(u32 *div_sel, u32 *field_mask,			    struct clk *clk){	int ret = ~0;	u32 reg_val, div_off;	u32 div_addr = 0;	u32 mask = ~0;	div_off = clk->rate_offset;	switch ((*div_sel & SRC_RATE_SEL_MASK)) {	case CM_MPU_SEL1:		div_addr = (u32)&CM_CLKSEL_MPU;		mask = 0x1f;		break;	case CM_DSP_SEL1:		div_addr = (u32)&CM_CLKSEL_DSP;		if (cpu_is_omap2420()) {			if ((div_off == 0) || (div_off == 8))				mask = 0x1f;			else if (div_off == 5)				mask = 0x3;		} else if (cpu_is_omap2430()) {			if (div_off == 0)				mask = 0x1f;			else if (div_off == 5)				mask = 0x3;		}		break;	case CM_GFX_SEL1:		div_addr = (u32)&CM_CLKSEL_GFX;		if (div_off == 0)			mask = 0x7;		break;	case CM_MODEM_SEL1:		div_addr = (u32)&CM_CLKSEL_MDM;		if (div_off == 0)			mask = 0xf;		break;	case CM_SYSCLKOUT_SEL1:		div_addr = (u32)&PRCM_CLKOUT_CTRL;		if ((div_off == 3) || (div_off = 11))			mask= 0x3;		break;	case CM_CORE_SEL1:		div_addr = (u32)&CM_CLKSEL1_CORE;		switch (div_off) {		case 0:					/* l3 */		case 8:					/* dss1 */		case 15:				/* vylnc-2420 */		case 20:				/* ssi */			mask = 0x1f; break;		case 5:					/* l4 */			mask = 0x3; break;		case 13:				/* dss2 */			mask = 0x1; break;		case 25:				/* usb */			mask = 0xf; break;		}	}	*field_mask = mask;	if (unlikely(mask == ~0))		div_addr = 0;	*div_sel = div_addr;	if (unlikely(div_addr == 0))		return ret;	/* Isolate field */	reg_val = __raw_readl((void __iomem *)div_addr) & (mask << div_off);	/* Normalize back to divider value */	reg_val >>= div_off;	return reg_val;}/* * Return divider to be applied to parent clock. * Return 0 on error. */static u32 omap2_clksel_get_divisor(struct clk *clk){	int ret = 0;	u32 div, div_sel, div_off, field_mask, field_val;	/* isolate control register */	div_sel = (SRC_RATE_SEL_MASK & clk->flags);	div_off = clk->rate_offset;	field_val = omap2_get_clksel(&div_sel, &field_mask, clk);	if (div_sel == 0)		return ret;	div_sel = (SRC_RATE_SEL_MASK & clk->flags);	div = omap2_clksel_to_divisor(div_sel, field_val);	return div;}/* Set the clock rate for a clock source */static int omap2_clk_set_rate(struct clk *clk, unsigned long rate){	int ret = -EINVAL;	void __iomem * reg;	u32 div_sel, div_off, field_mask, field_val, reg_val, validrate;	u32 new_div = 0;	if (!(clk->flags & CONFIG_PARTICIPANT) && (clk->flags & RATE_CKCTL)) {		if (clk == &dpll_ck)			return omap2_reprogram_dpll(clk, rate);		/* Isolate control register */		div_sel = (SRC_RATE_SEL_MASK & clk->flags);		div_off = clk->src_offset;		validrate = omap2_clksel_round_rate(clk, rate, &new_div);		if(validrate != rate)			return(ret);		field_val = omap2_get_clksel(&div_sel, &field_mask, clk);		if (div_sel == 0)			return ret;		if(clk->flags & CM_SYSCLKOUT_SEL1){			switch(new_div){			case 16: field_val = 4; break;			case 8:  field_val = 3; break;			case 4:  field_val = 2; break;			case 2:  field_val = 1; break;			case 1:  field_val = 0; break;			}		}		else			field_val = new_div;		reg = (void __iomem *)div_sel;		reg_val = __raw_readl(reg);		reg_val &= ~(field_mask << div_off);		reg_val |= (field_val << div_off);		__raw_writel(reg_val, reg);		clk->rate = clk->parent->rate / field_val;		if (clk->flags & DELAYED_APP)			__raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL);		ret = 0;	} else if (clk->set_rate != 0)		ret = clk->set_rate(clk, rate);	if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))		propagate_rate(clk);	return ret;}/* Converts encoded control register address into a full address */static u32 omap2_get_src_field(u32 *type_to_addr, u32 reg_offset,			       struct clk *src_clk, u32 *field_mask){	u32 val = ~0, src_reg_addr = 0, mask = 0;	/* Find target control register.*/	switch ((*type_to_addr & SRC_RATE_SEL_MASK)) {	case CM_CORE_SEL1:		src_reg_addr = (u32)&CM_CLKSEL1_CORE;		if (reg_offset == 13) {			/* DSS2_fclk */			mask = 0x1;			if (src_clk == &sys_ck)				val = 0;			if (src_clk == &func_48m_ck)				val = 1;		} else if (reg_offset == 8) {		/* DSS1_fclk */			mask = 0x1f;			if (src_clk == &sys_ck)				val = 0;			else if (src_clk == &core_ck)	/* divided clock */				val = 0x10;		/* rate needs fixing */		} else if ((reg_offset == 15) && cpu_is_omap2420()){ /*vlnyq*/			mask = 0x1F;			if(src_clk == &func_96m_ck)				val = 0;			else if (src_clk == &core_ck)				val = 0x10;		}		break;	case CM_CORE_SEL2:		src_reg_addr = (u32)&CM_CLKSEL2_CORE;		mask = 0x3;		if (src_clk == &func_32k_ck)			val = 0x0;		if (src_clk == &sys_ck)			val = 0x1;		if (src_clk == &alt_ck)			val = 0x2;		break;	case CM_WKUP_SEL1:		src_reg_addr = (u32)&CM_CLKSEL2_CORE;		mask = 0x3;		if (src_clk == &func_32k_ck)			val = 0x0;		if (src_clk == &sys_ck)			val = 0x1;		if (src_clk == &alt_ck)			val = 0x2;		break;	case CM_PLL_SEL1:		src_reg_addr = (u32)&CM_CLKSEL1_PLL;		mask = 0x1;		if (reg_offset == 0x3) {			if (src_clk == &apll96_ck)				val = 0;			if (src_clk == &alt_ck)				val = 1;		}		else if (reg_offset == 0x5) {			if (src_clk == &apll54_ck)				val = 0;			if (src_clk == &alt_ck)				val = 1;		}		break;	case CM_PLL_SEL2:		src_reg_addr = (u32)&CM_CLKSEL2_PLL;		mask = 0x3;		if (src_clk == &func_32k_ck)			val = 0x0;		if (src_clk == &dpll_ck)			val = 0x2;		break;	case CM_SYSCLKOUT_SEL1:		src_reg_addr = (u32)&PRCM_CLKOUT_CTRL;		mask = 0x3;		if (src_clk == &dpll_ck)			val = 0;		if (src_clk == &sys_ck)			val = 1;		if (src_clk == &func_54m_ck)			val = 2;		if (src_clk == &func_96m_ck)			val = 3;		break;	}	if (val == ~0)			/* Catch errors in offset */		*type_to_addr = 0;	else		*type_to_addr = src_reg_addr;	*field_mask = mask;	return val;}static int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent){	void __iomem * reg;	u32 src_sel, src_off, field_val, field_mask, reg_val, rate;	int ret = -EINVAL;	if (unlikely(clk->flags & CONFIG_PARTICIPANT))		return ret;	if (clk->flags & SRC_SEL_MASK) {	/* On-chip SEL collection */		src_sel = (SRC_RATE_SEL_MASK & clk->flags);		src_off = clk->src_offset;		if (src_sel == 0)			goto set_parent_error;		field_val = omap2_get_src_field(&src_sel, src_off, new_parent,						&field_mask);		reg = (void __iomem *)src_sel;		if (clk->usecount > 0)			omap2_clk_disable(clk);		/* Set new source value (previous dividers if any in effect) */		reg_val = __raw_readl(reg) & ~(field_mask << src_off);		reg_val |= (field_val << src_off);		__raw_writel(reg_val, reg);		if (clk->flags & DELAYED_APP)			__raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL);		if (clk->usecount > 0)			omap2_clk_enable(clk);		clk->parent = new_parent;		/* SRC_RATE_SEL_MASK clocks follow their parents rates.*/		if ((new_parent == &core_ck) && (clk == &dss1_fck))			clk->rate = new_parent->rate / 0x10;		else			clk->rate = new_parent->rate;		if (unlikely(clk->flags & RATE_PROPAGATES))			propagate_rate(clk);		return 0;	} else {		clk->parent = new_parent;		rate = new_parent->rate;		omap2_clk_set_rate(clk, rate);		ret = 0;	} set_parent_error:	return ret;}/* Sets basic clocks based on the specified rate */static int omap2_select_table_rate(struct clk * clk, unsigned long rate){	u32 flags, cur_rate, done_rate, bypass = 0;	u8 cpu_mask = 0;	struct prcm_config *prcm;	unsigned long found_speed = 0;	if (clk != &virt_prcm_set)		return -EINVAL;	/* FIXME: Change cpu_is_omap2420() to cpu_is_omap242x() */	if (cpu_is_omap2420())		cpu_mask = RATE_IN_242X;	else if (cpu_is_omap2430())		cpu_mask = RATE_IN_243X;	for (prcm = rate_table; prcm->mpu_speed; prcm++) {		if (!(prcm->flags & cpu_mask))			continue;		if (prcm->xtal_speed != sys_ck.rate)			continue;		if (prcm->mpu_speed <= rate) {			found_speed = prcm->mpu_speed;			break;		}	}	if (!found_speed) {		printk(KERN_INFO "Could not set MPU rate to %luMHz\n",	 rate / 1000000);		return -EINVAL;	}	curr_prcm_set = prcm;	cur_rate = omap2_get_dpll_rate(&dpll_ck);	if (prcm->dpll_speed == cur_rate / 2) {		omap2_reprogram_sdrc(PRCM_HALF_SPEED, 1);	} else if (prcm->dpll_speed == cur_rate * 2) {		omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1);	} else if (prcm->dpll_speed != cur_rate) {		local_irq_save(flags);		if (prcm->dpll_speed == prcm->xtal_speed)			bypass = 1;		if ((prcm->cm_clksel2_pll & 0x3) == 2)			done_rate = PRCM_FULL_SPEED;		else			done_rate = PRCM_HALF_SPEED;		/* MPU divider */		CM_CLKSEL_MPU = prcm->cm_clksel_mpu;		/* dsp + iva1 div(2420), iva2.1(2430) */		CM_CLKSEL_DSP = prcm->cm_clksel_dsp;		CM_CLKSEL_GFX = prcm->cm_clksel_gfx;		/* Major subsystem dividers */		CM_CLKSEL1_CORE = prcm->cm_clksel1_core;		if (cpu_is_omap2430())			CM_CLKSEL_MDM = prcm->cm_clksel_mdm;		/* x2 to enter init_mem */		omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1);		omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr,			       bypass);		omap2_init_memory_params(omap2_dll_force_needed());		omap2_reprogram_sdrc(done_rate, 0);		local_irq_restore(flags);	}	omap2_clksel_recalc(&dpll_ck);	return 0;}/*------------------------------------------------------------------------- * Omap2 clock reset and init functions *-------------------------------------------------------------------------*/static struct clk_functions omap2_clk_functions = {	.clk_enable		= omap2_clk_enable,	.clk_disable		= omap2_clk_disable,	.clk_use		= omap2_clk_use,	.clk_unuse		= omap2_clk_unuse,	.clk_round_rate		= omap2_clk_round_rate,	.clk_set_rate		= omap2_clk_set_rate,	.clk_set_parent		= omap2_clk_set_parent,};static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys){	u32 div, aplls, sclk = 13000000;	aplls = CM_CLKSEL1_PLL;	aplls &= ((1 << 23) | (1 << 24) | (1 << 25));	aplls >>= 23;			/* Isolate field, 0,2,3 */	if (aplls == 0)		sclk = 19200000;	else if (aplls == 2)		sclk = 13000000;	else if (aplls == 3)		sclk = 12000000;	div = PRCM_CLKSRC_CTRL;	div &= ((1 << 7) | (1 << 6));	div >>= sys->rate_offset;	osc->rate = sclk * div;	sys->rate = sclk;}#ifdef CONFIG_OMAP_RESET_CLOCKSstatic void __init omap2_disable_unused_clocks(void){	struct clk *ck;	u32 regval32;	list_for_each_entry(ck, &clocks, node) {		if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) ||			ck->enable_reg == 0)			continue;		regval32 = __raw_readl(ck->enable_reg);		if ((regval32 & (1 << ck->enable_bit)) == 0)			continue;		printk(KERN_INFO "Disabling unused clock \"%s\"\n", ck->name);		omap2_clk_disable(ck);	}}late_initcall(omap2_disable_unused_clocks);#endif/* * Switch the MPU rate if specified on cmdline. * We cannot do this early until cmdline is parsed. */static int __init omap2_clk_arch_init(void){	if (!mpurate)		return -EINVAL;	if (omap2_select_table_rate(&virt_prcm_set, mpurate))		printk(KERN_ERR "Could not find matching MPU rate\n");	propagate_rate(&osc_ck);		/* update main root fast */	propagate_rate(&func_32k_ck);		/* update main root slow */	printk(KERN_INFO "Switched to new clocking rate (Crystal/DPLL/MPU): "	       "%ld.%01ld/%ld/%ld MHz\n",	       (sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10,	       (dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ;	return 0;}arch_initcall(omap2_clk_arch_init);int __init omap2_clk_init(void){	struct prcm_config *prcm;	struct clk ** clkp;	u32 clkrate;	clk_init(&omap2_clk_functions);	omap2_get_crystal_rate(&osc_ck, &sys_ck);	for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks);	     clkp++) {		if ((*clkp)->flags & CLOCK_IN_OMAP242X && cpu_is_omap2420()) {			clk_register(*clkp);			continue;		}		if ((*clkp)->flags & CLOCK_IN_OMAP243X && cpu_is_omap2430()) {			clk_register(*clkp);			continue;		}	}	/* Check the MPU rate set by bootloader */	clkrate = omap2_get_dpll_rate(&dpll_ck);	for (prcm = rate_table; prcm->mpu_speed; prcm++) {		if (prcm->xtal_speed != sys_ck.rate)			continue;		if (prcm->dpll_speed <= clkrate)			 break;	}	curr_prcm_set = prcm;	propagate_rate(&osc_ck);		/* update main root fast */	propagate_rate(&func_32k_ck);		/* update main root slow */	printk(KERN_INFO "Clocking rate (Crystal/DPLL/MPU): "	       "%ld.%01ld/%ld/%ld MHz\n",	       (sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10,	       (dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ;	/*	 * Only enable those clocks we will need, let the drivers	 * enable other clocks as necessary	 */	clk_use(&sync_32k_ick);	clk_use(&omapctrl_ick);	if (cpu_is_omap2430())		clk_use(&sdrc_ick);	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -