The I2S MCLK outputs on RK3588 are gated by bits in the SYS_GRF
register SOC_CON6 (offset 0x318). These gates control whether the
internal CRU MCLK signals reach the external IO pins connected to
audio codecs.
The kernel should explicitly manage these gates so that audio
functionality does not depend on bootloader register state. This is
analogous to what was done for RK3576 SAI MCLK outputs [1].
Register the SYS_GRF as an auxiliary GRF with grf_type_sys in the
early clock init, and add GATE_GRF entries for all four I2S MCLK
output gates:
- I2S0_8CH_MCLKOUT_TO_IO (bit 0)
- I2S1_8CH_MCLKOUT_TO_IO (bit 1)
- I2S2_2CH_MCLKOUT_TO_IO (bit 2)
- I2S3_2CH_MCLKOUT_TO_IO (bit 7)
Board DTS files that need MCLK on an IO pin can reference these
clocks, e.g.:
clocks = <&cru I2S0_8CH_MCLKOUT_TO_IO>;
Tested on the Youyeetoo YY3588 (RK3588) with an ES8388 codec on I2S0.
[1] https://lore.kernel.org/r/20250305-rk3576-sai-v1-2-64e6cf863e9a@collabora.com/
Signed-off-by: Daniele Briguglio <hello@superkali.me>
---
drivers/clk/rockchip/clk-rk3588.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c
index 1694223f4f84..0e550642c655 100644
--- a/drivers/clk/rockchip/clk-rk3588.c
+++ b/drivers/clk/rockchip/clk-rk3588.c
@@ -5,6 +5,7 @@
*/
#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
@@ -892,6 +893,8 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_CLKGATE_CON(8), 0, GFLAGS),
MUX(I2S2_2CH_MCLKOUT, "i2s2_2ch_mclkout", i2s2_2ch_mclkout_p, CLK_SET_RATE_PARENT,
RK3588_CLKSEL_CON(30), 2, 1, MFLAGS),
+ GATE_GRF(I2S2_2CH_MCLKOUT_TO_IO, "i2s2_2ch_mclkout_to_io", "i2s2_2ch_mclkout",
+ 0, 0x0318, 2, GFLAGS, grf_type_sys),
COMPOSITE(CLK_I2S3_2CH_SRC, "clk_i2s3_2ch_src", gpll_aupll_p, 0,
RK3588_CLKSEL_CON(30), 8, 1, MFLAGS, 3, 5, DFLAGS,
@@ -907,6 +910,8 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_CLKGATE_CON(8), 4, GFLAGS),
MUX(I2S3_2CH_MCLKOUT, "i2s3_2ch_mclkout", i2s3_2ch_mclkout_p, CLK_SET_RATE_PARENT,
RK3588_CLKSEL_CON(32), 2, 1, MFLAGS),
+ GATE_GRF(I2S3_2CH_MCLKOUT_TO_IO, "i2s3_2ch_mclkout_to_io", "i2s3_2ch_mclkout",
+ 0, 0x0318, 7, GFLAGS, grf_type_sys),
GATE(PCLK_ACDCDIG, "pclk_acdcdig", "pclk_audio_root", 0,
RK3588_CLKGATE_CON(7), 11, GFLAGS),
GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_audio_root", 0,
@@ -935,6 +940,8 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_CLKGATE_CON(7), 10, GFLAGS),
MUX(I2S0_8CH_MCLKOUT, "i2s0_8ch_mclkout", i2s0_8ch_mclkout_p, CLK_SET_RATE_PARENT,
RK3588_CLKSEL_CON(28), 2, 2, MFLAGS),
+ GATE_GRF(I2S0_8CH_MCLKOUT_TO_IO, "i2s0_8ch_mclkout_to_io", "i2s0_8ch_mclkout",
+ 0, 0x0318, 0, GFLAGS, grf_type_sys),
GATE(HCLK_PDM1, "hclk_pdm1", "hclk_audio_root", 0,
RK3588_CLKGATE_CON(9), 6, GFLAGS),
@@ -2220,6 +2227,8 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_PMU_CLKGATE_CON(2), 13, GFLAGS),
MUX(I2S1_8CH_MCLKOUT, "i2s1_8ch_mclkout", i2s1_8ch_mclkout_p, CLK_SET_RATE_PARENT,
RK3588_PMU_CLKSEL_CON(9), 2, 2, MFLAGS),
+ GATE_GRF(I2S1_8CH_MCLKOUT_TO_IO, "i2s1_8ch_mclkout_to_io", "i2s1_8ch_mclkout",
+ 0, 0x0318, 1, GFLAGS, grf_type_sys),
GATE(PCLK_PMU1, "pclk_pmu1", "pclk_pmu0_root", CLK_IS_CRITICAL,
RK3588_PMU_CLKGATE_CON(1), 0, GFLAGS),
GATE(CLK_DDR_FAIL_SAFE, "clk_ddr_fail_safe", "clk_pmu0", CLK_IGNORE_UNUSED,
@@ -2439,6 +2448,8 @@ static struct rockchip_clk_branch rk3588_clk_branches[] = {
static void __init rk3588_clk_early_init(struct device_node *np)
{
struct rockchip_clk_provider *ctx;
+ struct rockchip_aux_grf *sys_grf_e;
+ struct regmap *sys_grf;
unsigned long clk_nr_clks, max_clk_id1, max_clk_id2;
void __iomem *reg_base;
@@ -2479,6 +2490,17 @@ static void __init rk3588_clk_early_init(struct device_node *np)
&rk3588_cpub1clk_data, rk3588_cpub1clk_rates,
ARRAY_SIZE(rk3588_cpub1clk_rates));
+ /* Register SYS_GRF for I2S MCLK output to IO gate clocks */
+ sys_grf = syscon_regmap_lookup_by_compatible("rockchip,rk3588-sys-grf");
+ if (!IS_ERR(sys_grf)) {
+ sys_grf_e = kzalloc_obj(*sys_grf_e);
+ if (sys_grf_e) {
+ sys_grf_e->grf = sys_grf;
+ sys_grf_e->type = grf_type_sys;
+ hash_add(ctx->aux_grf_table, &sys_grf_e->node, grf_type_sys);
+ }
+ }
+
rockchip_clk_register_branches(ctx, rk3588_early_clk_branches,
ARRAY_SIZE(rk3588_early_clk_branches));
--
2.53.0
Hi Daniele,
kernel test robot noticed the following build errors:
[auto build test ERROR on b84a0ebe421ca56995ff78b66307667b62b3a900]
url: https://github.com/intel-lab-lkp/linux/commits/Daniele-Briguglio/dt-bindings-clock-rockchip-rk3588-cru-add-I2S-MCLK-output-to-IO-clock-IDs/20260316-222240
base: b84a0ebe421ca56995ff78b66307667b62b3a900
patch link: https://lore.kernel.org/r/20260316-rk3588-mclk-gate-grf-v1-3-66fb9a246718%40superkali.me
patch subject: [PATCH 3/3] clk: rockchip: rk3588: add GATE_GRF clocks for I2S MCLK output to IO
config: arm-allyesconfig (https://download.01.org/0day-ci/archive/20260319/202603191419.MH6EuPga-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260319/202603191419.MH6EuPga-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603191419.MH6EuPga-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/clk/rockchip/clk-rk3588.c: In function 'rk3588_clk_early_init':
>> drivers/clk/rockchip/clk-rk3588.c:2496:29: error: implicit declaration of function 'kzalloc_obj' [-Wimplicit-function-declaration]
2496 | sys_grf_e = kzalloc_obj(*sys_grf_e);
| ^~~~~~~~~~~
>> drivers/clk/rockchip/clk-rk3588.c:2496:27: error: assignment to 'struct rockchip_aux_grf *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
2496 | sys_grf_e = kzalloc_obj(*sys_grf_e);
| ^
vim +/kzalloc_obj +2496 drivers/clk/rockchip/clk-rk3588.c
2447
2448 static void __init rk3588_clk_early_init(struct device_node *np)
2449 {
2450 struct rockchip_clk_provider *ctx;
2451 struct rockchip_aux_grf *sys_grf_e;
2452 struct regmap *sys_grf;
2453 unsigned long clk_nr_clks, max_clk_id1, max_clk_id2;
2454 void __iomem *reg_base;
2455
2456 max_clk_id1 = rockchip_clk_find_max_clk_id(rk3588_clk_branches,
2457 ARRAY_SIZE(rk3588_clk_branches));
2458 max_clk_id2 = rockchip_clk_find_max_clk_id(rk3588_early_clk_branches,
2459 ARRAY_SIZE(rk3588_early_clk_branches));
2460 clk_nr_clks = max(max_clk_id1, max_clk_id2) + 1;
2461
2462 reg_base = of_iomap(np, 0);
2463 if (!reg_base) {
2464 pr_err("%s: could not map cru region\n", __func__);
2465 return;
2466 }
2467
2468 ctx = rockchip_clk_init_early(np, reg_base, clk_nr_clks);
2469 if (IS_ERR(ctx)) {
2470 pr_err("%s: rockchip clk init failed\n", __func__);
2471 iounmap(reg_base);
2472 return;
2473 }
2474 early_ctx = ctx;
2475
2476 rockchip_clk_register_plls(ctx, rk3588_pll_clks,
2477 ARRAY_SIZE(rk3588_pll_clks),
2478 RK3588_GRF_SOC_STATUS0);
2479
2480 rockchip_clk_register_armclk(ctx, ARMCLK_L, "armclk_l",
2481 mux_armclkl_p, ARRAY_SIZE(mux_armclkl_p),
2482 &rk3588_cpulclk_data, rk3588_cpulclk_rates,
2483 ARRAY_SIZE(rk3588_cpulclk_rates));
2484 rockchip_clk_register_armclk(ctx, ARMCLK_B01, "armclk_b01",
2485 mux_armclkb01_p, ARRAY_SIZE(mux_armclkb01_p),
2486 &rk3588_cpub0clk_data, rk3588_cpub0clk_rates,
2487 ARRAY_SIZE(rk3588_cpub0clk_rates));
2488 rockchip_clk_register_armclk(ctx, ARMCLK_B23, "armclk_b23",
2489 mux_armclkb23_p, ARRAY_SIZE(mux_armclkb23_p),
2490 &rk3588_cpub1clk_data, rk3588_cpub1clk_rates,
2491 ARRAY_SIZE(rk3588_cpub1clk_rates));
2492
2493 /* Register SYS_GRF for I2S MCLK output to IO gate clocks */
2494 sys_grf = syscon_regmap_lookup_by_compatible("rockchip,rk3588-sys-grf");
2495 if (!IS_ERR(sys_grf)) {
> 2496 sys_grf_e = kzalloc_obj(*sys_grf_e);
2497 if (sys_grf_e) {
2498 sys_grf_e->grf = sys_grf;
2499 sys_grf_e->type = grf_type_sys;
2500 hash_add(ctx->aux_grf_table, &sys_grf_e->node, grf_type_sys);
2501 }
2502 }
2503
2504 rockchip_clk_register_branches(ctx, rk3588_early_clk_branches,
2505 ARRAY_SIZE(rk3588_early_clk_branches));
2506
2507 rockchip_clk_of_add_provider(np, ctx);
2508 }
2509 CLK_OF_DECLARE_DRIVER(rk3588_cru, "rockchip,rk3588-cru", rk3588_clk_early_init);
2510
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.