Linux启动过程分析(十一)---da850_set_emif_clk_rate()函数分析

/*
* 虽然在bootloader中已经把emif的时钟速率设置为允许的值,但是内核需要重新
*设置以使它支持平台请求的特定时钟速率。
*/

ret = da850_set_emif_clk_rate()->

static __init int da850_set_emif_clk_rate(void)
{
	struct clk *emif_clk;

	emif_clk = clk_get(NULL, "pll0_sysclk3");
	if (WARN(IS_ERR(emif_clk), "Unable to get emif clock\n"))
		return PTR_ERR(emif_clk);

	return clk_set_rate(emif_clk, CONFIG_DA850_FIX_PLL0_SYSCLK3RATE);
}

先来分析一下clk_get这个函数(位于drivers\clk\Clkdev.c):


struct clk *clk_get(struct device *dev, const char *con_id)
{
	const char *dev_id = dev ? dev_name(dev) : NULL;

	return clk_get_sys(dev_id, con_id);
}

因为dev传递下来的值是NULL,所以dev_id的值也是NULL;
然后继续调用clk_get_sys(NULL,“pll0_sysclk3”);


struct clk *clk_get_sys(const char *dev_id, const char *con_id)
{
	struct clk_lookup *cl;

	mutex_lock(&clocks_mutex);
	cl = clk_find(dev_id, con_id);
	if (cl && !__clk_get(cl->clk))
		cl = NULL;
	mutex_unlock(&clocks_mutex);

	return cl ? cl->clk : ERR_PTR(-ENOENT);
}

clk_get_sys的实现依赖于clk_find这个函数
clk_find(NULL,“pll0_sysclk3”);


/*
 * Find the correct struct clk for the device and connection ID.
 * We do slightly fuzzy matching here:
 *  An entry with a NULL ID is assumed to be a wildcard.
 *  If an entry has a device ID, it must match
 *  If an entry has a connection ID, it must match
 * Then we take the most specific entry - with the following
 * order of precedence: dev+con > dev only > con only.
 */
static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
{
	struct clk_lookup *p, *cl = NULL;
	int match, best = 0;

	list_for_each_entry(p, &clocks, node) {
		match = 0;
		if (p->dev_id) {
			if (!dev_id || strcmp(p->dev_id, dev_id))
				continue;
			match += 2;
		}
		if (p->con_id) {
			if (!con_id || strcmp(p->con_id, con_id))
				continue;
			match += 1;
		}

		if (match > best) {
			cl = p;
			if (match != 3)
				best = match;
			else
				break;
		}
	}
	return cl;
}

list_for_each_entry函数从clocks的链表中的表头,开始和我们传入的硬件相比较,如果找到了就返回一个指向该硬件clk_lookup类型的指针。


struct clk;
struct device;

struct clk_lookup {
	struct list_head	node;
	const char		*dev_id;
	const char		*con_id;
	struct clk		*clk;
};

clk_lookup中clk内容是:


static struct clk pll0_sysclk3 = {
	.name		= "pll0_sysclk3",
	.parent		= &pll0_clk,
	.flags		= CLK_PLL,
	.div_reg	= PLLDIV3,
	.set_rate	= da850_set_pll0sysclk3_rate,
	.maxrate	= 152000000,
};

紧接着来分析clk_set_rate(emif_clk, CONFIG_DA850_FIX_PLL0_SYSCLK3RATE)这个函数。


int clk_set_rate(struct clk *clk, unsigned long rate)
{
	unsigned long flags;
	int ret = -EINVAL;

	if (clk == NULL || IS_ERR(clk))
		return ret;

	if (clk->set_rate)
		ret = clk->set_rate(clk, rate);

	spin_lock_irqsave(&clockfw_lock, flags);
	if (ret == 0) {
		if (clk->recalc)
			clk->rate = clk->recalc(clk);
		propagate_rate(clk);
	}
	spin_unlock_irqrestore(&clockfw_lock, flags);

	return ret;
}

#define CONFIG_DA850_FIX_PLL0_SYSCLK3RATE 0

其中clk->set_rate指向的函数是:da850_set_pll0sysclk3_rate(struct clk *clk, unsigned long rate);
参数传递后如下:
da850_set_pll0sysclk3_rate(emif_clk,0)->


static int da850_set_pll0sysclk3_rate(struct clk *clk, unsigned long rate)
{
	struct clk *arm_clk;
	unsigned long sys_clk3_rate = 148000000;
	int ret;

	arm_clk = clk_get(NULL, "arm");
	if (WARN(IS_ERR(arm_clk), "Unable to get ARM clock\n"))
		return PTR_ERR(arm_clk);

	/* Set EMIF clock based on OPPs */
	switch (clk_get_rate(arm_clk)) {
	case 200000000:
		sys_clk3_rate = 75000000;
		break;
	case 96000000:
		sys_clk3_rate = 50000000;
		break;
	}

	if (rate)
		sys_clk3_rate = min(sys_clk3_rate, rate);

	ret = davinci_set_sysclk_rate(clk, sys_clk3_rate);
	if (WARN_ON(ret))
		return ret;

	return 0;
}

这里重点分析arm_clk = clk_get(NULL, “arm”);
会返回指向arm的clk_lookup类型的指针,clk_lookup中的clk即arm_clk的内容是:


static struct clk arm_clk = {
	.name		= "arm",
	.parent		= &pll0_sysclk6,
	.lpsc		= DA8XX_LPSC0_ARM,
	.flags		= ALWAYS_ENABLED,
	.set_rate	= da850_set_armrate,
	.round_rate	= da850_round_armrate,
};

clk_get_rate(arm_clk)->


unsigned long clk_get_rate(struct clk *clk)
{
	if (clk == NULL || IS_ERR(clk))
		return -EINVAL;

	return clk->rate;
}

这个函数会返回arm_clk结构体中存储的rate值。但目前看来这个值在结构体中没有定义,所以到
ret = davinci_set_sysclk_rate(clk, sys_clk3_rate)这个地方来执行
将参数传入:
ret = davinci_set_sysclk_rate(emif_clk, 148000000)->


int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate)
{
	unsigned v;
	struct pll_data *pll;
	unsigned long input;
	unsigned ratio = 0;

	/* If this is the PLL base clock, wrong function to call */
	if (clk->pll_data)
		return -EINVAL;

	/* There must be a parent... */
	if (WARN_ON(!clk->parent))
		return -EINVAL;

	/* ... the parent must be a PLL... */
	if (WARN_ON(!clk->parent->pll_data))
		return -EINVAL;

	/* ... and this clock must have a divider. */
	if (WARN_ON(!clk->div_reg))
		return -EINVAL;

	pll = clk->parent->pll_data;

	input = clk->parent->rate;

	/* If pre-PLL, source clock is before the multiplier and divider(s) */
	if (clk->flags & PRE_PLL)
		input = pll->input_rate;

	if (input > rate) {
		/*
		 * Can afford to provide an output little higher than requested
		 * only if maximum rate supported by hardware on this sysclk
		 * is known.
		 */
		if (clk->maxrate) {
			ratio = DIV_ROUND_CLOSEST(input, rate);
			if (input / ratio > clk->maxrate)
				ratio = 0;
		}

		if (ratio == 0)
			ratio = DIV_ROUND_UP(input, rate);

		ratio--;
	}

	if (ratio > pll->div_ratio_mask)
		return -EINVAL;
/*等待PLLSTAT位被清零(表示当前没有操作)*/
	do {
		v = __raw_readl(pll->base + PLLSTAT);
	} while (v & PLLSTAT_GOSTAT);
/*这里的clk指的是pll0_sysclk3,则div_reg	= PLLDIV3= 0x120,对应的寄存器为PLLDIV3 PLLC0 Divider 3 Register*/
	v = __raw_readl(pll->base + clk->div_reg);
	/*先将对应的掩码清零*/
	v &= ~pll->div_ratio_mask;
	/*指定分频系数的同时将Divider3使能*/
	v |= ratio | PLLDIV_EN;
	__raw_writel(v, pll->base + clk->div_reg);
/*设置PLLCMD的GOSET位为1,来传输新的分频参数*/
	v = __raw_readl(pll->base + PLLCMD);
	v |= PLLCMD_GOSET;
	__raw_writel(v, pll->base + PLLCMD);
/*等待PLLSTAT的值被清零,表示分频的结束*/
	do {
		v = __raw_readl(pll->base + PLLSTAT);
	} while (v & PLLSTAT_GOSTAT);

	return 0;
}

emif_clk所对应的clk结构体如下:


static struct clk pll0_sysclk3 = {
	.name		= "pll0_sysclk3",
	.parent		= &pll0_clk,
	.flags		= CLK_PLL,
	.div_reg	= PLLDIV3,
	.set_rate	= da850_set_pll0sysclk3_rate,
	.maxrate	= 152000000,
};

前面的几个if经过判断,都没有错误,接下来看:

pll = clk->parent->pll_data;
展开:

 pll=pll0_clk->pll_data;
 pll=pll0_data;
 ->
static struct pll_data pll0_data = {
	.num		= 1,
	.phys_base	= DA8XX_PLL0_BASE,
	.flags		= PLL_HAS_PREDIV | PLL_HAS_POSTDIV,
};
#define DA8XX_PLL0_BASE		0x01c11000
#define PLL_HAS_PREDIV          0x01
#define PLL_HAS_POSTDIV         0x02 

input = clk->parent->rate;

input=pll0_clk->rate=0;

接下来继续看clk_set_rate的后半部分:

if (ret == 0) {
		if (clk->recalc)
			clk->rate = clk->recalc(clk);
		propagate_rate(clk);
	}

没有执行。

你可能感兴趣的:(Linux内核)