TxClk_Source field of documentaion

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

TxClk_Source field of documentaion

1,237 Views
sgordon777
Contributor I

Processor: MIMX8MM5

Documentation: i.MX 8M Mijni Applications Processor Reference Manual

Document number: IMX8MMRM Rev. 3 

Page#4211

 

I am trying to write a SPDIF driver for the MIMX8MM5 processor. The reference manual I'm using has missing information about the clock source for the SPDIF TX.

Specifically, the TxClk_Source field of the SPDIFTxClk register, has only one option:

000b - Click Selection from Audio Clock Mux (ACM)

1-Why is there only one option? It's a 3 bit field

2-What is the Audio Clock Mux? I cannot find references to this ANYWHERE in this manual

 

TRegarding the clocking fo

Labels (1)
0 Kudos
Reply
28 Replies

1,086 Views
sgordon777
Contributor I

The thread is quite vague about how SPDIF1 TxClock is generated. I *THINK* it is implying that SPDIF1_CLOCK_ROOT controls the Tx clock of SPDIF1. Howver, I tried changing the divide registers of SPDIF1_CLOCK_ROOT (CCM_BASE + 0xA880) and the signal output by my SPDIF1-TX didn't change.

 I still feel I don't have all the information available on clocking the Transmit section of SPDIF1

0 Kudos
Reply

1,069 Views
Zhiming_Liu
NXP TechSupport
NXP TechSupport

Hi @sgordon777 

Please check the mux mode of with IOMUXC_SW_MUX_CTL_PAD_SPDIF_TX, the default mux mode is 101b ALT5 Select signal GPIO5_IO03 

 

In Linux dts, the setting is


	pinctrl_spdif1: spdif1grp {
		fsl,pins = <
			MX8MM_IOMUXC_SPDIF_TX_SPDIF1_OUT	0xd6
			MX8MM_IOMUXC_SPDIF_RX_SPDIF1_IN		0xd6
		>;
	};

And for the SPDIF1 node, the SPDIF1 root clock is from AUDIO_PLL1, and the TX clock is from SPDIF1 root clock.

&spdif1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_spdif1>;
	assigned-clocks = <&clk IMX8MM_CLK_SPDIF1>;
	assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
	assigned-clock-rates = <24576000>;
	clocks = <&clk IMX8MM_CLK_AUDIO_AHB>, <&clk IMX8MM_CLK_24M>,
		<&clk IMX8MM_CLK_SPDIF1>, <&clk IMX8MM_CLK_DUMMY>,
		<&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>,
		<&clk IMX8MM_CLK_AUDIO_AHB>, <&clk IMX8MM_CLK_DUMMY>,
		<&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>,
		<&clk IMX8MM_AUDIO_PLL1_OUT>, <&clk IMX8MM_AUDIO_PLL2_OUT>;
	clock-names = "core", "rxtx0", "rxtx1", "rxtx2", "rxtx3",
		"rxtx4", "rxtx5", "rxtx6", "rxtx7", "spba", "pll8k", "pll11k";
	status = "okay";
};

For the driver call, please trace spdif_priv->txclk in sound/soc/fsl/fsl_spdif.c,



Best Regards,
Zhiming

0 Kudos
Reply

1,064 Views
sgordon777
Contributor I
Hello, thanks for your suggestsions.
 
The pinmux are definitely correct, the SPDIF1 pins are routed and working fine. The problem is the clock routing to the SPDIF Transmit, not he pinmux: 
-I am seeing 24Mhz signal on on SPDIF1_TX. I can divide this down with TxClk_DF (but not SYSCLK_DF)
-I am getting a PLL lock on SPDIF1_RX
-I can redirect SPDIF1_RX to SPDIF1_TX (using TxSel field = 5)
 
Here's my pinmux:
spdif1_default: spdif1_default {
group0 {
pinmux = <&iomuxc_spdif_tx_spdif_out_spdif1_out>,
<&iomuxc_spdif_rx_spdif_in_spdif1_in>;
slew-rate = "fast";
drive-strength = "40-ohm";
};
};
0 Kudos
Reply

1,062 Views
sgordon777
Contributor I
 
 
Clock routing: I am trying to change the CCM registers to rout other clock signals to the SPDIF TX peripheral (see picture). However, anything besides 0x000 (24Mhz) causes the system to crash.
sgordon777_0-1749096738500.png

 

0 Kudos
Reply

1,034 Views
Zhiming_Liu
NXP TechSupport
NXP TechSupport

Hi @sgordon777 

It looks like you are using zephyr, right? Are you sure the PLLs are generated from 24Mhz? I checked the zephyr source code, there is no such code to generate PLLs like Linux. In Linux, the PLLs are generated from drivers/clk/imx/clk-pll14xx.c with imx_pll1443x_tbl



Best Regards,
Zhiming

0 Kudos
Reply

1,004 Views
sgordon777
Contributor I

Yes we are using zephyr, and thanks for the information about the PLLs.

 

However, I'm still lacking even the most basic confirmation about how the clocks are routed to the SPDIF1 Tx module.

Can we please confirm whether SPDIF TX is clocked from SPDIF_CLK_ROOT (CCM offset 0xA880), and we have the seven options shown in the table above (of which it seems 000 is selected (because I see a 24Mhz output on SPDIF-TX.)

0 Kudos
Reply

964 Views
Zhiming_Liu
NXP TechSupport
NXP TechSupport

Hi @sgordon777 

Can we please confirm whether SPDIF TX is clocked from SPDIF_CLK_ROOT

-->Yes, we can refer the setting in Linux dts, the TX clock is from SPDIF_CLK_ROOT.

For zephyr, the other PLLs in the seven options will not be generated, and the default source of SPDIF_CLK_ROOT is 24MHz. Since the PLL wasn't generated, but you wanted to use it, that's what caused the system to crash. If you need to use a PLL, these are the three steps:

1.generate the AUDIO PLL

2.set the source of SPDIF_CLK_ROOT to be the AUDIO PLL

3.cancel the gate of SPDIF_CLK_ROOT so the clock will flow correctly

Best Regards,
Zhiming

0 Kudos
Reply

893 Views
sgordon777
Contributor I

>> 3.cancel the gate of SPDIF_CLK_ROOT so the clock will flow correctly

What does this mean exactly? Can you refer to a section in the REF manual?

>> 2.set the source of SPDIF_CLK_ROOT to be the AUDIO PLL

You mean using the bitfields in the CCM_BASE + 0xA880 register right?

 

>>Since the PLL wasn't generated, but you wanted to use it, that's what caused the system to crash.

-Even if I choose the EXT_CLK_2 or EXT_CLK_3 options (b110, b111) I get the crash though.  Are EXT_CLK_X associated with PLLs?

  

sgordon777_0-1749218163916.png

 

0 Kudos
Reply

780 Views
Zhiming_Liu
NXP TechSupport
NXP TechSupport

Hi @sgordon777 

Below is the generic clock path: 

24Mhz-->PLLs-->CCM-->xxx_CLK_ROOT-->LPCG gate control

External clock input-->CCM-->xxx_CLK_ROOT-->LPCG gate control

The cg unit is clock gate.

Zhiming_Liu_0-1749431472362.png


EXT_CLK_x is not PLLs, external clock from a clock input external to the chip. PLLs, 24MHz and 32KHz are clocks that can be used by default. But need generate PLLs with PLL driver to get basic PLLs.

Zhiming_Liu_1-1749431761718.png

 

The CCM_BASE + 0xA880 is used to select sources, EXT_CLK, PLLs or 24MHz.

Most clocks have LPCG control. To generate the SPDIF clock, you need to refer to the diagram below for the steps you need to take. 

1.In zephyr os, generate PLLs, then set CCM_BASE + 0xA880 to select the source of SPDIF_CLK_ROOT.

2.disable gate of PLLs you select as you can see that there is a cg unit before you set the PRE and POST divider.

Zhiming_Liu_2-1749432253735.png

3. Then set the PRE and POST divider to get the SPDIF clock rate you want.


Best Regards,
Zhiming

0 Kudos
Reply

737 Views
sgordon777
Contributor I

Thanks you. Yes, I'm aware of the clock tree chapter, I've tried to follow it for the purpose of this discussion. However, It's not very clear at all what registers these slice diagrams are referrring to:

sgordon777_1-1749483739114.png

 - There is no MUX_A field in the CCM_POST_ROOT88 register, as the above diagram implies.

- There *IS* a MUX_A field in the CCM_PRE_ROOT88 register.

- There is a "MUX field in the CCM_TARGET_ROOT88 register. This is what I've been trying to use. However as I've been saying, it locks the system if I choose a value other than 000, even if I select NON-PLL (external clocks). Also, the values I write in PREDIV, POSTDIV, and ENABLE fields for this register are completely ignored.

I hope you can clarify, Thanks

 

 

0 Kudos
Reply

706 Views
Zhiming_Liu
NXP TechSupport
NXP TechSupport

Hi,
1. Select source to VIDEO_PLL1_CLK:

CCM base + 0xa880
Zhiming_Liu_0-1749524087436.png

The MUX_A here is MUX bits in CCM_TARGET_ROOT81. To write CCM_TARGET_ROOTn, write 1 to the bits you want in CCM_TARGET_ROOTn_SET. To clear bits, write 1 to the bits you want in CCM_TARGET_ROOTn_CLR.  You need to use xxx_SET, xxx_CLR, and xxx_TOG interfaces. 

 

2. AUDIO_PLL1_OUT gate control.

CCM_ANALOG : 0x30360000+0X0
Zhiming_Liu_1-1749524541483.png

 


Best Regards,
Zhiming

0 Kudos
Reply

677 Views
sgordon777
Contributor I

>> You need to use xxx_SET, xxx_CLR, and xxx_TOG interfaces. 

Thanks, A couple comments on this:

1-First, I have tried this long ago (before writing to the forum) , and get EXACT same results as writing to base.

2-The manual implies that the set/clr/tog interface are for convenience, and not required

3-How could I use the set/clr/tog interface to set multi-bit patterns with both 1s and 0s, like MUX, as opposed to traditional &(~mask) | value ??? 

4-The FSL library definitely writes to "BASE"

 

 

0 Kudos
Reply

644 Views
Zhiming_Liu
NXP TechSupport
NXP TechSupport

Hi@sgordon777 

Have you had success in generating the base PLLs so far? To generate the base PLLs, the base address for them is 0x3036_0000. If you are porting ccm driver in zephyr, please refer functions in  drivers/clk/imx/clk-pll14xx.c, like clk_pll14xx_prepare, clk_pll1443x_set_rate. Is that what you said about writes being ignored happening base PLLs generation?



Best Regards,
Zhiming

0 Kudos
Reply

611 Views
sgordon777
Contributor I

Ok I have found the main problem: It was that my MMU configuration didn't have the PLL and CCM segments defined propperly. Once I defined these everything has fallen into place and I was able to configure, and select AudioPLL1 and confirm it's correct frequency in the SPDIF Tx BiPhase signal.

BUT

I'm still confused about the TxClkSource field of the SPDIF1's STC register. I was led to believe (see manual below) that 000 was the only valid option for this field. However, I could not get AudioPLL1 to rout to the SPDIF until I set this field to 001!? (I was lucky to stumble up upon this)

I'd really like some insight into this as I don;t like setting fields by trial and error. I have a simmilar question about the ClkSrc_Sel field of the SRPC register.

 

sgordon777_1-1749678100007.png

 

 

2) - field (bits 8:10).

#2  is where the Reference manual is flat wrong. The manual implies that 000b is the only choice, but you must set this field to the same value you've set to the CCM_TARGET_ROOTn - MUX field

sgordon777_0-1749677606250.png

 

 

0 Kudos
Reply

576 Views
Zhiming_Liu
NXP TechSupport
NXP TechSupport

Hi @sgordon777 

You've reminded me to check the spdif driver. This field is written in SPDIF driver which cause the TxClk_Source =111 before setting the source and clock rate. At least that's what's done from the linux driver. The reason why these bits are hidden is that for most customers there is no need to manually adjust these bits, the BSP are already done. Only core software development has the most detailed information, and support team doesn't have it. You can refer to the settings in the Linux SPDIF driver to set up the SRPC.

if (!fsl_spdif_can_set_clk_rate(spdif_priv, clk))
		goto clk_set_bypass;

	/* The S/PDIF block needs a clock of 64 * fs * txclk_df */
	ret = clk_set_rate(spdif_priv->txclk[clk],
			   64 * sample_rate * txclk_df);
	if (ret) {
		dev_err(&pdev->dev, "failed to set tx clock rate\n");
		return ret;
	}

clk_set_bypass:
	dev_dbg(&pdev->dev, "expected clock rate = %d\n",
			(64 * sample_rate * txclk_df * sysclk_df));
	dev_dbg(&pdev->dev, "actual clock rate = %ld\n",
			clk_get_rate(spdif_priv->txclk[clk]));

	/* set fs field in consumer channel status */
	spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs);

	/* select clock source and divisor */
	stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) |
	      STC_TXCLK_DF(txclk_df) | STC_SYSCLK_DF(sysclk_df);
	mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK |
	       STC_TXCLK_DF_MASK | STC_SYSCLK_DF_MASK;
	regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc);

	dev_dbg(&pdev->dev, "set sample rate to %dHz for %dHz playback\n",
			spdif_priv->txrate[rate], sample_rate);

	return 0;



Best Regards,
Zhiming

0 Kudos
Reply

561 Views
sgordon777
Contributor I

Thank Zhiming,

>> Only core software development has the most detailed information

>> You can refer to the settings in the Linux SPDIF driver to set up the SRPC.

I appreciate that (looking at the Linux source was next on my list, but I dont even know where to get it). I left the SRPC at 0

However, looking at Linux drivers isn't a substitute for having good bit-level documentation because I might be trying to do something in my Zephyr driver that the Linux driver doesnt do. We don't have BSP because we're designing the boards.

Can you tell me the difference between the SRPC:clocksrc and STC:clkcrc, and what each is used for?

-Field descriptions (fig2) say 0000 is the only option for both

-but the SPDIF system diagram(fig1) manual implies that SRPC:clksrc is used for muxing.

-But as I mentioned in the above pos, I had to set STC:TxClk_Source [bits 8:10] to 001 to get the AudioPLL1 to come through.

FIG1: SPDIF System diagram

sgordon777_2-1749741913942.png

FIG2: STC vs SRPC (both have txclk soruce field)

sgordon777_0-1749741743213.png

 

Would really appreciate clarification,

Steve

0 Kudos
Reply

516 Views
Zhiming_Liu
NXP TechSupport
NXP TechSupport

Hi @sgordon777 

1. In Figure 13-85, SRPC[CLKSRC_SEL] should be STC[TxClk_Source].

2. ClkSrc_Sel

0000b – if (DPLL Locked) SPDIF Rx Clock else 24M_REF_CLK
0001b – if (DPLL Locked) SPDIF Rx Clock else SPDIF1_CLK_ROOT
0010b – if (DPLL Locked) SPDIF Rx Clock else SPDIF1_CLK_ROOT
0011b – if (DPLL Locked) SPDIF Rx Clock else SPDIF1_CLK_ROOT
0100b – if (DPLL Locked) SPDIF Rx Clock else SPDIF1_CLK_ROOT
0101b – 24M_REF_CLK
0110b – SPDIF1_CLK_ROOT
0111b – SPDIF1_CLK_ROOT
1000b – SPDIF1_CLK_ROOT
1001b – SPDIF1_CLK_ROOT
1010b – if (DPLL Locked) SPDIF Rx Clock else SPDIF1_CLK_ROOT
1011b – if (DPLL Locked) SPDIF Rx Clock else SPDIF1_CLK_ROOT
1100b – SPDIF1_CLK_ROOT
1101b – SPDIF1_CLK_ROOT
Others: Reserved


This information is from design team.


Best Regards,
Zhiming

0 Kudos
Reply

471 Views
sgordon777
Contributor I

Thanks Zhiming, I appreciate you getting the design team involved. I think we're "almost there". Unfortuantely however, I was not able to see the effects of switching between RX-derived clock which is described in the above table. Here's what I did:
1-SPDIF1_STC[TxClk_Source] = 0, build, run
2-Unplug SPDIF_IN cable: Measure SPDIF_Tx Biphase clock = 24.000 Mhz
3-Plug in SPDIF_IN cable and Verify PLL lock: Measrure SPDIF_Tx Biphase clock = 24.000 Mhz (according to the diagram above, this should be 24.576 Hz (the frequency of the measured PLL from SPDIF_IN)

I tried many of the options in your list but none worked.
Is there something I need to turn on or some register to set in order to enable this automatic switching between RX-derived clock and the ROOT-Slice options?
Automatic switching is not a requirement. However clocking SPDIF-TX from SPDIF-RX derived block is a hard requirement for our product and we were told that this is possible.

I also am still hoping to answer the question of what is SRPC[CLKSRC_SEL] used for? (though this is secondary to the above concern).

Again, we are using a MIMX8MM5

Thanks, Steve

0 Kudos
Reply

178 Views
Zhiming_Liu
NXP TechSupport
NXP TechSupport

Hi @sgordon777 

Here are reference driver  in Linux driver:linux/sound/soc/fsl/fsl_spdif.c at master · torvalds/linux

The DPLL lock will trigger interrupt and enter spdif_isr, set spdif_priv->dpll_locked=true.

if (sis & INT_DPLL_LOCKED)
		spdif_irq_dpll_lock(spdif_priv);



/* DPLL locked and lock loss interrupt handler */
static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv)
{
	struct regmap *regmap = spdif_priv->regmap;
	struct platform_device *pdev = spdif_priv->pdev;
	u32 locked;

	regmap_read(regmap, REG_SPDIF_SRPC, &locked);
	locked &= SRPC_DPLL_LOCKED;

	dev_dbg(&pdev->dev, "isr: Rx dpll %s \n",
			locked ? "locked" : "loss lock");

	spdif_priv->dpll_locked = locked ? true : false;

	if (spdif_priv->snd_card && spdif_priv->rxrate_kcontrol) {
		snd_ctl_notify(spdif_priv->snd_card,
			       SNDRV_CTL_EVENT_MASK_VALUE,
			       &spdif_priv->rxrate_kcontrol->id);
	}
}

 

The following function is not suitable for your application scenario. But we need to make sure the DPLL is locked.

Make sure spdif_private->rxrate_kcontrol can be got.

spdif_private->rxrate_kcontrol = snd_soc_card_get_kcontrol(dai->component->card,
								   RX_SAMPLE_RATE_KCONTROL);

 

/* Index list for the values that has if (DPLL Locked) condition */
static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
spdif_set_rx_clksrc, handle hw params. 
 
static int fsl_spdif_hw_params(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *params,
				struct snd_soc_dai *dai)
{
	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
	struct platform_device *pdev = spdif_priv->pdev;
	u32 sample_rate = params_rate(params);
	int ret = 0;

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		ret = spdif_reparent_rootclk(spdif_priv, sample_rate);
		if (ret) {
			dev_err(&pdev->dev, "%s: reparent root clk failed: %d\n",
				__func__, sample_rate);
			return ret;
		}

		ret  = spdif_set_sample_rate(substream, sample_rate);
		if (ret) {
			dev_err(&pdev->dev, "%s: set sample rate failed: %d\n",
					__func__, sample_rate);
			return ret;
		}
		spdif_set_cstatus(ctrl, IEC958_AES3_CON_CLOCK,
				  IEC958_AES3_CON_CLOCK_1000PPM);
		spdif_write_channel_status(spdif_priv);
	} else {
		/* Setup rx clock source */
		ret = spdif_set_rx_clksrc(spdif_priv, SPDIF_DEFAULT_GAINSEL, 1);
	}

	return ret;
}

/* Set SPDIF PhaseConfig register for rx clock */
static int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv,
				enum spdif_gainsel gainsel, int dpll_locked)
{
	struct regmap *regmap = spdif_priv->regmap;
	u8 clksrc=spdif_priv->rxclk_src;

	if (clksrc >= SRPC_CLKSRC_MAX || gainsel >= GAINSEL_MULTI_MAX)
		return -EINVAL;

	regmap_update_bits(regmap, REG_SPDIF_SRPC,
			SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK,
			SRPC_CLKSRC_SEL_SET(clksrc) | SRPC_GAINSEL_SET(gainsel));

	return 0;
}

Get RX data clock rate given the SPDIF bus_clk
 
/*
 * Get DPLL lock or not info from stable interrupt status register.
 * User application must use this control to get locked,
 * then can do next PCM operation
 */
static int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
	int rate = 0;

	if (spdif_priv->dpll_locked)
		rate = spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL);

	ucontrol->value.integer.value[0] = rate;

	return 0;
}

/* Get RX data clock rate given the SPDIF bus_clk */
static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv,
				enum spdif_gainsel gainsel)
{
	struct regmap *regmap = spdif_priv->regmap;
	struct platform_device *pdev = spdif_priv->pdev;
	u64 tmpval64, busclk_freq = 0;
	u32 freqmeas, phaseconf;
	u8 clksrc;

	regmap_read(regmap, REG_SPDIF_SRFM, &freqmeas);
	regmap_read(regmap, REG_SPDIF_SRPC, &phaseconf);

	clksrc=(phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf;

	/* Get bus clock from system */
	if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED))
		busclk_freq = clk_get_rate(spdif_priv->sysclk);

	/* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */
	tmpval64 = (u64) busclk_freq * freqmeas;
	do_div(tmpval64, gainsel_multi[gainsel] * 1024);
	do_div(tmpval64, 128 * 1024);

	dev_dbg(&pdev->dev, "FreqMeas: %d\n", freqmeas);
	dev_dbg(&pdev->dev, "BusclkFreq: %lld\n", busclk_freq);
	dev_dbg(&pdev->dev, "RxRate: %lld\n", tmpval64);

	return (int)tmpval64;
}



Best Regards,
Zhiming

0 Kudos
Reply

143 Views
sgordon777
Contributor I

>> Make sure the DPLL is locked

I absolutely did do this, as you can see in my query. Not only did I verify the DPLL was locked, I also verified that FreqMeas is measuring the exact right frequency of the RX signal. Look forward to hearing more.

 

Original query:

"3-Plug in SPDIF_IN cable and Verify PLL lock: Measrure SPDIF_Tx Biphase clock = 24.000 Mhz (according to the diagram above, this should be 24.576 Hz (the frequency of the measured PLL from SPDIF_IN)"

0 Kudos
Reply