From 994633894f208a0151baaee1688ab3c431912553 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sun, 6 Apr 2025 12:53:18 -0400 Subject: [PATCH 01/16] tools/power turbostat: re-factor sysfs code Probe cpuidle "sysfs" residency and counts separately, since soon we will make one disabled on, and the other disabled off. Clarify that some BIC (build-in-counters) are actually "groups". since we're about to re-name some of those groups. no functional change. Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 31 ++++++++++++++++++--------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index c9a34c16c7a8..df0391bedcde 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -273,10 +273,10 @@ struct msr_counter bic[] = { #define BIC_NMI (1ULL << 61) #define BIC_CPU_c1e (1ULL << 62) -#define BIC_TOPOLOGY (BIC_Package | BIC_Node | BIC_CoreCnt | BIC_PkgCnt | BIC_Core | BIC_CPU | BIC_Die) -#define BIC_THERMAL_PWR (BIC_CoreTmp | BIC_PkgTmp | BIC_PkgWatt | BIC_CorWatt | BIC_GFXWatt | BIC_RAMWatt | BIC_PKG__ | BIC_RAM__ | BIC_SysWatt) -#define BIC_FREQUENCY (BIC_Avg_MHz | BIC_Busy | BIC_Bzy_MHz | BIC_TSC_MHz | BIC_GFXMHz | BIC_GFXACTMHz | BIC_SAMMHz | BIC_SAMACTMHz | BIC_UNCORE_MHZ) -#define BIC_IDLE (BIC_Busy | BIC_sysfs | BIC_CPU_c1 | BIC_CPU_c3 | BIC_CPU_c6 | BIC_CPU_c7 | BIC_GFX_rc6 | BIC_Pkgpc2 | BIC_Pkgpc3 | BIC_Pkgpc6 | BIC_Pkgpc7 | BIC_Pkgpc8 | BIC_Pkgpc9 | BIC_Pkgpc10 | BIC_CPU_LPI | BIC_SYS_LPI | BIC_Mod_c6 | BIC_Totl_c0 | BIC_Any_c0 | BIC_GFX_c0 | BIC_CPUGFX | BIC_SAM_mc6 | BIC_Diec6) +#define BIC_GROUP_TOPOLOGY (BIC_Package | BIC_Node | BIC_CoreCnt | BIC_PkgCnt | BIC_Core | BIC_CPU | BIC_Die) +#define BIC_GROUP_THERMAL_PWR (BIC_CoreTmp | BIC_PkgTmp | BIC_PkgWatt | BIC_CorWatt | BIC_GFXWatt | BIC_RAMWatt | BIC_PKG__ | BIC_RAM__ | BIC_SysWatt) +#define BIC_GROUP_FREQUENCY (BIC_Avg_MHz | BIC_Busy | BIC_Bzy_MHz | BIC_TSC_MHz | BIC_GFXMHz | BIC_GFXACTMHz | BIC_SAMMHz | BIC_SAMACTMHz | BIC_UNCORE_MHZ) +#define BIC_GROUP_IDLE (BIC_Busy | BIC_sysfs | BIC_CPU_c1 | BIC_CPU_c3 | BIC_CPU_c6 | BIC_CPU_c7 | BIC_GFX_rc6 | BIC_Pkgpc2 | BIC_Pkgpc3 | BIC_Pkgpc6 | BIC_Pkgpc7 | BIC_Pkgpc8 | BIC_Pkgpc9 | BIC_Pkgpc10 | BIC_CPU_LPI | BIC_SYS_LPI | BIC_Mod_c6 | BIC_Totl_c0 | BIC_Any_c0 | BIC_GFX_c0 | BIC_CPUGFX | BIC_SAM_mc6 | BIC_Diec6) #define BIC_OTHER (BIC_IRQ | BIC_NMI | BIC_SMI | BIC_ThreadC | BIC_CoreTmp | BIC_IPC) #define BIC_DISABLED_BY_DEFAULT (BIC_USEC | BIC_TOD | BIC_APIC | BIC_X2APIC) @@ -2354,16 +2354,16 @@ unsigned long long bic_lookup(char *name_list, enum show_hide_mode mode) retval |= ~0; break; } else if (!strcmp(name_list, "topology")) { - retval |= BIC_TOPOLOGY; + retval |= BIC_GROUP_TOPOLOGY; break; } else if (!strcmp(name_list, "power")) { - retval |= BIC_THERMAL_PWR; + retval |= BIC_GROUP_THERMAL_PWR; break; } else if (!strcmp(name_list, "idle")) { - retval |= BIC_IDLE; + retval |= BIC_GROUP_IDLE; break; } else if (!strcmp(name_list, "frequency")) { - retval |= BIC_FREQUENCY; + retval |= BIC_GROUP_FREQUENCY; break; } else if (!strcmp(name_list, "other")) { retval |= BIC_OTHER; @@ -10260,7 +10260,7 @@ int is_deferred_skip(char *name) return 0; } -void probe_sysfs(void) +void probe_cpuidle_residency(void) { char path[64]; char name_buf[16]; @@ -10304,6 +10304,16 @@ void probe_sysfs(void) if (state < min_state) min_state = state; } +} + +void probe_cpuidle_counts(void) +{ + char path[64]; + char name_buf[16]; + FILE *input; + int state; + int min_state = 1024, max_state = 0; + char *sp; for (state = 10; state >= 0; --state) { @@ -10602,7 +10612,8 @@ skip_cgroup_setting: print_bootcmd(); } - probe_sysfs(); + probe_cpuidle_residency(); + probe_cpuidle_counts(); if (!getuid()) set_rlimit(); -- 2.51.0 From 6f110a5e4f9977c31ce76fefbfef6fd4eab6bfb7 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 6 Apr 2025 10:00:04 -0700 Subject: [PATCH 02/16] Disable SLUB_TINY for build testing ... and don't error out so hard on missing module descriptions. Before commit 6c6c1fc09de3 ("modpost: require a MODULE_DESCRIPTION()") we used to warn about missing module descriptions, but only when building with extra warnigns (ie 'W=1'). After that commit the warning became an unconditional hard error. And it turns out not all modules have been converted despite the claims to the contrary. As reported by Damian Tometzki, the slub KUnit test didn't have a module description, and apparently nobody ever really noticed. The reason nobody noticed seems to be that the slub KUnit tests get disabled by SLUB_TINY, which also ends up disabling a lot of other code, both in tests and in slub itself. And so anybody doing full build tests didn't actually see this failre. So let's disable SLUB_TINY for build-only tests, since it clearly ends up limiting build coverage. Also turn the missing module descriptions error back into a warning, but let's keep it around for non-'W=1' builds. Reported-by: Damian Tometzki Link: https://lore.kernel.org/all/01070196099fd059-e8463438-7b1b-4ec8-816d-173874be9966-000000@eu-central-1.amazonses.com/ Cc: Masahiro Yamada Cc: Jeff Johnson Fixes: 6c6c1fc09de3 ("modpost: require a MODULE_DESCRIPTION()") Signed-off-by: Linus Torvalds --- mm/Kconfig | 2 +- scripts/mod/modpost.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/Kconfig b/mm/Kconfig index d3fb3762887b..e113f713b493 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -201,7 +201,7 @@ config KVFREE_RCU_BATCHED config SLUB_TINY bool "Configure for minimal memory footprint" - depends on EXPERT + depends on EXPERT && !COMPILE_TEST select SLAB_MERGE_DEFAULT help Configures the slab allocator in a way to achieve minimal memory diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 92627e8d0e16..be89921d60b6 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1603,7 +1603,7 @@ static void read_symbols(const char *modname) } if (!get_modinfo(&info, "description")) - error("missing MODULE_DESCRIPTION() in %s\n", modname); + warn("missing MODULE_DESCRIPTION() in %s\n", modname); } for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { -- 2.51.0 From ec4acd3166d8a7a03b059d01b9c6f11a658e833f Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sun, 6 Apr 2025 14:29:57 -0400 Subject: [PATCH 03/16] tools/power turbostat: disable "cpuidle" invocation counters, by default Create "pct_idle" counter group, the sofware notion of residency so it can now be singled out, independent of other counter groups. Create "cpuidle" group, the cpuidle invocation counts. Disable "cpuidle", by default. Create "swidle" = "cpuidle" + "pct_idle". Undocument "sysfs", the old name for "swidle", but keep it working for backwards compatibilty. Create "hwidle", all the HW idle counters Modify "idle", enabled by default "idle" = "hwidle" + "pct_idle" (and now excludes "cpuidle") Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.8 | 12 +++++----- tools/power/x86/turbostat/turbostat.c | 34 +++++++++++++++++++++------ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index e86493880c16..b74ed916057e 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 @@ -100,7 +100,7 @@ The column name "all" can be used to enable all disabled-by-default built-in cou .PP \fB--show column\fP show only the specified built-in columns. May be invoked multiple times, or with a comma-separated list of column names. .PP -\fB--show CATEGORY --hide CATEGORY\fP Show and hide also accept a single CATEGORY of columns: "all", "topology", "idle", "frequency", "power", "sysfs", "other". +\fB--show CATEGORY --hide CATEGORY\fP Show and hide also accept a single CATEGORY of columns: "all", "topology", "idle", "frequency", "power", "cpuidle", "hwidle", "swidle", "other". "idle" (enabled by default), includes "hwidle" and "idle_pct". "cpuidle" (default disabled) includes cpuidle software invocation counters. "swidle" includes "cpuidle" plus "idle_pct". "hwidle" includes only hardware based idle residency counters. Older versions of turbostat used the term "sysfs" for what is now "swidle". .PP \fB--Dump\fP displays the raw counter values. .PP @@ -158,15 +158,15 @@ The system configuration dump (if --quiet is not used) is followed by statistics .PP \fBSMI\fP The number of System Management Interrupts serviced CPU during the measurement interval. While this counter is actually per-CPU, SMI are triggered on all processors, so the number should be the same for all CPUs. .PP -\fBC1, C2, C3...\fP The number times Linux requested the C1, C2, C3 idle state during the measurement interval. The system summary line shows the sum for all CPUs. These are C-state names as exported in /sys/devices/system/cpu/cpu*/cpuidle/state*/name. While their names are generic, their attributes are processor specific. They the system description section of output shows what MWAIT sub-states they are mapped to on each system. +\fBC1, C2, C3...\fP The number times Linux requested the C1, C2, C3 idle state during the measurement interval. The system summary line shows the sum for all CPUs. These are C-state names as exported in /sys/devices/system/cpu/cpu*/cpuidle/state*/name. While their names are generic, their attributes are processor specific. They the system description section of output shows what MWAIT sub-states they are mapped to on each system. These counters are in the "cpuidle" group, which is disabled, by default. .PP -\fBC1+, C2+, C3+...\fP The idle governor idle state misprediction statistics. Inidcates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a deeper idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/below file. +\fBC1+, C2+, C3+...\fP The idle governor idle state misprediction statistics. Inidcates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a deeper idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/below file. These counters are in the "cpuidle" group, which is disabled, by default. .PP -\fBC1-, C2-, C3-...\fP The idle governor idle state misprediction statistics. Inidcates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a shallower idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/above file. +\fBC1-, C2-, C3-...\fP The idle governor idle state misprediction statistics. Inidcates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a shallower idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/above file. These counters are in the "cpuidle" group, which is disabled, by default. .PP -\fBC1%, C2%, C3%\fP The residency percentage that Linux requested C1, C2, C3.... The system summary is the average of all CPUs in the system. Note that these are software, reflecting what was requested. The hardware counters reflect what was actually achieved. +\fBC1%, C2%, C3%\fP The residency percentage that Linux requested C1, C2, C3.... The system summary is the average of all CPUs in the system. Note that these are software, reflecting what was requested. The hardware counters reflect what was actually achieved. These counters are in the "pct_idle" group, which is enabled by default. .PP -\fBCPU%c1, CPU%c3, CPU%c6, CPU%c7\fP show the percentage residency in hardware core idle states. These numbers are from hardware residency counters. +\fBCPU%c1, CPU%c3, CPU%c6, CPU%c7\fP show the percentage residency in hardware core idle states. These numbers are from hardware residency counters and are in the "hwidle" group, which is enabled, by default. .PP \fBCoreTmp\fP Degrees Celsius reported by the per-core Digital Thermal Sensor. .PP diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index df0391bedcde..ab184f95cdaf 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -153,7 +153,7 @@ struct msr_counter bic[] = { { 0x0, "TSC_MHz", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "IRQ", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "SMI", NULL, 32, 0, FORMAT_DELTA, NULL, 0 }, - { 0x0, "sysfs", NULL, 0, 0, 0, NULL, 0 }, + { 0x0, "cpuidle", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "CPU%c1", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "CPU%c3", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "CPU%c6", NULL, 0, 0, 0, NULL, 0 }, @@ -206,6 +206,7 @@ struct msr_counter bic[] = { { 0x0, "Sys_J", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "NMI", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "CPU%c1e", NULL, 0, 0, 0, NULL, 0 }, + { 0x0, "pct_idle", NULL, 0, 0, 0, NULL, 0 }, }; #define MAX_BIC (sizeof(bic) / sizeof(struct msr_counter)) @@ -219,7 +220,7 @@ struct msr_counter bic[] = { #define BIC_TSC_MHz (1ULL << 7) #define BIC_IRQ (1ULL << 8) #define BIC_SMI (1ULL << 9) -#define BIC_sysfs (1ULL << 10) +#define BIC_cpuidle (1ULL << 10) #define BIC_CPU_c1 (1ULL << 11) #define BIC_CPU_c3 (1ULL << 12) #define BIC_CPU_c6 (1ULL << 13) @@ -272,17 +273,20 @@ struct msr_counter bic[] = { #define BIC_Sys_J (1ULL << 60) #define BIC_NMI (1ULL << 61) #define BIC_CPU_c1e (1ULL << 62) +#define BIC_pct_idle (1ULL << 63) #define BIC_GROUP_TOPOLOGY (BIC_Package | BIC_Node | BIC_CoreCnt | BIC_PkgCnt | BIC_Core | BIC_CPU | BIC_Die) #define BIC_GROUP_THERMAL_PWR (BIC_CoreTmp | BIC_PkgTmp | BIC_PkgWatt | BIC_CorWatt | BIC_GFXWatt | BIC_RAMWatt | BIC_PKG__ | BIC_RAM__ | BIC_SysWatt) #define BIC_GROUP_FREQUENCY (BIC_Avg_MHz | BIC_Busy | BIC_Bzy_MHz | BIC_TSC_MHz | BIC_GFXMHz | BIC_GFXACTMHz | BIC_SAMMHz | BIC_SAMACTMHz | BIC_UNCORE_MHZ) -#define BIC_GROUP_IDLE (BIC_Busy | BIC_sysfs | BIC_CPU_c1 | BIC_CPU_c3 | BIC_CPU_c6 | BIC_CPU_c7 | BIC_GFX_rc6 | BIC_Pkgpc2 | BIC_Pkgpc3 | BIC_Pkgpc6 | BIC_Pkgpc7 | BIC_Pkgpc8 | BIC_Pkgpc9 | BIC_Pkgpc10 | BIC_CPU_LPI | BIC_SYS_LPI | BIC_Mod_c6 | BIC_Totl_c0 | BIC_Any_c0 | BIC_GFX_c0 | BIC_CPUGFX | BIC_SAM_mc6 | BIC_Diec6) +#define BIC_GROUP_HW_IDLE (BIC_Busy | BIC_CPU_c1 | BIC_CPU_c3 | BIC_CPU_c6 | BIC_CPU_c7 | BIC_GFX_rc6 | BIC_Pkgpc2 | BIC_Pkgpc3 | BIC_Pkgpc6 | BIC_Pkgpc7 | BIC_Pkgpc8 | BIC_Pkgpc9 | BIC_Pkgpc10 | BIC_CPU_LPI | BIC_SYS_LPI | BIC_Mod_c6 | BIC_Totl_c0 | BIC_Any_c0 | BIC_GFX_c0 | BIC_CPUGFX | BIC_SAM_mc6 | BIC_Diec6) +#define BIC_GROUP_SW_IDLE (BIC_Busy | BIC_cpuidle | BIC_pct_idle ) +#define BIC_GROUP_IDLE (BIC_GROUP_HW_IDLE | BIC_pct_idle) #define BIC_OTHER (BIC_IRQ | BIC_NMI | BIC_SMI | BIC_ThreadC | BIC_CoreTmp | BIC_IPC) -#define BIC_DISABLED_BY_DEFAULT (BIC_USEC | BIC_TOD | BIC_APIC | BIC_X2APIC) +#define BIC_DISABLED_BY_DEFAULT (BIC_USEC | BIC_TOD | BIC_APIC | BIC_X2APIC | BIC_cpuidle) unsigned long long bic_enabled = (0xFFFFFFFFFFFFFFFFULL & ~BIC_DISABLED_BY_DEFAULT); -unsigned long long bic_present = BIC_USEC | BIC_TOD | BIC_sysfs | BIC_APIC | BIC_X2APIC; +unsigned long long bic_present = BIC_USEC | BIC_TOD | BIC_cpuidle | BIC_pct_idle | BIC_APIC | BIC_X2APIC; #define DO_BIC(COUNTER_NAME) (bic_enabled & bic_present & COUNTER_NAME) #define DO_BIC_READ(COUNTER_NAME) (bic_present & COUNTER_NAME) @@ -2362,6 +2366,15 @@ unsigned long long bic_lookup(char *name_list, enum show_hide_mode mode) } else if (!strcmp(name_list, "idle")) { retval |= BIC_GROUP_IDLE; break; + } else if (!strcmp(name_list, "swidle")) { + retval |= BIC_GROUP_SW_IDLE; + break; + } else if (!strcmp(name_list, "sysfs")) { /* legacy compatibility */ + retval |= BIC_GROUP_SW_IDLE; + break; + } else if (!strcmp(name_list, "hwidle")) { + retval |= BIC_GROUP_HW_IDLE; + break; } else if (!strcmp(name_list, "frequency")) { retval |= BIC_GROUP_FREQUENCY; break; @@ -2372,6 +2385,7 @@ unsigned long long bic_lookup(char *name_list, enum show_hide_mode mode) } if (i == MAX_BIC) { + fprintf(stderr, "deferred %s\n", name_list); if (mode == SHOW_LIST) { deferred_add_names[deferred_add_index++] = name_list; if (deferred_add_index >= MAX_DEFERRED) { @@ -10269,6 +10283,9 @@ void probe_cpuidle_residency(void) int min_state = 1024, max_state = 0; char *sp; + if (!DO_BIC(BIC_pct_idle)) + return; + for (state = 10; state >= 0; --state) { sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name", base_cpu, state); @@ -10291,7 +10308,7 @@ void probe_cpuidle_residency(void) sprintf(path, "cpuidle/state%d/time", state); - if (!DO_BIC(BIC_sysfs) && !is_deferred_add(name_buf)) + if (!DO_BIC(BIC_pct_idle) && !is_deferred_add(name_buf)) continue; if (is_deferred_skip(name_buf)) @@ -10315,6 +10332,9 @@ void probe_cpuidle_counts(void) int min_state = 1024, max_state = 0; char *sp; + if (!DO_BIC(BIC_cpuidle)) + return; + for (state = 10; state >= 0; --state) { sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name", base_cpu, state); @@ -10327,7 +10347,7 @@ void probe_cpuidle_counts(void) remove_underbar(name_buf); - if (!DO_BIC(BIC_sysfs) && !is_deferred_add(name_buf)) + if (!DO_BIC(BIC_cpuidle) && !is_deferred_add(name_buf)) continue; if (is_deferred_skip(name_buf)) -- 2.51.0 From 03e00e373cab981ad808271b2650700cfa0fbda6 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sun, 6 Apr 2025 14:49:20 -0400 Subject: [PATCH 04/16] tools/power turbostat: v2025.05.06 Support up to 8192 processors Add cpuidle governor debug telemetry, disabled by default Update default output to exclude cpuidle invocation counts Bug fixes Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index ab184f95cdaf..1b9fdc1a7ee8 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -9594,7 +9594,7 @@ int get_and_dump_counters(void) void print_version() { - fprintf(outf, "turbostat version 2025.02.02 - Len Brown \n"); + fprintf(outf, "turbostat version 2025.04.06 - Len Brown \n"); } #define COMMAND_LINE_SIZE 2048 -- 2.51.0 From 0efdedb3358aa78102967f242379686f94315830 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 2 Apr 2025 21:21:57 +0100 Subject: [PATCH 05/16] tools/include: make uapi/linux/types.h usable from assembly MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The "real" linux/types.h UAPI header gracefully degrades to a NOOP when included from assembly code. Mirror this behaviour in the tools/ variant. Test for __ASSEMBLER__ over __ASSEMBLY__ as the former is provided by the toolchain automatically. Reported-by: Mark Brown Closes: https://lore.kernel.org/lkml/af553c62-ca2f-4956-932c-dd6e3a126f58@sirena.org.uk/ Fixes: c9fbaa879508 ("selftests: vDSO: parse_vdso: Use UAPI headers instead of libc headers") Signed-off-by: Thomas Weißschuh Link: https://patch.msgid.link/20250321-uapi-consistency-v1-1-439070118dc0@linutronix.de Signed-off-by: Mark Brown Reviewed-by: Mark Brown Signed-off-by: Linus Torvalds --- tools/include/uapi/linux/types.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/include/uapi/linux/types.h b/tools/include/uapi/linux/types.h index 91fa51a9c31d..85aa327245c6 100644 --- a/tools/include/uapi/linux/types.h +++ b/tools/include/uapi/linux/types.h @@ -4,6 +4,8 @@ #include +#ifndef __ASSEMBLER__ + /* copied from linux:include/uapi/linux/types.h */ #define __bitwise typedef __u16 __bitwise __le16; @@ -20,4 +22,5 @@ typedef __u32 __bitwise __wsum; #define __aligned_be64 __be64 __attribute__((aligned(8))) #define __aligned_le64 __le64 __attribute__((aligned(8))) +#endif /* __ASSEMBLER__ */ #endif /* _UAPI_LINUX_TYPES_H */ -- 2.51.0 From 0af2f6be1b4281385b618cb86ad946eded089ac8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 6 Apr 2025 13:11:33 -0700 Subject: [PATCH 06/16] Linux 6.15-rc1 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index e55726a71d95..38689a0c3605 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 -PATCHLEVEL = 14 +PATCHLEVEL = 15 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc1 NAME = Baby Opossum Posse # *DOCUMENTATION* -- 2.51.0 From 831a8ac72264426ccd0ee5d2b0d74491ea7d2bfb Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 8 Apr 2025 09:46:12 +0300 Subject: [PATCH 07/16] clk: rockchip: rk3588: Add PLL rate for 1500 MHz At least one RK3588 clock (CPLL) uses 1.5 GHz, so let's add that frequency to the PLL table. Signed-off-by: Alexander Shiyan Link: https://lore.kernel.org/r/20250408064612.41359-1-eagle.alexander923@gmail.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3588.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c index 4031733def4e..1694223f4f84 100644 --- a/drivers/clk/rockchip/clk-rk3588.c +++ b/drivers/clk/rockchip/clk-rk3588.c @@ -64,6 +64,7 @@ static struct rockchip_pll_rate_table rk3588_pll_rates[] = { RK3588_PLL_RATE(1560000000, 2, 260, 1, 0), RK3588_PLL_RATE(1536000000, 2, 256, 1, 0), RK3588_PLL_RATE(1512000000, 2, 252, 1, 0), + RK3588_PLL_RATE(1500000000, 2, 250, 1, 0), RK3588_PLL_RATE(1488000000, 2, 248, 1, 0), RK3588_PLL_RATE(1464000000, 2, 244, 1, 0), RK3588_PLL_RATE(1440000000, 2, 240, 1, 0), -- 2.51.0 From 646bfc52bbe184c0579060c3919e5d70885b0dcc Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Wed, 26 Mar 2025 11:35:56 +0000 Subject: [PATCH 08/16] clk: rockchip: Drop empty init callback for rk3588 PLL type Unlike PLLs in previous geneation of SoCs, PLLs in RK3588 type don't require any platform-specific initialization. Drop callback rockchip_rk3588_pll_init() that does nothing in fact to clean the driver up. Signed-off-by: Yao Zi Link: https://lore.kernel.org/r/20250326113556.21039-1-ziyao@disroot.org Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-pll.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 2c2abb3b4210..af74439a7457 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -1027,16 +1027,6 @@ static int rockchip_rk3588_pll_is_enabled(struct clk_hw *hw) return !(pllcon & RK3588_PLLCON1_PWRDOWN); } -static int rockchip_rk3588_pll_init(struct clk_hw *hw) -{ - struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); - - if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) - return 0; - - return 0; -} - static const struct clk_ops rockchip_rk3588_pll_clk_norate_ops = { .recalc_rate = rockchip_rk3588_pll_recalc_rate, .enable = rockchip_rk3588_pll_enable, @@ -1051,7 +1041,6 @@ static const struct clk_ops rockchip_rk3588_pll_clk_ops = { .enable = rockchip_rk3588_pll_enable, .disable = rockchip_rk3588_pll_disable, .is_enabled = rockchip_rk3588_pll_is_enabled, - .init = rockchip_rk3588_pll_init, }; /* -- 2.51.0 From 3cb09de48f652abd662b436b23f914d3eb66f1fd Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Tue, 18 Mar 2025 11:18:51 -0700 Subject: [PATCH 09/16] clk: rockchip: rk3568: Add PLL rate for 33.3MHz Add PLL rate for 33.3 MHz to allow BTT HDMI5 screen to run at its native mode of 800x480 Signed-off-by: Vasily Khoruzhick Link: https://lore.kernel.org/r/20250318181930.1178256-1-anarsoul@gmail.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3568.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c index 7d9279291e76..ed2fb08bd39d 100644 --- a/drivers/clk/rockchip/clk-rk3568.c +++ b/drivers/clk/rockchip/clk-rk3568.c @@ -89,6 +89,7 @@ static struct rockchip_pll_rate_table rk3568_pll_rates[] = { RK3036_PLL_RATE(96000000, 1, 96, 6, 4, 1, 0), RK3036_PLL_RATE(78750000, 4, 315, 6, 4, 1, 0), RK3036_PLL_RATE(74250000, 2, 99, 4, 4, 1, 0), + RK3036_PLL_RATE(33300000, 4, 111, 5, 4, 1, 0), { /* sentinel */ }, }; -- 2.51.0 From 4210f21c004a18aad11c55bdaf552e649a4fd286 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Fri, 2 May 2025 13:03:07 +0200 Subject: [PATCH 10/16] dt-bindings: clock: rk3576: add IOC gated clocks Certain clocks on the RK3576 are additionally essentially "gated" behind some bit toggles in the IOC GRF range. Downstream ungates these by adding a separate clock driver that maps over the GRF range and leaks their implementation of this into the DT. Instead, define some new clock IDs for these, so that consumers of these types of clocks can properly articulate which clock they're using, so that we can then add them to the clock driver for SoCs that need them. Acked-by: Krzysztof Kozlowski Signed-off-by: Nicolas Frattaroli Link: https://lore.kernel.org/r/20250502-rk3576-sai-v3-1-376cef19dd7c@collabora.com Signed-off-by: Heiko Stuebner --- include/dt-bindings/clock/rockchip,rk3576-cru.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/dt-bindings/clock/rockchip,rk3576-cru.h b/include/dt-bindings/clock/rockchip,rk3576-cru.h index f576e61bec70..ded5ce42e62a 100644 --- a/include/dt-bindings/clock/rockchip,rk3576-cru.h +++ b/include/dt-bindings/clock/rockchip,rk3576-cru.h @@ -594,4 +594,14 @@ #define SCMI_ARMCLK_B 11 #define SCMI_CLK_GPU 456 +/* IOC-controlled output clocks */ +#define CLK_SAI0_MCLKOUT_TO_IO 571 +#define CLK_SAI1_MCLKOUT_TO_IO 572 +#define CLK_SAI2_MCLKOUT_TO_IO 573 +#define CLK_SAI3_MCLKOUT_TO_IO 574 +#define CLK_SAI4_MCLKOUT_TO_IO 575 +#define CLK_SAI4_MCLKOUT_TO_IO 575 +#define CLK_FSPI0_TO_IO 576 +#define CLK_FSPI1_TO_IO 577 + #endif -- 2.51.0 From 70a114daf2077472e58b3cac23ba8998e35352f4 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Fri, 2 May 2025 13:03:08 +0200 Subject: [PATCH 11/16] clk: rockchip: introduce auxiliary GRFs The MUXGRF clock branch type depends on having access to some sort of GRF as a regmap to be registered. So far, we could easily get away with only ever having one GRF stowed away in the context. However, newer Rockchip SoCs, such as the RK3576, have several GRFs which are relevant for clock purposes. It already depends on the pmu0 GRF for MUXGRF reasons, but could get away with not refactoring this because it didn't need the sysgrf at all, so could overwrite the pointer in the clock provider to the pmu0 grf regmap handle. In preparation for needing to finally access more than one GRF per SoC, let's untangle this. Introduce an auxiliary GRF hashmap, and a GRF type enum. The hashmap is keyed by the enum, and clock branches now have a struct member to store the value of that enum, which defaults to the system GRF. The SoC-specific _clk_init function can then insert pointers to GRF regmaps into the hashmap based on the grf type. During clock branch registration, we then pick the right GRF for each branch from the hashmap if something other than the sys GRF is requested. The reason for doing it with this grf type indirection in the clock branches is so that we don't need to define the MUXGRF branches in a separate step, just to have a direct pointer to a regmap available already. Signed-off-by: Nicolas Frattaroli Link: https://lore.kernel.org/r/20250502-rk3576-sai-v3-2-376cef19dd7c@collabora.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3288.c | 2 +- drivers/clk/rockchip/clk-rk3328.c | 6 +++--- drivers/clk/rockchip/clk-rk3568.c | 2 +- drivers/clk/rockchip/clk-rk3576.c | 32 +++++++++++++++++++++---------- drivers/clk/rockchip/clk-rv1126.c | 2 +- drivers/clk/rockchip/clk.c | 17 +++++++++++++++- drivers/clk/rockchip/clk.h | 29 +++++++++++++++++++++++++++- 7 files changed, 72 insertions(+), 18 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 90d329216064..0a1e017df7c6 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -418,7 +418,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { RK3288_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3288_CLKGATE_CON(3), 11, GFLAGS), MUXGRF(0, "aclk_vcodec_pre", mux_aclk_vcodec_pre_p, CLK_SET_RATE_PARENT, - RK3288_GRF_SOC_CON(0), 7, 1, MFLAGS), + RK3288_GRF_SOC_CON(0), 7, 1, MFLAGS, grf_type_sys), GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vcodec_pre", 0, RK3288_CLKGATE_CON(9), 0, GFLAGS), diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c index cf60fcf2fa5c..cd5f65b6cdf5 100644 --- a/drivers/clk/rockchip/clk-rk3328.c +++ b/drivers/clk/rockchip/clk-rk3328.c @@ -677,9 +677,9 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { RK3328_CLKSEL_CON(27), 15, 1, MFLAGS, 8, 5, DFLAGS, RK3328_CLKGATE_CON(3), 5, GFLAGS), MUXGRF(SCLK_MAC2IO, "clk_mac2io", mux_mac2io_src_p, CLK_SET_RATE_NO_REPARENT, - RK3328_GRF_MAC_CON1, 10, 1, MFLAGS), + RK3328_GRF_MAC_CON1, 10, 1, MFLAGS, grf_type_sys), MUXGRF(SCLK_MAC2IO_EXT, "clk_mac2io_ext", mux_mac2io_ext_p, CLK_SET_RATE_NO_REPARENT, - RK3328_GRF_SOC_CON4, 14, 1, MFLAGS), + RK3328_GRF_SOC_CON4, 14, 1, MFLAGS, grf_type_sys), COMPOSITE(SCLK_MAC2PHY_SRC, "clk_mac2phy_src", mux_2plls_p, 0, RK3328_CLKSEL_CON(26), 7, 1, MFLAGS, 0, 5, DFLAGS, @@ -692,7 +692,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { RK3328_CLKSEL_CON(26), 8, 2, DFLAGS, RK3328_CLKGATE_CON(9), 2, GFLAGS), MUXGRF(SCLK_MAC2PHY, "clk_mac2phy", mux_mac2phy_src_p, CLK_SET_RATE_NO_REPARENT, - RK3328_GRF_MAC_CON2, 10, 1, MFLAGS), + RK3328_GRF_MAC_CON2, 10, 1, MFLAGS, grf_type_sys), FACTOR(0, "xin12m", "xin24m", 0, 1, 2), diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c index ed2fb08bd39d..d48ab9d6c064 100644 --- a/drivers/clk/rockchip/clk-rk3568.c +++ b/drivers/clk/rockchip/clk-rk3568.c @@ -591,7 +591,7 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = { RK3568_CLKSEL_CON(9), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3568_CLKGATE_CON(4), 0, GFLAGS), MUXGRF(CLK_DDR1X, "clk_ddr1x", clk_ddr1x_p, CLK_SET_RATE_PARENT, - RK3568_CLKSEL_CON(9), 15, 1, MFLAGS), + RK3568_CLKSEL_CON(9), 15, 1, MFLAGS, grf_type_sys), COMPOSITE_NOMUX(CLK_MSCH, "clk_msch", "clk_ddr1x", CLK_IGNORE_UNUSED, RK3568_CLKSEL_CON(10), 0, 2, DFLAGS, diff --git a/drivers/clk/rockchip/clk-rk3576.c b/drivers/clk/rockchip/clk-rk3576.c index 595e010341f7..fd3aa19725c4 100644 --- a/drivers/clk/rockchip/clk-rk3576.c +++ b/drivers/clk/rockchip/clk-rk3576.c @@ -1676,13 +1676,13 @@ static struct rockchip_clk_branch rk3576_clk_branches[] __initdata = { /* phy ref */ MUXGRF(CLK_PHY_REF_SRC, "clk_phy_ref_src", clk_phy_ref_src_p, 0, - RK3576_PMU0_GRF_OSC_CON6, 4, 1, MFLAGS), + RK3576_PMU0_GRF_OSC_CON6, 4, 1, MFLAGS, grf_type_pmu0), MUXGRF(CLK_USBPHY_REF_SRC, "clk_usbphy_ref_src", clk_usbphy_ref_src_p, 0, - RK3576_PMU0_GRF_OSC_CON6, 2, 1, MFLAGS), + RK3576_PMU0_GRF_OSC_CON6, 2, 1, MFLAGS, grf_type_pmu0), MUXGRF(CLK_CPLL_REF_SRC, "clk_cpll_ref_src", clk_cpll_ref_src_p, 0, - RK3576_PMU0_GRF_OSC_CON6, 1, 1, MFLAGS), + RK3576_PMU0_GRF_OSC_CON6, 1, 1, MFLAGS, grf_type_pmu0), MUXGRF(CLK_AUPLL_REF_SRC, "clk_aupll_ref_src", clk_aupll_ref_src_p, 0, - RK3576_PMU0_GRF_OSC_CON6, 0, 1, MFLAGS), + RK3576_PMU0_GRF_OSC_CON6, 0, 1, MFLAGS, grf_type_pmu0), /* secure ns */ COMPOSITE_NODIV(ACLK_SECURE_NS, "aclk_secure_ns", mux_350m_175m_116m_24m_p, CLK_IS_CRITICAL, @@ -1725,13 +1725,14 @@ static void __init rk3576_clk_init(struct device_node *np) struct rockchip_clk_provider *ctx; unsigned long clk_nr_clks; void __iomem *reg_base; - struct regmap *grf; + struct rockchip_aux_grf *pmu0_grf_e; + struct regmap *pmu0_grf; clk_nr_clks = rockchip_clk_find_max_clk_id(rk3576_clk_branches, ARRAY_SIZE(rk3576_clk_branches)) + 1; - grf = syscon_regmap_lookup_by_compatible("rockchip,rk3576-pmu0-grf"); - if (IS_ERR(grf)) { + pmu0_grf = syscon_regmap_lookup_by_compatible("rockchip,rk3576-pmu0-grf"); + if (IS_ERR(pmu0_grf)) { pr_err("%s: could not get PMU0 GRF syscon\n", __func__); return; } @@ -1745,11 +1746,16 @@ static void __init rk3576_clk_init(struct device_node *np) ctx = rockchip_clk_init(np, reg_base, clk_nr_clks); if (IS_ERR(ctx)) { pr_err("%s: rockchip clk init failed\n", __func__); - iounmap(reg_base); - return; + goto err_unmap; } - ctx->grf = grf; + pmu0_grf_e = kzalloc(sizeof(*pmu0_grf_e), GFP_KERNEL); + if (!pmu0_grf_e) + goto err_unmap; + + pmu0_grf_e->grf = pmu0_grf; + pmu0_grf_e->type = grf_type_pmu0; + hash_add(ctx->aux_grf_table, &pmu0_grf_e->node, grf_type_pmu0); rockchip_clk_register_plls(ctx, rk3576_pll_clks, ARRAY_SIZE(rk3576_pll_clks), @@ -1772,6 +1778,12 @@ static void __init rk3576_clk_init(struct device_node *np) rockchip_register_restart_notifier(ctx, RK3576_GLB_SRST_FST, NULL); rockchip_clk_of_add_provider(np, ctx); + + return; + +err_unmap: + iounmap(reg_base); + return; } CLK_OF_DECLARE(rk3576_cru, "rockchip,rk3576-cru", rk3576_clk_init); diff --git a/drivers/clk/rockchip/clk-rv1126.c b/drivers/clk/rockchip/clk-rv1126.c index fc19c5522490..15e7bfe84506 100644 --- a/drivers/clk/rockchip/clk-rv1126.c +++ b/drivers/clk/rockchip/clk-rv1126.c @@ -857,7 +857,7 @@ static struct rockchip_clk_branch rv1126_clk_branches[] __initdata = { RV1126_GMAC_CON, 5, 1, MFLAGS), MUXGRF(CLK_GMAC_SRC, "clk_gmac_src", mux_clk_gmac_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, - RV1126_GRF_IOFUNC_CON1, 12, 1, MFLAGS), + RV1126_GRF_IOFUNC_CON1, 12, 1, MFLAGS, grf_type_sys), GATE(CLK_GMAC_REF, "clk_gmac_ref", "clk_gmac_src", 0, RV1126_CLKGATE_CON(20), 7, GFLAGS), diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index cbf93ea119a9..0f029106d8aa 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -382,6 +382,8 @@ static struct rockchip_clk_provider *rockchip_clk_init_base( ctx->cru_node = np; spin_lock_init(&ctx->lock); + hash_init(ctx->aux_grf_table); + ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node, "rockchip,grf"); @@ -496,6 +498,8 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, struct rockchip_clk_branch *list, unsigned int nr_clk) { + struct regmap *grf = ctx->grf; + struct rockchip_aux_grf *agrf; struct clk *clk; unsigned int idx; unsigned long flags; @@ -504,6 +508,17 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, flags = list->flags; clk = NULL; + /* for GRF-dependent branches, choose the right grf first */ + if (list->branch_type == branch_muxgrf && + list->grf_type != grf_type_sys) { + hash_for_each_possible(ctx->aux_grf_table, agrf, node, list->grf_type) { + if (agrf->type == list->grf_type) { + grf = agrf->grf; + break; + } + } + } + /* catch simple muxes */ switch (list->branch_type) { case branch_mux: @@ -526,7 +541,7 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, case branch_muxgrf: clk = rockchip_clk_register_muxgrf(list->name, list->parent_names, list->num_parents, - flags, ctx->grf, list->muxdiv_offset, + flags, grf, list->muxdiv_offset, list->mux_shift, list->mux_width, list->mux_flags); break; diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index df2b2d706450..c136ac54e621 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -19,6 +19,7 @@ #include #include +#include struct clk; @@ -440,12 +441,35 @@ enum rockchip_pll_type { .k = _k, \ } +enum rockchip_grf_type { + grf_type_sys = 0, + grf_type_pmu0, + grf_type_pmu1, + grf_type_ioc, +}; + +/* ceil(sqrt(enums in rockchip_grf_type - 1)) */ +#define GRF_HASH_ORDER 2 + +/** + * struct rockchip_aux_grf - entry for the aux_grf_table hashtable + * @grf: pointer to the grf this entry references + * @type: what type of GRF this is + * @node: hlist node + */ +struct rockchip_aux_grf { + struct regmap *grf; + enum rockchip_grf_type type; + struct hlist_node node; +}; + /** * struct rockchip_clk_provider - information about clock provider * @reg_base: virtual address for the register base. * @clk_data: holds clock related data like clk* and number of clocks. * @cru_node: device-node of the clock-provider * @grf: regmap of the general-register-files syscon + * @aux_grf_table: hashtable of auxiliary GRF regmaps, indexed by grf_type * @lock: maintains exclusion between callbacks for a given clock-provider. */ struct rockchip_clk_provider { @@ -453,6 +477,7 @@ struct rockchip_clk_provider { struct clk_onecell_data clk_data; struct device_node *cru_node; struct regmap *grf; + DECLARE_HASHTABLE(aux_grf_table, GRF_HASH_ORDER); spinlock_t lock; }; @@ -660,6 +685,7 @@ struct rockchip_clk_branch { u8 gate_shift; u8 gate_flags; unsigned int linked_clk_id; + enum rockchip_grf_type grf_type; struct rockchip_clk_branch *child; }; @@ -900,7 +926,7 @@ struct rockchip_clk_branch { .mux_table = mt, \ } -#define MUXGRF(_id, cname, pnames, f, o, s, w, mf) \ +#define MUXGRF(_id, cname, pnames, f, o, s, w, mf, gt) \ { \ .id = _id, \ .branch_type = branch_muxgrf, \ @@ -913,6 +939,7 @@ struct rockchip_clk_branch { .mux_width = w, \ .mux_flags = mf, \ .gate_offset = -1, \ + .grf_type = gt, \ } #define DIV(_id, cname, pname, f, o, s, w, df) \ -- 2.51.0 From e277168cabe9fd99e647f5dad0bc846d5d6b0093 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Fri, 2 May 2025 13:03:09 +0200 Subject: [PATCH 12/16] clk: rockchip: introduce GRF gates Some rockchip SoCs, namely the RK3576, have bits in a General Register File (GRF) that act just like clock gates. The downstream vendor kernel simply maps over the already mapped GRF range with a generic clock gate driver. This solution isn't suitable for upstream, as a memory range will be in use by multiple drivers at the same time, and it leaks implementation details into the device tree. Instead, implement this with a new clock branch type in the Rockchip clock driver: GRF gates. Somewhat akin to MUXGRF, this clock branch depends on the type of GRF, but functions like a gate instead. Signed-off-by: Nicolas Frattaroli Link: https://lore.kernel.org/r/20250502-rk3576-sai-v3-3-376cef19dd7c@collabora.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk.c | 9 ++- drivers/clk/rockchip/clk.h | 20 ++++++ drivers/clk/rockchip/gate-grf.c | 105 ++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/rockchip/gate-grf.c diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index e8ece20aebfd..f0e0b2c6e876 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -14,6 +14,7 @@ clk-rockchip-y += clk-mmc-phase.o clk-rockchip-y += clk-muxgrf.o clk-rockchip-y += clk-ddr.o clk-rockchip-y += gate-link.o +clk-rockchip-y += gate-grf.o clk-rockchip-$(CONFIG_RESET_CONTROLLER) += softrst.o obj-$(CONFIG_CLK_PX30) += clk-px30.o diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 0f029106d8aa..34d96aa7cd51 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -509,7 +509,7 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, clk = NULL; /* for GRF-dependent branches, choose the right grf first */ - if (list->branch_type == branch_muxgrf && + if ((list->branch_type == branch_muxgrf || list->branch_type == branch_grf_gate) && list->grf_type != grf_type_sys) { hash_for_each_possible(ctx->aux_grf_table, agrf, node, list->grf_type) { if (agrf->type == list->grf_type) { @@ -588,6 +588,13 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, ctx->reg_base + list->gate_offset, list->gate_shift, list->gate_flags, &ctx->lock); break; + case branch_grf_gate: + flags |= CLK_SET_RATE_PARENT; + clk = rockchip_clk_register_gate_grf(list->name, + list->parent_names[0], flags, grf, + list->gate_offset, list->gate_shift, + list->gate_flags); + break; case branch_composite: clk = rockchip_clk_register_branch(list->name, list->parent_names, list->num_parents, diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index c136ac54e621..ebaed429a30d 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -647,6 +647,11 @@ struct clk *rockchip_clk_register_muxgrf(const char *name, int flags, struct regmap *grf, int reg, int shift, int width, int mux_flags); +struct clk *rockchip_clk_register_gate_grf(const char *name, + const char *parent_name, unsigned long flags, + struct regmap *regmap, unsigned int reg, + unsigned int shift, u8 gate_flags); + #define PNAME(x) static const char *const x[] __initconst enum rockchip_clk_branch_type { @@ -656,6 +661,7 @@ enum rockchip_clk_branch_type { branch_divider, branch_fraction_divider, branch_gate, + branch_grf_gate, branch_linked_gate, branch_mmc, branch_inverter, @@ -985,6 +991,20 @@ struct rockchip_clk_branch { .gate_flags = gf, \ } +#define GATE_GRF(_id, cname, pname, f, o, b, gf, gt) \ + { \ + .id = _id, \ + .branch_type = branch_grf_gate, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .gate_offset = o, \ + .gate_shift = b, \ + .gate_flags = gf, \ + .grf_type = gt, \ + } + #define GATE_LINK(_id, cname, pname, linkedclk, f, o, b, gf) \ { \ .id = _id, \ diff --git a/drivers/clk/rockchip/gate-grf.c b/drivers/clk/rockchip/gate-grf.c new file mode 100644 index 000000000000..8122f471f391 --- /dev/null +++ b/drivers/clk/rockchip/gate-grf.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2025 Collabora Ltd. + * Author: Nicolas Frattaroli + * + * Certain clocks on Rockchip are "gated" behind an additional register bit + * write in a GRF register, such as the SAI MCLKs on RK3576. This code + * implements a clock driver for these types of gates, based on regmaps. + */ + +#include +#include +#include +#include +#include "clk.h" + +struct rockchip_gate_grf { + struct clk_hw hw; + struct regmap *regmap; + unsigned int reg; + unsigned int shift; + u8 flags; +}; + +#define to_gate_grf(_hw) container_of(_hw, struct rockchip_gate_grf, hw) + +static int rockchip_gate_grf_enable(struct clk_hw *hw) +{ + struct rockchip_gate_grf *gate = to_gate_grf(hw); + u32 val = !(gate->flags & CLK_GATE_SET_TO_DISABLE) ? BIT(gate->shift) : 0; + u32 hiword = ((gate->flags & CLK_GATE_HIWORD_MASK) ? 1 : 0) << (gate->shift + 16); + int ret; + + ret = regmap_update_bits(gate->regmap, gate->reg, + hiword | BIT(gate->shift), hiword | val); + + return ret; +} + +static void rockchip_gate_grf_disable(struct clk_hw *hw) +{ + struct rockchip_gate_grf *gate = to_gate_grf(hw); + u32 val = !(gate->flags & CLK_GATE_SET_TO_DISABLE) ? 0 : BIT(gate->shift); + u32 hiword = ((gate->flags & CLK_GATE_HIWORD_MASK) ? 1 : 0) << (gate->shift + 16); + + regmap_update_bits(gate->regmap, gate->reg, + hiword | BIT(gate->shift), hiword | val); +} + +static int rockchip_gate_grf_is_enabled(struct clk_hw *hw) +{ + struct rockchip_gate_grf *gate = to_gate_grf(hw); + bool invert = !!(gate->flags & CLK_GATE_SET_TO_DISABLE); + int ret; + + ret = regmap_test_bits(gate->regmap, gate->reg, BIT(gate->shift)); + if (ret < 0) + ret = 0; + + return invert ? 1 - ret : ret; + +} + +static const struct clk_ops rockchip_gate_grf_ops = { + .enable = rockchip_gate_grf_enable, + .disable = rockchip_gate_grf_disable, + .is_enabled = rockchip_gate_grf_is_enabled, +}; + +struct clk *rockchip_clk_register_gate_grf(const char *name, + const char *parent_name, unsigned long flags, + struct regmap *regmap, unsigned int reg, unsigned int shift, + u8 gate_flags) +{ + struct rockchip_gate_grf *gate; + struct clk_init_data init; + struct clk *clk; + + if (IS_ERR(regmap)) { + pr_err("%s: regmap not available\n", __func__); + return ERR_PTR(-EOPNOTSUPP); + } + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.flags = flags; + init.num_parents = parent_name ? 1 : 0; + init.parent_names = parent_name ? &parent_name : NULL; + init.ops = &rockchip_gate_grf_ops; + + gate->hw.init = &init; + gate->regmap = regmap; + gate->reg = reg; + gate->shift = shift; + gate->flags = gate_flags; + + clk = clk_register(NULL, &gate->hw); + if (IS_ERR(clk)) + kfree(gate); + + return clk; +} -- 2.51.0 From 9199ec29f0977efee223791c9ee3eb402d23f8ba Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Fri, 2 May 2025 13:03:10 +0200 Subject: [PATCH 13/16] clk: rockchip: add GATE_GRFs for SAI MCLKOUT to rk3576 The Rockchip RK3576 gates the SAI MCLKOUT clocks behind some IOC GRF writes. Add these clock branches, and add the IOC GRF to the auxiliary GRF hashtable. Signed-off-by: Nicolas Frattaroli Link: https://lore.kernel.org/r/20250502-rk3576-sai-v3-4-376cef19dd7c@collabora.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3576.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/clk/rockchip/clk-rk3576.c b/drivers/clk/rockchip/clk-rk3576.c index fd3aa19725c4..71e77013f726 100644 --- a/drivers/clk/rockchip/clk-rk3576.c +++ b/drivers/clk/rockchip/clk-rk3576.c @@ -15,6 +15,7 @@ #define RK3576_GRF_SOC_STATUS0 0x600 #define RK3576_PMU0_GRF_OSC_CON6 0x18 +#define RK3576_VCCIO_IOC_MISC_CON0 0x6400 enum rk3576_plls { bpll, lpll, vpll, aupll, cpll, gpll, ppll, @@ -1479,6 +1480,14 @@ static struct rockchip_clk_branch rk3576_clk_branches[] __initdata = { RK3576_CLKGATE_CON(10), 0, GFLAGS), GATE(CLK_SAI0_MCLKOUT, "clk_sai0_mclkout", "mclk_sai0_8ch", 0, RK3576_CLKGATE_CON(10), 1, GFLAGS), + GATE_GRF(CLK_SAI0_MCLKOUT_TO_IO, "mclk_sai0_to_io", "clk_sai0_mclkout", + 0, RK3576_VCCIO_IOC_MISC_CON0, 0, GFLAGS, grf_type_ioc), + GATE_GRF(CLK_SAI1_MCLKOUT_TO_IO, "mclk_sai1_to_io", "clk_sai1_mclkout", + 0, RK3576_VCCIO_IOC_MISC_CON0, 1, GFLAGS, grf_type_ioc), + GATE_GRF(CLK_SAI2_MCLKOUT_TO_IO, "mclk_sai2_to_io", "clk_sai2_mclkout", + 0, RK3576_VCCIO_IOC_MISC_CON0, 2, GFLAGS, grf_type_ioc), + GATE_GRF(CLK_SAI3_MCLKOUT_TO_IO, "mclk_sai3_to_io", "clk_sai3_mclkout", + 0, RK3576_VCCIO_IOC_MISC_CON0, 3, GFLAGS, grf_type_ioc), /* sdgmac */ COMPOSITE_NODIV(HCLK_SDGMAC_ROOT, "hclk_sdgmac_root", mux_200m_100m_50m_24m_p, 0, @@ -1725,7 +1734,9 @@ static void __init rk3576_clk_init(struct device_node *np) struct rockchip_clk_provider *ctx; unsigned long clk_nr_clks; void __iomem *reg_base; + struct rockchip_aux_grf *ioc_grf_e; struct rockchip_aux_grf *pmu0_grf_e; + struct regmap *ioc_grf; struct regmap *pmu0_grf; clk_nr_clks = rockchip_clk_find_max_clk_id(rk3576_clk_branches, @@ -1737,6 +1748,12 @@ static void __init rk3576_clk_init(struct device_node *np) return; } + ioc_grf = syscon_regmap_lookup_by_compatible("rockchip,rk3576-ioc-grf"); + if (IS_ERR(ioc_grf)) { + pr_err("%s: could not get IOC GRF syscon\n", __func__); + return; + } + reg_base = of_iomap(np, 0); if (!reg_base) { pr_err("%s: could not map cru region\n", __func__); @@ -1757,6 +1774,14 @@ static void __init rk3576_clk_init(struct device_node *np) pmu0_grf_e->type = grf_type_pmu0; hash_add(ctx->aux_grf_table, &pmu0_grf_e->node, grf_type_pmu0); + ioc_grf_e = kzalloc(sizeof(*ioc_grf_e), GFP_KERNEL); + if (!ioc_grf_e) + goto err_free_pmu0; + + ioc_grf_e->grf = ioc_grf; + ioc_grf_e->type = grf_type_ioc; + hash_add(ctx->aux_grf_table, &ioc_grf_e->node, grf_type_ioc); + rockchip_clk_register_plls(ctx, rk3576_pll_clks, ARRAY_SIZE(rk3576_pll_clks), RK3576_GRF_SOC_STATUS0); @@ -1781,6 +1806,8 @@ static void __init rk3576_clk_init(struct device_node *np) return; +err_free_pmu0: + kfree(pmu0_grf_e); err_unmap: iounmap(reg_base); return; -- 2.51.0 From 8a023e86f3d999007f2687952afe78ef34a6aa91 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Tue, 6 May 2025 09:22:02 +0000 Subject: [PATCH 14/16] dt-bindings: clock: Add GRF clock definition for RK3528 These clocks are for SD/SDIO tuning purpose and come with registers in GRF syscon. Signed-off-by: Yao Zi Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250506092206.46143-2-ziyao@disroot.org Signed-off-by: Heiko Stuebner --- include/dt-bindings/clock/rockchip,rk3528-cru.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/dt-bindings/clock/rockchip,rk3528-cru.h b/include/dt-bindings/clock/rockchip,rk3528-cru.h index 55a448f5ed6d..0245a53fc334 100644 --- a/include/dt-bindings/clock/rockchip,rk3528-cru.h +++ b/include/dt-bindings/clock/rockchip,rk3528-cru.h @@ -414,6 +414,12 @@ #define MCLK_I2S2_2CH_SAI_SRC_PRE 402 #define MCLK_I2S3_8CH_SAI_SRC_PRE 403 #define MCLK_SDPDIF_SRC_PRE 404 +#define SCLK_SDMMC_DRV 405 +#define SCLK_SDMMC_SAMPLE 406 +#define SCLK_SDIO0_DRV 407 +#define SCLK_SDIO0_SAMPLE 408 +#define SCLK_SDIO1_DRV 409 +#define SCLK_SDIO1_SAMPLE 410 /* scmi-clocks indices */ #define SCMI_PCLK_KEYREADER 0 -- 2.51.0 From 621ba4d9f6db560a7406fd732af1b495ff5aa103 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Tue, 6 May 2025 09:22:03 +0000 Subject: [PATCH 15/16] clk: rockchip: Support MMC clocks in GRF region Registers of MMC drive/sample clocks in Rockchip RV1106 and RK3528 locate in GRF regions. Adjust MMC clock code to support register operations through regmap. Signed-off-by: Yao Zi Link: https://lore.kernel.org/r/20250506092206.46143-3-ziyao@disroot.org Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-mmc-phase.c | 24 ++++++++++++++++++++---- drivers/clk/rockchip/clk.c | 16 ++++++++++++++-- drivers/clk/rockchip/clk.h | 17 ++++++++++++++++- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index 91012078681b..b3ed8e7523e5 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -9,11 +9,14 @@ #include #include #include +#include #include "clk.h" struct rockchip_mmc_clock { struct clk_hw hw; void __iomem *reg; + struct regmap *grf; + int grf_reg; int shift; int cached_phase; struct notifier_block clk_rate_change_nb; @@ -54,7 +57,12 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw) if (!rate) return 0; - raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift); + if (mmc_clock->grf) + regmap_read(mmc_clock->grf, mmc_clock->grf_reg, &raw_value); + else + raw_value = readl(mmc_clock->reg); + + raw_value >>= mmc_clock->shift; degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; @@ -134,8 +142,12 @@ static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees) raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; raw_value |= nineties; - writel(HIWORD_UPDATE(raw_value, 0x07ff, mmc_clock->shift), - mmc_clock->reg); + raw_value = HIWORD_UPDATE(raw_value, 0x07ff, mmc_clock->shift); + + if (mmc_clock->grf) + regmap_write(mmc_clock->grf, mmc_clock->grf_reg, raw_value); + else + writel(raw_value, mmc_clock->reg); pr_debug("%s->set_phase(%d) delay_nums=%u reg[0x%p]=0x%03x actual_degrees=%d\n", clk_hw_get_name(hw), degrees, delay_num, @@ -189,7 +201,9 @@ static int rockchip_mmc_clk_rate_notify(struct notifier_block *nb, struct clk *rockchip_clk_register_mmc(const char *name, const char *const *parent_names, u8 num_parents, - void __iomem *reg, int shift) + void __iomem *reg, + struct regmap *grf, int grf_reg, + int shift) { struct clk_init_data init; struct rockchip_mmc_clock *mmc_clock; @@ -208,6 +222,8 @@ struct clk *rockchip_clk_register_mmc(const char *name, mmc_clock->hw.init = &init; mmc_clock->reg = reg; + mmc_clock->grf = grf; + mmc_clock->grf_reg = grf_reg; mmc_clock->shift = shift; clk = clk_register(NULL, &mmc_clock->hw); diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 34d96aa7cd51..43d7ed5c3418 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -509,8 +509,10 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, clk = NULL; /* for GRF-dependent branches, choose the right grf first */ - if ((list->branch_type == branch_muxgrf || list->branch_type == branch_grf_gate) && - list->grf_type != grf_type_sys) { + if ((list->branch_type == branch_muxgrf || + list->branch_type == branch_grf_gate || + list->branch_type == branch_grf_mmc) && + list->grf_type != grf_type_sys) { hash_for_each_possible(ctx->aux_grf_table, agrf, node, list->grf_type) { if (agrf->type == list->grf_type) { grf = agrf->grf; @@ -612,6 +614,16 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, list->name, list->parent_names, list->num_parents, ctx->reg_base + list->muxdiv_offset, + NULL, 0, + list->div_shift + ); + break; + case branch_grf_mmc: + clk = rockchip_clk_register_mmc( + list->name, + list->parent_names, list->num_parents, + 0, + grf, list->muxdiv_offset, list->div_shift ); break; diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index ebaed429a30d..d411de7a6f4a 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -619,7 +619,9 @@ struct clk *rockchip_clk_register_cpuclk(const char *name, struct clk *rockchip_clk_register_mmc(const char *name, const char *const *parent_names, u8 num_parents, - void __iomem *reg, int shift); + void __iomem *reg, + struct regmap *grf, int grf_reg, + int shift); /* * DDRCLK flags, including method of setting the rate @@ -664,6 +666,7 @@ enum rockchip_clk_branch_type { branch_grf_gate, branch_linked_gate, branch_mmc, + branch_grf_mmc, branch_inverter, branch_factor, branch_ddrclk, @@ -1030,6 +1033,18 @@ struct rockchip_clk_branch { .div_shift = shift, \ } +#define MMC_GRF(_id, cname, pname, offset, shift, grftype) \ + { \ + .id = _id, \ + .branch_type = branch_grf_mmc, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .muxdiv_offset = offset, \ + .div_shift = shift, \ + .grf_type = grftype, \ + } + #define INVERTER(_id, cname, pname, io, is, if) \ { \ .id = _id, \ -- 2.51.0 From 306d2f5ddaa765f04ffb54fc9437a6318f904b53 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Tue, 6 May 2025 09:22:04 +0000 Subject: [PATCH 16/16] clk: rockchip: rk3528: Add SD/SDIO tuning clocks in GRF region These clocks locate in VO and VPU GRF, serving for SD/SDIO controller tuning purpose. Add their definitions and register them in driver if corresponding GRF is available. GRFs are looked up by compatible to simplify devicetree binding. Signed-off-by: Yao Zi Link: https://lore.kernel.org/r/20250506092206.46143-4-ziyao@disroot.org Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3528.c | 82 ++++++++++++++++++++++++++++--- drivers/clk/rockchip/clk.h | 5 ++ 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3528.c b/drivers/clk/rockchip/clk-rk3528.c index b8b577b902a0..f5f10493abfb 100644 --- a/drivers/clk/rockchip/clk-rk3528.c +++ b/drivers/clk/rockchip/clk-rk3528.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include @@ -1061,23 +1063,65 @@ static struct rockchip_clk_branch rk3528_clk_branches[] __initdata = { 0, 1, 1), }; +static struct rockchip_clk_branch rk3528_vo_clk_branches[] __initdata = { + MMC_GRF(SCLK_SDMMC_DRV, "sdmmc_drv", "cclk_src_sdmmc0", + RK3528_SDMMC_CON(0), 1, grf_type_vo), + MMC_GRF(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "cclk_src_sdmmc0", + RK3528_SDMMC_CON(1), 1, grf_type_vo), +}; + +static struct rockchip_clk_branch rk3528_vpu_clk_branches[] __initdata = { + MMC_GRF(SCLK_SDIO0_DRV, "sdio0_drv", "cclk_src_sdio0", + RK3528_SDIO0_CON(0), 1, grf_type_vpu), + MMC_GRF(SCLK_SDIO0_SAMPLE, "sdio0_sample", "cclk_src_sdio0", + RK3528_SDIO0_CON(1), 1, grf_type_vpu), + MMC_GRF(SCLK_SDIO1_DRV, "sdio1_drv", "cclk_src_sdio1", + RK3528_SDIO1_CON(0), 1, grf_type_vpu), + MMC_GRF(SCLK_SDIO1_SAMPLE, "sdio1_sample", "cclk_src_sdio1", + RK3528_SDIO1_CON(1), 1, grf_type_vpu), +}; + static int __init clk_rk3528_probe(struct platform_device *pdev) { - struct rockchip_clk_provider *ctx; + unsigned long nr_vpu_branches = ARRAY_SIZE(rk3528_vpu_clk_branches); + unsigned long nr_vo_branches = ARRAY_SIZE(rk3528_vo_clk_branches); + unsigned long nr_branches = ARRAY_SIZE(rk3528_clk_branches); + unsigned long nr_clks, nr_vo_clks, nr_vpu_clks; + struct rockchip_aux_grf *vo_grf_e, *vpu_grf_e; + struct regmap *vo_grf, *vpu_grf; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - unsigned long nr_branches = ARRAY_SIZE(rk3528_clk_branches); - unsigned long nr_clks; + struct rockchip_clk_provider *ctx; void __iomem *reg_base; - nr_clks = rockchip_clk_find_max_clk_id(rk3528_clk_branches, - nr_branches) + 1; - reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg_base)) return dev_err_probe(dev, PTR_ERR(reg_base), "could not map cru region"); + nr_clks = rockchip_clk_find_max_clk_id(rk3528_clk_branches, + nr_branches) + 1; + + vo_grf = syscon_regmap_lookup_by_compatible("rockchip,rk3528-vo-grf"); + if (!IS_ERR(vo_grf)) { + nr_vo_clks = rockchip_clk_find_max_clk_id(rk3528_vo_clk_branches, + nr_vo_branches) + 1; + nr_clks = max(nr_clks, nr_vo_clks); + } else if (PTR_ERR(vo_grf) != -ENODEV) { + return dev_err_probe(dev, PTR_ERR(vo_grf), + "failed to look up VO GRF\n"); + } + + vpu_grf = syscon_regmap_lookup_by_compatible("rockchip,rk3528-vpu-grf"); + if (!IS_ERR(vpu_grf)) { + nr_vpu_clks = rockchip_clk_find_max_clk_id(rk3528_vpu_clk_branches, + nr_vpu_branches) + 1; + nr_clks = max(nr_clks, nr_vpu_clks); + } else if (PTR_ERR(vpu_grf) != -ENODEV) { + return dev_err_probe(dev, PTR_ERR(vpu_grf), + "failed to look up VPU GRF\n"); + } + ctx = rockchip_clk_init(np, reg_base, nr_clks); if (IS_ERR(ctx)) return dev_err_probe(dev, PTR_ERR(ctx), @@ -1092,6 +1136,32 @@ static int __init clk_rk3528_probe(struct platform_device *pdev) ARRAY_SIZE(rk3528_cpuclk_rates)); rockchip_clk_register_branches(ctx, rk3528_clk_branches, nr_branches); + if (!IS_ERR(vo_grf)) { + vo_grf_e = devm_kzalloc(dev, sizeof(*vo_grf_e), GFP_KERNEL); + if (!vo_grf_e) + return -ENOMEM; + + vo_grf_e->grf = vo_grf; + vo_grf_e->type = grf_type_vo; + hash_add(ctx->aux_grf_table, &vo_grf_e->node, grf_type_vo); + + rockchip_clk_register_branches(ctx, rk3528_vo_clk_branches, + nr_vo_branches); + } + + if (!IS_ERR(vpu_grf)) { + vpu_grf_e = devm_kzalloc(dev, sizeof(*vpu_grf_e), GFP_KERNEL); + if (!vpu_grf_e) + return -ENOMEM; + + vpu_grf_e->grf = vpu_grf; + vpu_grf_e->type = grf_type_vpu; + hash_add(ctx->aux_grf_table, &vpu_grf_e->node, grf_type_vpu); + + rockchip_clk_register_branches(ctx, rk3528_vpu_clk_branches, + nr_vpu_branches); + } + rk3528_rst_init(np, reg_base); rockchip_register_restart_notifier(ctx, RK3528_GLB_SRST_FST, NULL); diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index d411de7a6f4a..10be168f49e3 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -218,6 +218,9 @@ struct clk; #define RK3528_CLKSEL_CON(x) ((x) * 0x4 + 0x300) #define RK3528_CLKGATE_CON(x) ((x) * 0x4 + 0x800) #define RK3528_SOFTRST_CON(x) ((x) * 0x4 + 0xa00) +#define RK3528_SDMMC_CON(x) ((x) * 0x4 + 0x24) +#define RK3528_SDIO0_CON(x) ((x) * 0x4 + 0x4) +#define RK3528_SDIO1_CON(x) ((x) * 0x4 + 0xc) #define RK3528_PMU_CLKSEL_CON(x) ((x) * 0x4 + 0x300 + RK3528_PMU_CRU_BASE) #define RK3528_PMU_CLKGATE_CON(x) ((x) * 0x4 + 0x800 + RK3528_PMU_CRU_BASE) #define RK3528_PCIE_CLKSEL_CON(x) ((x) * 0x4 + 0x300 + RK3528_PCIE_CRU_BASE) @@ -446,6 +449,8 @@ enum rockchip_grf_type { grf_type_pmu0, grf_type_pmu1, grf_type_ioc, + grf_type_vo, + grf_type_vpu, }; /* ceil(sqrt(enums in rockchip_grf_type - 1)) */ -- 2.51.0