Platform: RK3399
OS: Android 7.1
Kernel: v4.4.83
需求:
默认codec的clock source是从I2S1的mclk获取,由于I2S0和I2S1的mclk是共用同一个,
而且同一时刻只有一个I2S模块才能使用,而I2S0需要接麦克阵列,因此I2S1接的RT5640 Codec的时钟源改从BCLK1来获取。
信号源选择方法:
参考RT5640 codec的数据手册中的图,clock source可以从MCLK也可以从PLL获取。
原理图:
5640和cpu的接法如下:
修改:
移除之前对I2S1修改的patch以及添加对5640 clock source的控制。
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-vop-clk-set.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-vop-clk-set.dtsi
index 8a98bbc..0546ed2 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-vop-clk-set.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-vop-clk-set.dtsi
@@ -89,12 +89,12 @@
assigned-clock-parents = <&cru PLL_GPLL>;
};
-/* Kris,180906, Fix playback noise issue.
+
&i2s1 {
assigned-clocks = <&cru SCLK_I2S1_DIV>;
assigned-clock-parents = <&cru PLL_GPLL>;
};
-*/
+
&i2s2 {
assigned-clocks = <&cru SCLK_I2S2_DIV>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 5bf6cb9..109d8ce 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1693,9 +1693,6 @@
dma-names = "tx", "rx";
clock-names = "i2s_clk", "i2s_hclk";
clocks = <&cru SCLK_I2S1_8CH>, <&cru HCLK_I2S1_8CH>;
- //Kris,180706, porting rt5640 on i2s1.
- assigned-clocks = <&cru SCLK_I2S_8CH>;
- assigned-clock-parents = <&cru SCLK_I2S1_8CH>;
pinctrl-names = "default";
pinctrl-0 = <&i2s1_2ch_bus>;
power-domains = <&power RK3399_PD_SDIOAUDIO>;
diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
index e2d872f..cd7b268 100644
--- a/drivers/clk/rockchip/clk-rk3399.c
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -711,9 +711,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
&rk3399_i2s2_fracmux),
GATE(SCLK_I2S2_8CH, "clk_i2s2", "clk_i2s2_mux", CLK_SET_RATE_PARENT,
RK3399_CLKGATE_CON(8), 11, GFLAGS),
- //Kris,180706, porting rt5640 on i2s1.
- //MUX(0, "clk_i2sout_src", mux_i2sch_p, CLK_SET_RATE_PARENT,
- MUX(SCLK_I2S_8CH, "clk_i2sout_src", mux_i2sch_p, CLK_SET_RATE_PARENT,
+ MUX(0, "clk_i2sout_src", mux_i2sch_p, CLK_SET_RATE_PARENT,
RK3399_CLKSEL_CON(31), 0, 2, MFLAGS),
COMPOSITE_NODIV(SCLK_I2S_8CH_OUT, "clk_i2sout", mux_i2sout_p, CLK_SET_RATE_PARENT,
RK3399_CLKSEL_CON(30), 8, 2, MFLAGS,
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 08179f5..1e5c79b 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -1169,16 +1169,6 @@ static inline int _ldst_devtomem(struct pl330_dmac *pl330, unsigned dry_run,
off += _emit_WFP(dry_run, &buf[off], cond, pxs->desc->peri);
off += _emit_LDP(dry_run, &buf[off], cond, pxs->desc->peri);
off += _emit_ST(dry_run, &buf[off], ALWAYS);
-#ifdef CONFIG_ARCH_ROCKCHIP
- /*
- * Make suree dma has finish transmission, or later flush may
- * cause dma second transmission,and fifo is overrun.
- */
- off += _emit_WMB(dry_run, &buf[off]);
- off += _emit_NOP(dry_run, &buf[off]);
- off += _emit_WMB(dry_run, &buf[off]);
- off += _emit_NOP(dry_run, &buf[off]);
-#endif
if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP))
off += _emit_FLUSHP(dry_run, &buf[off],
@@ -1199,16 +1189,6 @@ static inline int _ldst_memtodev(struct pl330_dmac *pl330,
off += _emit_WFP(dry_run, &buf[off], cond, pxs->desc->peri);
off += _emit_LD(dry_run, &buf[off], ALWAYS);
off += _emit_STP(dry_run, &buf[off], cond, pxs->desc->peri);
-#ifdef CONFIG_ARCH_ROCKCHIP
- /*
- * Make suree dma has finish transmission, or later flush may
- * cause dma second transmission,and fifo is overrun.
- */
- off += _emit_WMB(dry_run, &buf[off]);
- off += _emit_NOP(dry_run, &buf[off]);
- off += _emit_WMB(dry_run, &buf[off]);
- off += _emit_NOP(dry_run, &buf[off]);
-#endif
if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP))
off += _emit_FLUSHP(dry_run, &buf[off],
@@ -1347,11 +1327,7 @@ static inline int _loop_cyclic(struct pl330_dmac *pl330, unsigned dry_run,
/* forever loop */
off += _emit_MOV(dry_run, &buf[off], SAR, x->src_addr);
off += _emit_MOV(dry_run, &buf[off], DAR, x->dst_addr);
-#ifdef CONFIG_ARCH_ROCKCHIP
- if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP))
- off += _emit_FLUSHP(dry_run, &buf[off],
- pxs->desc->peri);
-#endif
+
/* loop0 */
off += _emit_LP(dry_run, &buf[off], 0, lcnt0);
ljmp0 = off;
@@ -1390,7 +1366,7 @@ static inline int _loop_cyclic(struct pl330_dmac *pl330, unsigned dry_run,
ccr &= ~(0xf << CC_SRCBRSTLEN_SHFT);
ccr &= ~(0xf << CC_DSTBRSTLEN_SHFT);
off += _emit_MOV(dry_run, &buf[off], CCR, ccr);
- off += _emit_LP(dry_run, &buf[off], 1, c);
+ off += _emit_LP(dry_run, &buf[off], 1, c - 1);
ljmp1 = off;
off += _bursts(pl330, dry_run, &buf[off], pxs, 1);
lpend.cond = ALWAYS;
@@ -1427,11 +1403,7 @@ static inline int _setup_loops(struct pl330_dmac *pl330,
u32 ccr = pxs->ccr;
unsigned long c, bursts = BYTE_TO_BURST(x->bytes, ccr);
int off = 0;
-#ifdef CONFIG_ARCH_ROCKCHIP
- if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP))
- off += _emit_FLUSHP(dry_run, &buf[off],
- pxs->desc->peri);
-#endif
+
while (bursts) {
c = bursts;
off += _loop(pl330, dry_run, &buf[off], &c, pxs);
@@ -1785,17 +1757,16 @@ static int pl330_update(struct pl330_dmac *pl330)
/* Detach the req */
descdone = thrd->req[active].desc;
- if (descdone) {
- if (!descdone->cyclic) {
- thrd->req[active].desc = NULL;
- thrd->req_running = -1;
- /* Get going again ASAP */
- _start(thrd);
- }
- /* For now, just make a list of callbacks to be done */
- list_add_tail(&descdone->rqd, &pl330->req_done);
+ if (!descdone->cyclic) {
+ thrd->req[active].desc = NULL;
+ thrd->req_running = -1;
+ /* Get going again ASAP */
+ _start(thrd);
}
+
+ /* For now, just make a list of callbacks to be done */
+ list_add_tail(&descdone->rqd, &pl330->req_done);
}
}
@@ -1846,6 +1817,7 @@ static bool _chan_ns(const struct pl330_dmac *pl330, int i)
static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330)
{
struct pl330_thread *thrd = NULL;
+ unsigned long flags;
int chans, i;
if (pl330->state == DYING)
@@ -1853,6 +1825,8 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330)
chans = pl330->pcfg.num_chan;
+ spin_lock_irqsave(&pl330->lock, flags);
+
for (i = 0; i < chans; i++) {
thrd = &pl330->channels[i];
if ((thrd->free) && (!_manager_ns(thrd) ||
@@ -1870,6 +1844,8 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330)
thrd = NULL;
}
+ spin_unlock_irqrestore(&pl330->lock, flags);
+
return thrd;
}
@@ -1887,6 +1863,7 @@ static inline void _free_event(struct pl330_thread *thrd, int ev)
static void pl330_release_channel(struct pl330_thread *thrd)
{
struct pl330_dmac *pl330;
+ unsigned long flags;
if (!thrd || thrd->free)
return;
@@ -1898,8 +1875,10 @@ static void pl330_release_channel(struct pl330_thread *thrd)
pl330 = thrd->dmac;
+ spin_lock_irqsave(&pl330->lock, flags);
_free_event(thrd, thrd->ev);
thrd->free = true;
+ spin_unlock_irqrestore(&pl330->lock, flags);
}
/* Initialize the structure for PL330 configuration, that can be used
@@ -2269,19 +2248,19 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
struct pl330_dmac *pl330 = pch->dmac;
unsigned long flags;
- spin_lock_irqsave(&pl330->lock, flags);
+ spin_lock_irqsave(&pch->lock, flags);
dma_cookie_init(chan);
pch->thread = pl330_request_channel(pl330);
if (!pch->thread) {
- spin_unlock_irqrestore(&pl330->lock, flags);
+ spin_unlock_irqrestore(&pch->lock, flags);
return -ENOMEM;
}
tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch);
- spin_unlock_irqrestore(&pl330->lock, flags);
+ spin_unlock_irqrestore(&pch->lock, flags);
return 1;
}
@@ -2384,20 +2363,19 @@ static int pl330_pause(struct dma_chan *chan)
static void pl330_free_chan_resources(struct dma_chan *chan)
{
struct dma_pl330_chan *pch = to_pchan(chan);
- struct pl330_dmac *pl330 = pch->dmac;
unsigned long flags;
tasklet_kill(&pch->task);
pm_runtime_get_sync(pch->dmac->ddma.dev);
- spin_lock_irqsave(&pl330->lock, flags);
+ spin_lock_irqsave(&pch->lock, flags);
pl330_release_channel(pch->thread);
pch->thread = NULL;
list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
- spin_unlock_irqrestore(&pl330->lock, flags);
+ spin_unlock_irqrestore(&pch->lock, flags);
pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
}
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index ee9d1ba..985f9ee 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -1797,6 +1797,10 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
snd_soc_update_bits(codec, RT5640_ADDA_CLK1, mask_clk, val_clk);
}
//理论上,PLL的计算是动态自适应的,可能驱动有问题导致计算不对。
//后来是找realtek FAE拿的参数数据
+ /*Kris, 181128, Use BCLK1 as clock source. {*/
+ snd_soc_update_bits(codec, RT5640_ADDA_CLK1, 0xffff, 0000);
+ /*Kris, 181128, Use BCLK1 as clock source. }*/
+
return 0;
}
@@ -1969,12 +1973,22 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
pll_code.n_code, pll_code.k_code);
//理论上,PLL的计算是动态自适应的,可能驱动有问题导致计算不对。
//后来是找realtek FAE拿的参数数据
+/*Kris, 181128, Use BCLK1 as clock source. {*/
+#if 0
snd_soc_write(codec, RT5640_PLL_CTRL1,
pll_code.n_code << RT5640_PLL_N_SFT | pll_code.k_code);
snd_soc_write(codec, RT5640_PLL_CTRL2,
(pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT |
pll_code.m_bp << RT5640_PLL_M_BP_SFT);
+#else
+ snd_soc_write(codec, RT5640_GLB_CLK, 0x5000);
+ snd_soc_write(codec, RT5640_PLL_CTRL1, 0x0f06);
+ snd_soc_write(codec, RT5640_PLL_CTRL2, 0x0800);
+#endif
+/*Kris, 181128, Use BCLK1 as clock source. }*/
+
+
rt5640->pll_in = freq_in;
rt5640->pll_out = freq_out;
rt5640->pll_src = source;
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index dc971a0..d84eefc 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -21,6 +21,11 @@
#include <sound/soc-dai.h>
#include <sound/soc.h>
+#include "../codecs/rt5640.h"
+
+
+
+
struct simple_card_data {
struct snd_soc_card snd_card;
struct simple_dai_props {
@@ -90,8 +95,25 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
if (mclk_fs) {
mclk = params_rate(params) * mclk_fs;
- ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
- SND_SOC_CLOCK_IN);
+
+/*Kris, 181128, Use BCLK1 as clock source. {*/
//修改对应的时钟源
+#if 0
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN);
+#else
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, mclk * 2, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "codec_dai sys clock not set\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1, mclk, mclk *2);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "codec_dai pll clock not set\n");
+ return ret;
+ }
+#endif
+/*Kris, 181128, Use BCLK1 as clock source. }*/
+
if (ret && ret != -ENOTSUPP)
goto err;
遗留问题:
RT5640 codec中的BLKC1是指pin脚,那么80h寄存器选的是BCLK2,为什么还能工作?