07-24-2022, 03:38 AM
(This post was last modified: 07-24-2022, 04:08 AM by CounterPillow.)
Hi there, thanks for this extensive level of looking into it. I hope I can shed some more light from my Quartz64 SPDIF experience: over there it uses pretty much the same driver. I don't know if the controller on the SoC is exactly the same, but it likely is. SPDIF on the Quartz64 Model A works fine.
A few things I've noticed while looking at the schematic:
1. Apparently there's a second SPDIF thing connected to some driver, not on the Pi-2 header? Not sure what that's about.
2. The one on the Pi-2 bus GPIO header doesn't have a low-pass filter. The Quartz64 Model A uses a low-pass filter of 220 MHz.
I don't have an oscilloscope to try and reproduce your measurements (I'm working on it, desk space in my room is at a premium) but you can try using TOSlink instead of coax to optoisolate the whole thing and rule out problems with the transmission line even further. I can send you one of my less well soldered together Quartz64 Model A TOSlink adapters for free if you need a breakout board with a driver IC/LED combo that can handle both 3.3V and 5V, you'll just have to connect to the right pins with jumper wires.
However, the information you gave about 44.1 KHz working better than 48 KHz and 96 KHz not working at all points towards some sort of buffer issue maybe. Try adding some debug instrumentation to sound/soc/rockchip/rockchip_spdif.c.
I don't have access to the Part 2 of the RK3399 TRM in which SPDIF is documented, but I do have access to the RK356x TRM which should have the same SPDIF controller.
One thing I can see right now when comparing the TRM with the driver is the following discrepancy: the SPDIF_CFGR has bits 23:16 assigned like this:
The driver sets mclk to srate * 128 in rk_spdif_hw_params. However, it doesn't seem to write the register, unless I'm missing something. It does write "val" but "val" has nothing to do with the mclk value being set it seems.
The comment above the clock setting call says /* Set clock and calculate divider */ but it never seems to calculate/set the divider.
Downstream BSP kernel driver in the RK3588 SDK does this seemingly differently:
Whereby the defines used are
Interestingly, this doesn't set the mclk rate at all, this is done in rk_spdif_set_sysclk.
Hope this is of some help to you, I just quickly looked over this while having my morning coffee. It definitely looks like a driver issue to me, and it'd be great if we could get it sorted.
A few things I've noticed while looking at the schematic:
1. Apparently there's a second SPDIF thing connected to some driver, not on the Pi-2 header? Not sure what that's about.
2. The one on the Pi-2 bus GPIO header doesn't have a low-pass filter. The Quartz64 Model A uses a low-pass filter of 220 MHz.
I don't have an oscilloscope to try and reproduce your measurements (I'm working on it, desk space in my room is at a premium) but you can try using TOSlink instead of coax to optoisolate the whole thing and rule out problems with the transmission line even further. I can send you one of my less well soldered together Quartz64 Model A TOSlink adapters for free if you need a breakout board with a driver IC/LED combo that can handle both 3.3V and 5V, you'll just have to connect to the right pins with jumper wires.
However, the information you gave about 44.1 KHz working better than 48 KHz and 96 KHz not working at all points towards some sort of buffer issue maybe. Try adding some debug instrumentation to sound/soc/rockchip/rockchip_spdif.c.
I don't have access to the Part 2 of the RK3399 TRM in which SPDIF is documented, but I do have access to the RK356x TRM which should have the same SPDIF controller.
One thing I can see right now when comparing the TRM with the driver is the following discrepancy: the SPDIF_CFGR has bits 23:16 assigned like this:
The driver sets mclk to srate * 128 in rk_spdif_hw_params. However, it doesn't seem to write the register, unless I'm missing something. It does write "val" but "val" has nothing to do with the mclk value being set it seems.
The comment above the clock setting call says /* Set clock and calculate divider */ but it never seems to calculate/set the divider.
Downstream BSP kernel driver in the RK3588 SDK does this seemingly differently:
Code:
static int rk_spdif_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai);
unsigned int val = SPDIF_CFGR_HALFWORD_ENABLE;
unsigned int mclk_rate = clk_get_rate(spdif->mclk);
int bmc, div;
int ret;
/* bmc = 128fs */
bmc = 128 * params_rate(params);
div = DIV_ROUND_CLOSEST(mclk_rate, bmc);
val |= SPDIF_CFGR_CLK_DIV(div);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
val |= SPDIF_CFGR_VDW_16;
break;
case SNDRV_PCM_FORMAT_S20_3LE:
val |= SPDIF_CFGR_VDW_20;
break;
case SNDRV_PCM_FORMAT_S24_LE:
val |= SPDIF_CFGR_VDW_24;
break;
default:
return -EINVAL;
}
ret = regmap_update_bits(spdif->regmap, SPDIF_CFGR,
SPDIF_CFGR_CLK_DIV_MASK |
SPDIF_CFGR_HALFWORD_ENABLE |
SDPIF_CFGR_VDW_MASK, val);
return ret;
}
Whereby the defines used are
Code:
#define SPDIF_CFGR_CLK_DIV_SHIFT (16)
#define SPDIF_CFGR_CLK_DIV_MASK (0xff << SPDIF_CFGR_CLK_DIV_SHIFT)
#define SPDIF_CFGR_CLK_DIV(x) ((x - 1) << SPDIF_CFGR_CLK_DIV_SHIFT)
Interestingly, this doesn't set the mclk rate at all, this is done in rk_spdif_set_sysclk.
Hope this is of some help to you, I just quickly looked over this while having my morning coffee. It definitely looks like a driver issue to me, and it'd be great if we could get it sorted.
Occasional Linux Kernel Contributor, Avid Wiki Updater, Ask Me About Quartz64
Open Hardware Quartz64 Model A TOSLink Adapter
Pi-bus GPIO Extender For ROCKPro64 And Quartz64 Model A
Plebian GNU/Linux