【EMMC】MSM8953里时钟是如何分频的

时钟源

MSM8953振荡频率为19.2 MHz的单晶振荡器(XO)。XO作为所有pll的源,也可以作为其他时钟的源。MSM8953没有单独的休眠晶体,使用586的除数从XO生成睡眠时钟32.768khz作为时钟信号源。
在这里插入图片描述

分析代码

在host中probe函数里有在初始化阶段获取clk信息

	/* Setup SDC MMC clock */
	msm_host->clk = devm_clk_get(&pdev->dev, "core_clk");
	if (IS_ERR(msm_host->clk)) {
		ret = PTR_ERR(msm_host->clk);
		goto bus_aggr_clk_disable;
	}

跳转到设备树获取设备树中时钟信息,以下分别是mmc和sd的。下面只示例mmc,sd同理。

	clocks = <&clock_gcc clk_gcc_sdcc1_ahb_clk>,
			 <&clock_gcc clk_gcc_sdcc1_apps_clk>,
			 <&clock_gcc clk_gcc_sdcc1_ice_core_clk>;
	clock-names = "iface_clk", "core_clk", "ice_core_clk";
------------------------------------------------------------------------
	clocks = <&clock_gcc clk_gcc_sdcc2_ahb_clk>,
			<&clock_gcc clk_gcc_sdcc2_apps_clk>;
	clock-names = "iface_clk", "core_clk";

查看clock-gcc-msm8953文件的probe函数,解析设备树资源

res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
	if (!res) {
		dev_err(&pdev->dev, "Register base not defined\n");
		return -ENOMEM;
	}

获取寄存器基地址以及偏移量

clock_gcc_gfx: qcom,gcc-gfx@1800000 {
		compatible = "qcom,gcc-gfx-8953";
		reg = <0x1800000 0x80000>;
		reg-names = "cc_base";
		vdd_gfx-supply = <&gfx_vreg_corner>;
		clocks = <&clock_gcc clk_xo_clk_src>;
		clock-names = "xo";
		qcom,gcc_oxili_gfx3d_clk-opp-handle = <&msm_gpu>;
		qcom,gfxfreq-corner =
			 <         0   0 >,
			 < 133330000   1 >,  /* Min SVS   */
			 < 216000000   2 >,  /* Low SVS   */
			 < 320000000   3 >,  /* SVS       */
			 < 400000000   4 >,  /* SVS Plus  */
			 < 510000000   5 >,  /* NOM       */
			 < 560000000   6 >,  /* Nom Plus  */
			 < 650000000   7 >;  /* Turbo     */
		#clock-cells = <1>;
	};

寄存器基地址映射

virt_bases[GCC_BASE] = devm_ioremap(&pdev->dev, res->start,
							resource_size(res));

获取时钟源table

static struct clk_freq_tbl ftbl_sdcc1_apps_clk_src[] = {
	F(    144000,              xo,   16,    3,    25),
	F(    400000,              xo,   12,    1,     4),
	F(  20000000, gpll0_main_div2,    5,    1,     4),
	F(  25000000, gpll0_main_div2,   16,    0,     0),
	F(  50000000,           gpll0,   16,    0,     0),
	F( 100000000,           gpll0,    8,    0,     0),
	F( 177770000,           gpll0,  4.5,    0,     0),
	F( 192000000,           gpll4,    6,    0,     0),
	F( 384000000,           gpll4,    3,    0,     0),
	F_END
};

static struct rcg_clk sdcc1_apps_clk_src = {
	.cmd_rcgr_reg = SDCC1_APPS_CMD_RCGR,
	.set_rate = set_rate_mnd,
	.freq_tbl = ftbl_sdcc1_apps_clk_src,
	.current_freq = &rcg_dummy_freq,
	.base = &virt_bases[GCC_BASE],
	.c = {
		.dbg_name = "sdcc1_apps_clk_src",
		.ops = &clk_ops_rcg_mnd,
		VDD_DIG_FMAX_MAP3(LOW_SVS, 25000000, SVS, 100000000, NOM,
				400000000),
		CLK_INIT(sdcc1_apps_clk_src.c),
	},
};

这里的table值是有对应的计算公式,可以根据相应spec分析。

F(f, s, d, m, n)
f = Frequency
s = PLL
d = SRC_DIV
m = Multiplier
n = Divisor

举个例子:

F(100000000, gpll0, 8, 0, 0),
f = 800 MHz *1/8 = 100000000 Hz
m、n和d的规则如下:
0>=m<=2
0>=n<=255
0>=d<=15, 其中d的值可以有0.5,例如0.51.01.52.0等。
注:
若m和n不存在,它们等于0。
因此,要添加100MHz作为频率,必须将其作为上表中的函数添加,然后可以将100MHz添加到设备树中,以便驱动程序可以选择此频率。

接着分析,这些值是如何写到寄存器中的。上面的src中有个set_rate_mnd函数。
这里要提一下spec中的寄存器。分别代表上面公式的mnd寄存器。
在这里插入图片描述在这里插入图片描述SDCC1_APPS_CMD_RCGR寄存器
在这里插入图片描述
将mnd的值写到上述的寄存器中

void set_rate_mnd(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
{
	unsigned long flags;

	spin_lock_irqsave(&local_clock_reg_lock, flags);
	__set_rate_mnd(rcg, nf);
	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
}
static void __set_rate_mnd(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
{
	u32 cfg_regval;

	cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
	writel_relaxed(nf->m_val, M_REG(rcg));
	writel_relaxed(nf->n_val, N_REG(rcg));
	writel_relaxed(nf->d_val, D_REG(rcg));

	cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
	cfg_regval &= ~(CFG_RCGR_DIV_MASK | CFG_RCGR_SRC_SEL_MASK);
	cfg_regval |= nf->div_src_val;

	/* Activate or disable the M/N:D divider as necessary */
	cfg_regval &= ~MND_MODE_MASK;
	if (nf->n_val != 0)
		cfg_regval |= MND_DUAL_EDGE_MODE_BVAL;
	writel_relaxed(cfg_regval, CFG_RCGR_REG(rcg));

	rcg_update_config(rcg);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值