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 bf657e234ac12923b579b13d8b9f1b5ca0519697 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 1 Apr 2025 15:35:20 +0100 Subject: [PATCH 07/16] memory: renesas-rpc-if: Fix RPCIF_DRENR_CDB macro error Fix the below macro error found while moving the reg definitions to renesas-rpc-if-regs.h in the later patch. ERROR: Macros with complex values should be enclosed in parentheses Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250401143537.224047-3-biju.das.jz@bp.renesas.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/renesas-rpc-if.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 15b4706aafee..c29bec8327e8 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -56,7 +56,7 @@ #define RPCIF_DROPR 0x0018 /* R/W */ #define RPCIF_DRENR 0x001C /* R/W */ -#define RPCIF_DRENR_CDB(o) (u32)((((o) & 0x3) << 30)) +#define RPCIF_DRENR_CDB(o) (((u32)((o) & 0x3)) << 30) #define RPCIF_DRENR_OCDB(o) (((o) & 0x3) << 28) #define RPCIF_DRENR_ADB(o) (((o) & 0x3) << 24) #define RPCIF_DRENR_OPDB(o) (((o) & 0x3) << 20) -- 2.51.0 From 74c35c84f2ba942e7a7744658a8257d0b3188ac2 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 1 Apr 2025 15:35:23 +0100 Subject: [PATCH 08/16] memory: renesas-rpc-if: Move rpcif_info definitions near to the user Move rpcif_info definitions near to the user. Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250401143537.224047-6-biju.das.jz@bp.renesas.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/renesas-rpc-if.c | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index c29bec8327e8..4a59bf27eace 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -191,26 +191,6 @@ struct rpcif_priv { u32 ddr; /* DRDRENR or SMDRENR */ }; -static const struct rpcif_info rpcif_info_r8a7796 = { - .type = RPCIF_RCAR_GEN3, - .strtim = 6, -}; - -static const struct rpcif_info rpcif_info_gen3 = { - .type = RPCIF_RCAR_GEN3, - .strtim = 7, -}; - -static const struct rpcif_info rpcif_info_rz_g2l = { - .type = RPCIF_RZ_G2L, - .strtim = 7, -}; - -static const struct rpcif_info rpcif_info_gen4 = { - .type = RPCIF_RCAR_GEN4, - .strtim = 15, -}; - /* * Custom accessor functions to ensure SM[RW]DR[01] are always accessed with * proper width. Requires rpcif_priv.xfer_size to be correctly set before! @@ -784,6 +764,26 @@ static void rpcif_remove(struct platform_device *pdev) platform_device_unregister(rpc->vdev); } +static const struct rpcif_info rpcif_info_r8a7796 = { + .type = RPCIF_RCAR_GEN3, + .strtim = 6, +}; + +static const struct rpcif_info rpcif_info_gen3 = { + .type = RPCIF_RCAR_GEN3, + .strtim = 7, +}; + +static const struct rpcif_info rpcif_info_rz_g2l = { + .type = RPCIF_RZ_G2L, + .strtim = 7, +}; + +static const struct rpcif_info rpcif_info_gen4 = { + .type = RPCIF_RCAR_GEN4, + .strtim = 15, +}; + static const struct of_device_id rpcif_of_match[] = { { .compatible = "renesas,r8a7796-rpc-if", .data = &rpcif_info_r8a7796 }, { .compatible = "renesas,rcar-gen3-rpc-if", .data = &rpcif_info_gen3 }, -- 2.51.0 From b2d25905366b4e6791f60e6bc76a636d1b88e6f8 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 24 Apr 2025 09:59:49 +0100 Subject: [PATCH 09/16] dt-bindings: memory: Document RZ/G3E support Document support for the Expanded Serial Peripheral Interface (xSPI) Controller in the Renesas RZ/G3E (R9A09G047) SoC. Reviewed-by: Rob Herring (Arm) Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250424090000.136804-2-biju.das.jz@bp.renesas.com Signed-off-by: Krzysztof Kozlowski --- .../renesas,rzg3e-xspi.yaml | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 Documentation/devicetree/bindings/memory-controllers/renesas,rzg3e-xspi.yaml diff --git a/Documentation/devicetree/bindings/memory-controllers/renesas,rzg3e-xspi.yaml b/Documentation/devicetree/bindings/memory-controllers/renesas,rzg3e-xspi.yaml new file mode 100644 index 000000000000..2bfe63ec62dc --- /dev/null +++ b/Documentation/devicetree/bindings/memory-controllers/renesas,rzg3e-xspi.yaml @@ -0,0 +1,135 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/memory-controllers/renesas,rzg3e-xspi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas Expanded Serial Peripheral Interface (xSPI) + +maintainers: + - Biju Das + +description: | + Renesas xSPI allows a SPI flash connected to the SoC to be accessed via + the memory-mapping or the manual command mode. + + The flash chip itself should be represented by a subnode of the XSPI node. + The flash interface is selected based on the "compatible" property of this + subnode: + - "jedec,spi-nor"; + +allOf: + - $ref: /schemas/spi/spi-controller.yaml# + +properties: + compatible: + const: renesas,r9a09g047-xspi # RZ/G3E + + reg: + items: + - description: xSPI registers + - description: direct mapping area + + reg-names: + items: + - const: regs + - const: dirmap + + interrupts: + items: + - description: Interrupt pulse signal by factors excluding errors + - description: Interrupt pulse signal by error factors + + interrupt-names: + items: + - const: pulse + - const: err_pulse + + clocks: + items: + - description: AHB clock + - description: AXI clock + - description: SPI clock + - description: Double speed SPI clock + + clock-names: + items: + - const: ahb + - const: axi + - const: spi + - const: spix2 + + power-domains: + maxItems: 1 + + resets: + items: + - description: Hardware reset + - description: AXI reset + + reset-names: + items: + - const: hresetn + - const: aresetn + + renesas,xspi-cs-addr-sys: + $ref: /schemas/types.yaml#/definitions/phandle + description: | + Phandle to the system controller (sys) that allows to configure + xSPI CS0 and CS1 addresses. + +patternProperties: + "flash@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + contains: + const: jedec,spi-nor + +required: + - compatible + - reg + - reg-names + - interrupts + - interrupt-names + - clocks + - clock-names + - power-domains + - resets + - reset-names + - '#address-cells' + - '#size-cells' + +unevaluatedProperties: false + +examples: + - | + #include + #include + + spi@11030000 { + compatible = "renesas,r9a09g047-xspi"; + reg = <0x11030000 0x10000>, <0x20000000 0x10000000>; + reg-names = "regs", "dirmap"; + interrupts = , + ; + interrupt-names = "pulse", "err_pulse"; + clocks = <&cpg CPG_MOD 0x9f>, <&cpg CPG_MOD 0xa0>, + <&cpg CPG_CORE 9>, <&cpg CPG_MOD 0xa1>; + clock-names = "ahb", "axi", "spi", "spix2"; + power-domains = <&cpg>; + resets = <&cpg 0xa3>, <&cpg 0xa4>; + reset-names = "hresetn", "aresetn"; + #address-cells = <1>; + #size-cells = <0>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <40000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + }; + }; -- 2.51.0 From 228e72bf943687d04bf06a98722ab6cf9d4b8ba6 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 24 Apr 2025 09:59:50 +0100 Subject: [PATCH 10/16] memory: renesas-rpc-if: Move rpc-if reg definitions Move rpc-if reg definitions to a header file for the preparation of adding support for RZ/G3E XSPI that has different register definitions. Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250424090000.136804-3-biju.das.jz@bp.renesas.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/renesas-rpc-if-regs.h | 147 +++++++++++++++++++++++++++ drivers/memory/renesas-rpc-if.c | 134 +----------------------- 2 files changed, 148 insertions(+), 133 deletions(-) create mode 100644 drivers/memory/renesas-rpc-if-regs.h diff --git a/drivers/memory/renesas-rpc-if-regs.h b/drivers/memory/renesas-rpc-if-regs.h new file mode 100644 index 000000000000..e6b33f7c40a8 --- /dev/null +++ b/drivers/memory/renesas-rpc-if-regs.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * R-Car RPC Interface Registers Definitions + * + * Copyright (C) 2025 Renesas Electronics Corporation + */ + +#ifndef __RENESAS_RPC_IF_REGS_H__ +#define __RENESAS_RPC_IF_REGS_H__ + +#include + +#define RPCIF_CMNCR 0x0000 /* R/W */ +#define RPCIF_CMNCR_MD BIT(31) +#define RPCIF_CMNCR_MOIIO3(val) (((val) & 0x3) << 22) +#define RPCIF_CMNCR_MOIIO2(val) (((val) & 0x3) << 20) +#define RPCIF_CMNCR_MOIIO1(val) (((val) & 0x3) << 18) +#define RPCIF_CMNCR_MOIIO0(val) (((val) & 0x3) << 16) +#define RPCIF_CMNCR_MOIIO(val) (RPCIF_CMNCR_MOIIO0(val) | RPCIF_CMNCR_MOIIO1(val) | \ + RPCIF_CMNCR_MOIIO2(val) | RPCIF_CMNCR_MOIIO3(val)) +#define RPCIF_CMNCR_IO3FV(val) (((val) & 0x3) << 14) /* documented for RZ/G2L */ +#define RPCIF_CMNCR_IO2FV(val) (((val) & 0x3) << 12) /* documented for RZ/G2L */ +#define RPCIF_CMNCR_IO0FV(val) (((val) & 0x3) << 8) +#define RPCIF_CMNCR_IOFV(val) (RPCIF_CMNCR_IO0FV(val) | RPCIF_CMNCR_IO2FV(val) | \ + RPCIF_CMNCR_IO3FV(val)) +#define RPCIF_CMNCR_BSZ(val) (((val) & 0x3) << 0) + +#define RPCIF_SSLDR 0x0004 /* R/W */ +#define RPCIF_SSLDR_SPNDL(d) (((d) & 0x7) << 16) +#define RPCIF_SSLDR_SLNDL(d) (((d) & 0x7) << 8) +#define RPCIF_SSLDR_SCKDL(d) (((d) & 0x7) << 0) + +#define RPCIF_DRCR 0x000C /* R/W */ +#define RPCIF_DRCR_SSLN BIT(24) +#define RPCIF_DRCR_RBURST(v) ((((v) - 1) & 0x1F) << 16) +#define RPCIF_DRCR_RCF BIT(9) +#define RPCIF_DRCR_RBE BIT(8) +#define RPCIF_DRCR_SSLE BIT(0) + +#define RPCIF_DRCMR 0x0010 /* R/W */ +#define RPCIF_DRCMR_CMD(c) (((c) & 0xFF) << 16) +#define RPCIF_DRCMR_OCMD(c) (((c) & 0xFF) << 0) + +#define RPCIF_DREAR 0x0014 /* R/W */ +#define RPCIF_DREAR_EAV(c) (((c) & 0xF) << 16) +#define RPCIF_DREAR_EAC(c) (((c) & 0x7) << 0) + +#define RPCIF_DROPR 0x0018 /* R/W */ + +#define RPCIF_DRENR 0x001C /* R/W */ +#define RPCIF_DRENR_CDB(o) (((u32)((o) & 0x3)) << 30) +#define RPCIF_DRENR_OCDB(o) (((o) & 0x3) << 28) +#define RPCIF_DRENR_ADB(o) (((o) & 0x3) << 24) +#define RPCIF_DRENR_OPDB(o) (((o) & 0x3) << 20) +#define RPCIF_DRENR_DRDB(o) (((o) & 0x3) << 16) +#define RPCIF_DRENR_DME BIT(15) +#define RPCIF_DRENR_CDE BIT(14) +#define RPCIF_DRENR_OCDE BIT(12) +#define RPCIF_DRENR_ADE(v) (((v) & 0xF) << 8) +#define RPCIF_DRENR_OPDE(v) (((v) & 0xF) << 4) + +#define RPCIF_SMCR 0x0020 /* R/W */ +#define RPCIF_SMCR_SSLKP BIT(8) +#define RPCIF_SMCR_SPIRE BIT(2) +#define RPCIF_SMCR_SPIWE BIT(1) +#define RPCIF_SMCR_SPIE BIT(0) + +#define RPCIF_SMCMR 0x0024 /* R/W */ +#define RPCIF_SMCMR_CMD(c) (((c) & 0xFF) << 16) +#define RPCIF_SMCMR_OCMD(c) (((c) & 0xFF) << 0) + +#define RPCIF_SMADR 0x0028 /* R/W */ + +#define RPCIF_SMOPR 0x002C /* R/W */ +#define RPCIF_SMOPR_OPD3(o) (((o) & 0xFF) << 24) +#define RPCIF_SMOPR_OPD2(o) (((o) & 0xFF) << 16) +#define RPCIF_SMOPR_OPD1(o) (((o) & 0xFF) << 8) +#define RPCIF_SMOPR_OPD0(o) (((o) & 0xFF) << 0) + +#define RPCIF_SMENR 0x0030 /* R/W */ +#define RPCIF_SMENR_CDB(o) (((o) & 0x3) << 30) +#define RPCIF_SMENR_OCDB(o) (((o) & 0x3) << 28) +#define RPCIF_SMENR_ADB(o) (((o) & 0x3) << 24) +#define RPCIF_SMENR_OPDB(o) (((o) & 0x3) << 20) +#define RPCIF_SMENR_SPIDB(o) (((o) & 0x3) << 16) +#define RPCIF_SMENR_DME BIT(15) +#define RPCIF_SMENR_CDE BIT(14) +#define RPCIF_SMENR_OCDE BIT(12) +#define RPCIF_SMENR_ADE(v) (((v) & 0xF) << 8) +#define RPCIF_SMENR_OPDE(v) (((v) & 0xF) << 4) +#define RPCIF_SMENR_SPIDE(v) (((v) & 0xF) << 0) + +#define RPCIF_SMRDR0 0x0038 /* R */ +#define RPCIF_SMRDR1 0x003C /* R */ +#define RPCIF_SMWDR0 0x0040 /* W */ +#define RPCIF_SMWDR1 0x0044 /* W */ + +#define RPCIF_CMNSR 0x0048 /* R */ +#define RPCIF_CMNSR_SSLF BIT(1) +#define RPCIF_CMNSR_TEND BIT(0) + +#define RPCIF_DRDMCR 0x0058 /* R/W */ +#define RPCIF_DMDMCR_DMCYC(v) ((((v) - 1) & 0x1F) << 0) + +#define RPCIF_DRDRENR 0x005C /* R/W */ +#define RPCIF_DRDRENR_HYPE(v) (((v) & 0x7) << 12) +#define RPCIF_DRDRENR_ADDRE BIT(8) +#define RPCIF_DRDRENR_OPDRE BIT(4) +#define RPCIF_DRDRENR_DRDRE BIT(0) + +#define RPCIF_SMDMCR 0x0060 /* R/W */ +#define RPCIF_SMDMCR_DMCYC(v) ((((v) - 1) & 0x1F) << 0) + +#define RPCIF_SMDRENR 0x0064 /* R/W */ +#define RPCIF_SMDRENR_HYPE(v) (((v) & 0x7) << 12) +#define RPCIF_SMDRENR_ADDRE BIT(8) +#define RPCIF_SMDRENR_OPDRE BIT(4) +#define RPCIF_SMDRENR_SPIDRE BIT(0) + +#define RPCIF_PHYADD 0x0070 /* R/W available on R-Car E3/D3/V3M and RZ/G2{E,L} */ +#define RPCIF_PHYWR 0x0074 /* R/W available on R-Car E3/D3/V3M and RZ/G2{E,L} */ + +#define RPCIF_PHYCNT 0x007C /* R/W */ +#define RPCIF_PHYCNT_CAL BIT(31) +#define RPCIF_PHYCNT_OCTA(v) (((v) & 0x3) << 22) +#define RPCIF_PHYCNT_EXDS BIT(21) +#define RPCIF_PHYCNT_OCT BIT(20) +#define RPCIF_PHYCNT_DDRCAL BIT(19) +#define RPCIF_PHYCNT_HS BIT(18) +#define RPCIF_PHYCNT_CKSEL(v) (((v) & 0x3) << 16) /* valid only for RZ/G2L */ +#define RPCIF_PHYCNT_STRTIM(v) (((v) & 0x7) << 15 | ((v) & 0x8) << 24) /* valid for R-Car and RZ/G2{E,H,M,N} */ + +#define RPCIF_PHYCNT_WBUF2 BIT(4) +#define RPCIF_PHYCNT_WBUF BIT(2) +#define RPCIF_PHYCNT_PHYMEM(v) (((v) & 0x3) << 0) +#define RPCIF_PHYCNT_PHYMEM_MASK GENMASK(1, 0) + +#define RPCIF_PHYOFFSET1 0x0080 /* R/W */ +#define RPCIF_PHYOFFSET1_DDRTMG(v) (((v) & 0x3) << 28) + +#define RPCIF_PHYOFFSET2 0x0084 /* R/W */ +#define RPCIF_PHYOFFSET2_OCTTMG(v) (((v) & 0x7) << 8) + +#define RPCIF_PHYINT 0x0088 /* R/W */ +#define RPCIF_PHYINT_WPVAL BIT(1) + +#endif /* __RENESAS_RPC_IF_REGS_H__ */ diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 4a59bf27eace..64618a2d09f7 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -18,139 +18,7 @@ #include -#define RPCIF_CMNCR 0x0000 /* R/W */ -#define RPCIF_CMNCR_MD BIT(31) -#define RPCIF_CMNCR_MOIIO3(val) (((val) & 0x3) << 22) -#define RPCIF_CMNCR_MOIIO2(val) (((val) & 0x3) << 20) -#define RPCIF_CMNCR_MOIIO1(val) (((val) & 0x3) << 18) -#define RPCIF_CMNCR_MOIIO0(val) (((val) & 0x3) << 16) -#define RPCIF_CMNCR_MOIIO(val) (RPCIF_CMNCR_MOIIO0(val) | RPCIF_CMNCR_MOIIO1(val) | \ - RPCIF_CMNCR_MOIIO2(val) | RPCIF_CMNCR_MOIIO3(val)) -#define RPCIF_CMNCR_IO3FV(val) (((val) & 0x3) << 14) /* documented for RZ/G2L */ -#define RPCIF_CMNCR_IO2FV(val) (((val) & 0x3) << 12) /* documented for RZ/G2L */ -#define RPCIF_CMNCR_IO0FV(val) (((val) & 0x3) << 8) -#define RPCIF_CMNCR_IOFV(val) (RPCIF_CMNCR_IO0FV(val) | RPCIF_CMNCR_IO2FV(val) | \ - RPCIF_CMNCR_IO3FV(val)) -#define RPCIF_CMNCR_BSZ(val) (((val) & 0x3) << 0) - -#define RPCIF_SSLDR 0x0004 /* R/W */ -#define RPCIF_SSLDR_SPNDL(d) (((d) & 0x7) << 16) -#define RPCIF_SSLDR_SLNDL(d) (((d) & 0x7) << 8) -#define RPCIF_SSLDR_SCKDL(d) (((d) & 0x7) << 0) - -#define RPCIF_DRCR 0x000C /* R/W */ -#define RPCIF_DRCR_SSLN BIT(24) -#define RPCIF_DRCR_RBURST(v) ((((v) - 1) & 0x1F) << 16) -#define RPCIF_DRCR_RCF BIT(9) -#define RPCIF_DRCR_RBE BIT(8) -#define RPCIF_DRCR_SSLE BIT(0) - -#define RPCIF_DRCMR 0x0010 /* R/W */ -#define RPCIF_DRCMR_CMD(c) (((c) & 0xFF) << 16) -#define RPCIF_DRCMR_OCMD(c) (((c) & 0xFF) << 0) - -#define RPCIF_DREAR 0x0014 /* R/W */ -#define RPCIF_DREAR_EAV(c) (((c) & 0xF) << 16) -#define RPCIF_DREAR_EAC(c) (((c) & 0x7) << 0) - -#define RPCIF_DROPR 0x0018 /* R/W */ - -#define RPCIF_DRENR 0x001C /* R/W */ -#define RPCIF_DRENR_CDB(o) (((u32)((o) & 0x3)) << 30) -#define RPCIF_DRENR_OCDB(o) (((o) & 0x3) << 28) -#define RPCIF_DRENR_ADB(o) (((o) & 0x3) << 24) -#define RPCIF_DRENR_OPDB(o) (((o) & 0x3) << 20) -#define RPCIF_DRENR_DRDB(o) (((o) & 0x3) << 16) -#define RPCIF_DRENR_DME BIT(15) -#define RPCIF_DRENR_CDE BIT(14) -#define RPCIF_DRENR_OCDE BIT(12) -#define RPCIF_DRENR_ADE(v) (((v) & 0xF) << 8) -#define RPCIF_DRENR_OPDE(v) (((v) & 0xF) << 4) - -#define RPCIF_SMCR 0x0020 /* R/W */ -#define RPCIF_SMCR_SSLKP BIT(8) -#define RPCIF_SMCR_SPIRE BIT(2) -#define RPCIF_SMCR_SPIWE BIT(1) -#define RPCIF_SMCR_SPIE BIT(0) - -#define RPCIF_SMCMR 0x0024 /* R/W */ -#define RPCIF_SMCMR_CMD(c) (((c) & 0xFF) << 16) -#define RPCIF_SMCMR_OCMD(c) (((c) & 0xFF) << 0) - -#define RPCIF_SMADR 0x0028 /* R/W */ - -#define RPCIF_SMOPR 0x002C /* R/W */ -#define RPCIF_SMOPR_OPD3(o) (((o) & 0xFF) << 24) -#define RPCIF_SMOPR_OPD2(o) (((o) & 0xFF) << 16) -#define RPCIF_SMOPR_OPD1(o) (((o) & 0xFF) << 8) -#define RPCIF_SMOPR_OPD0(o) (((o) & 0xFF) << 0) - -#define RPCIF_SMENR 0x0030 /* R/W */ -#define RPCIF_SMENR_CDB(o) (((o) & 0x3) << 30) -#define RPCIF_SMENR_OCDB(o) (((o) & 0x3) << 28) -#define RPCIF_SMENR_ADB(o) (((o) & 0x3) << 24) -#define RPCIF_SMENR_OPDB(o) (((o) & 0x3) << 20) -#define RPCIF_SMENR_SPIDB(o) (((o) & 0x3) << 16) -#define RPCIF_SMENR_DME BIT(15) -#define RPCIF_SMENR_CDE BIT(14) -#define RPCIF_SMENR_OCDE BIT(12) -#define RPCIF_SMENR_ADE(v) (((v) & 0xF) << 8) -#define RPCIF_SMENR_OPDE(v) (((v) & 0xF) << 4) -#define RPCIF_SMENR_SPIDE(v) (((v) & 0xF) << 0) - -#define RPCIF_SMRDR0 0x0038 /* R */ -#define RPCIF_SMRDR1 0x003C /* R */ -#define RPCIF_SMWDR0 0x0040 /* W */ -#define RPCIF_SMWDR1 0x0044 /* W */ - -#define RPCIF_CMNSR 0x0048 /* R */ -#define RPCIF_CMNSR_SSLF BIT(1) -#define RPCIF_CMNSR_TEND BIT(0) - -#define RPCIF_DRDMCR 0x0058 /* R/W */ -#define RPCIF_DMDMCR_DMCYC(v) ((((v) - 1) & 0x1F) << 0) - -#define RPCIF_DRDRENR 0x005C /* R/W */ -#define RPCIF_DRDRENR_HYPE(v) (((v) & 0x7) << 12) -#define RPCIF_DRDRENR_ADDRE BIT(8) -#define RPCIF_DRDRENR_OPDRE BIT(4) -#define RPCIF_DRDRENR_DRDRE BIT(0) - -#define RPCIF_SMDMCR 0x0060 /* R/W */ -#define RPCIF_SMDMCR_DMCYC(v) ((((v) - 1) & 0x1F) << 0) - -#define RPCIF_SMDRENR 0x0064 /* R/W */ -#define RPCIF_SMDRENR_HYPE(v) (((v) & 0x7) << 12) -#define RPCIF_SMDRENR_ADDRE BIT(8) -#define RPCIF_SMDRENR_OPDRE BIT(4) -#define RPCIF_SMDRENR_SPIDRE BIT(0) - -#define RPCIF_PHYADD 0x0070 /* R/W available on R-Car E3/D3/V3M and RZ/G2{E,L} */ -#define RPCIF_PHYWR 0x0074 /* R/W available on R-Car E3/D3/V3M and RZ/G2{E,L} */ - -#define RPCIF_PHYCNT 0x007C /* R/W */ -#define RPCIF_PHYCNT_CAL BIT(31) -#define RPCIF_PHYCNT_OCTA(v) (((v) & 0x3) << 22) -#define RPCIF_PHYCNT_EXDS BIT(21) -#define RPCIF_PHYCNT_OCT BIT(20) -#define RPCIF_PHYCNT_DDRCAL BIT(19) -#define RPCIF_PHYCNT_HS BIT(18) -#define RPCIF_PHYCNT_CKSEL(v) (((v) & 0x3) << 16) /* valid only for RZ/G2L */ -#define RPCIF_PHYCNT_STRTIM(v) (((v) & 0x7) << 15 | ((v) & 0x8) << 24) /* valid for R-Car and RZ/G2{E,H,M,N} */ - -#define RPCIF_PHYCNT_WBUF2 BIT(4) -#define RPCIF_PHYCNT_WBUF BIT(2) -#define RPCIF_PHYCNT_PHYMEM(v) (((v) & 0x3) << 0) -#define RPCIF_PHYCNT_PHYMEM_MASK GENMASK(1, 0) - -#define RPCIF_PHYOFFSET1 0x0080 /* R/W */ -#define RPCIF_PHYOFFSET1_DDRTMG(v) (((v) & 0x3) << 28) - -#define RPCIF_PHYOFFSET2 0x0084 /* R/W */ -#define RPCIF_PHYOFFSET2_OCTTMG(v) (((v) & 0x7) << 8) - -#define RPCIF_PHYINT 0x0088 /* R/W */ -#define RPCIF_PHYINT_WPVAL BIT(1) +#include "renesas-rpc-if-regs.h" static const struct regmap_range rpcif_volatile_ranges[] = { regmap_reg_range(RPCIF_SMRDR0, RPCIF_SMRDR1), -- 2.51.0 From c66fce831d0669dc809f90bcefd80ae979e35431 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 24 Apr 2025 09:59:51 +0100 Subject: [PATCH 11/16] memory: renesas-rpc-if: Use devm_reset_control_array_get_exclusive() Replace devm_*_get_exclusive()->devm_*_array_get_exclusive() to support existing SoCs along with RZ/G3E as RZ/G3E has 2 resets. Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250424090000.136804-4-biju.das.jz@bp.renesas.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/renesas-rpc-if.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 64618a2d09f7..9f3ac5cb9ff4 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -603,7 +603,7 @@ static int rpcif_probe(struct platform_device *pdev) rpc->size = resource_size(res); rpc->info = of_device_get_match_data(dev); - rpc->rstc = devm_reset_control_get_exclusive(dev, NULL); + rpc->rstc = devm_reset_control_array_get_exclusive(dev); if (IS_ERR(rpc->rstc)) return PTR_ERR(rpc->rstc); -- 2.51.0 From 198158a8f64cf150325f68044274e21ab0aa69c8 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 24 Apr 2025 09:59:52 +0100 Subject: [PATCH 12/16] memory: renesas-rpc-if: Add regmap to struct rpcif_info The RZ/G3E XSPI has different regmap compared to RPC-IF. Add regmap to struct rpcif_info in order to support RZ/G3E XSPI. Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250424090000.136804-5-biju.das.jz@bp.renesas.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/renesas-rpc-if.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 9f3ac5cb9ff4..56b2e944beca 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -32,6 +32,7 @@ static const struct regmap_access_table rpcif_volatile_table = { }; struct rpcif_info { + const struct regmap_config *regmap_config; enum rpcif_type type; u8 strtim; }; @@ -588,8 +589,8 @@ static int rpcif_probe(struct platform_device *pdev) rpc->base = devm_platform_ioremap_resource_byname(pdev, "regs"); if (IS_ERR(rpc->base)) return PTR_ERR(rpc->base); - - rpc->regmap = devm_regmap_init(dev, NULL, rpc, &rpcif_regmap_config); + rpc->info = of_device_get_match_data(dev); + rpc->regmap = devm_regmap_init(dev, NULL, rpc, rpc->info->regmap_config); if (IS_ERR(rpc->regmap)) { dev_err(dev, "failed to init regmap for rpcif, error %ld\n", PTR_ERR(rpc->regmap)); @@ -602,7 +603,6 @@ static int rpcif_probe(struct platform_device *pdev) return PTR_ERR(rpc->dirmap); rpc->size = resource_size(res); - rpc->info = of_device_get_match_data(dev); rpc->rstc = devm_reset_control_array_get_exclusive(dev); if (IS_ERR(rpc->rstc)) return PTR_ERR(rpc->rstc); @@ -633,21 +633,25 @@ static void rpcif_remove(struct platform_device *pdev) } static const struct rpcif_info rpcif_info_r8a7796 = { + .regmap_config = &rpcif_regmap_config, .type = RPCIF_RCAR_GEN3, .strtim = 6, }; static const struct rpcif_info rpcif_info_gen3 = { + .regmap_config = &rpcif_regmap_config, .type = RPCIF_RCAR_GEN3, .strtim = 7, }; static const struct rpcif_info rpcif_info_rz_g2l = { + .regmap_config = &rpcif_regmap_config, .type = RPCIF_RZ_G2L, .strtim = 7, }; static const struct rpcif_info rpcif_info_gen4 = { + .regmap_config = &rpcif_regmap_config, .type = RPCIF_RCAR_GEN4, .strtim = 15, }; -- 2.51.0 From e1c200a4c7f0e8b842a9a5b7f38fa7036c0df417 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 24 Apr 2025 09:59:53 +0100 Subject: [PATCH 13/16] memory: renesas-rpc-if: Add wrapper functions Even though XSPI and RPCIF has different register layout, reuse the code by adding wrapper functions to support both XSPI and RPC-IF. While at it, replace error check for pm_runtime_resume_and_get(). Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250424090000.136804-6-biju.das.jz@bp.renesas.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/renesas-rpc-if.c | 96 ++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 31 deletions(-) diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 56b2e944beca..eea38f448e03 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -174,16 +174,11 @@ static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif_priv *rpc) regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000032); } -int rpcif_hw_init(struct device *dev, bool hyperflash) +static int rpcif_hw_init_impl(struct rpcif_priv *rpc, bool hyperflash) { - struct rpcif_priv *rpc = dev_get_drvdata(dev); u32 dummy; int ret; - ret = pm_runtime_resume_and_get(dev); - if (ret) - return ret; - if (rpc->info->type == RPCIF_RZ_G2L) { ret = reset_control_reset(rpc->rstc); if (ret) @@ -231,12 +226,26 @@ int rpcif_hw_init(struct device *dev, bool hyperflash) regmap_write(rpc->regmap, RPCIF_SSLDR, RPCIF_SSLDR_SPNDL(7) | RPCIF_SSLDR_SLNDL(7) | RPCIF_SSLDR_SCKDL(7)); - pm_runtime_put(dev); - rpc->bus_size = hyperflash ? 2 : 1; return 0; } + +int rpcif_hw_init(struct device *dev, bool hyperflash) +{ + struct rpcif_priv *rpc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + ret = rpcif_hw_init_impl(rpc, hyperflash); + + pm_runtime_put(dev); + + return ret; +} EXPORT_SYMBOL(rpcif_hw_init); static int wait_msg_xfer_end(struct rpcif_priv *rpc) @@ -261,11 +270,9 @@ static u8 rpcif_bit_size(u8 buswidth) return buswidth > 4 ? 2 : ilog2(buswidth); } -void rpcif_prepare(struct device *dev, const struct rpcif_op *op, u64 *offs, - size_t *len) +static void rpcif_prepare_impl(struct rpcif_priv *rpc, const struct rpcif_op *op, + u64 *offs, size_t *len) { - struct rpcif_priv *rpc = dev_get_drvdata(dev); - rpc->smcr = 0; rpc->smadr = 0; rpc->enable = 0; @@ -346,18 +353,21 @@ void rpcif_prepare(struct device *dev, const struct rpcif_op *op, u64 *offs, rpc->enable |= RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth)); } } -EXPORT_SYMBOL(rpcif_prepare); -int rpcif_manual_xfer(struct device *dev) +void rpcif_prepare(struct device *dev, const struct rpcif_op *op, u64 *offs, + size_t *len) { struct rpcif_priv *rpc = dev_get_drvdata(dev); + + rpcif_prepare_impl(rpc, op, offs, len); +} +EXPORT_SYMBOL(rpcif_prepare); + +static int rpcif_manual_xfer_impl(struct rpcif_priv *rpc) +{ u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4; int ret = 0; - ret = pm_runtime_resume_and_get(dev); - if (ret < 0) - return ret; - regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_CAL, RPCIF_PHYCNT_CAL); regmap_update_bits(rpc->regmap, RPCIF_CMNCR, @@ -465,15 +475,29 @@ int rpcif_manual_xfer(struct device *dev) goto err_out; } -exit: - pm_runtime_put(dev); return ret; err_out: if (reset_control_reset(rpc->rstc)) - dev_err(dev, "Failed to reset HW\n"); - rpcif_hw_init(dev, rpc->bus_size == 2); - goto exit; + dev_err(rpc->dev, "Failed to reset HW\n"); + rpcif_hw_init_impl(rpc, rpc->bus_size == 2); + return ret; +} + +int rpcif_manual_xfer(struct device *dev) +{ + struct rpcif_priv *rpc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + ret = rpcif_manual_xfer_impl(rpc); + + pm_runtime_put(dev); + + return ret; } EXPORT_SYMBOL(rpcif_manual_xfer); @@ -519,20 +543,15 @@ static void memcpy_fromio_readw(void *to, } } -ssize_t rpcif_dirmap_read(struct device *dev, u64 offs, size_t len, void *buf) +static size_t rpcif_dirmap_read_impl(struct rpcif_priv *rpc, u64 offs, + size_t len, void *buf) { - struct rpcif_priv *rpc = dev_get_drvdata(dev); loff_t from = offs & (rpc->size - 1); size_t size = rpc->size - from; - int ret; if (len > size) len = size; - ret = pm_runtime_resume_and_get(dev); - if (ret < 0) - return ret; - regmap_update_bits(rpc->regmap, RPCIF_CMNCR, RPCIF_CMNCR_MD, 0); regmap_write(rpc->regmap, RPCIF_DRCR, 0); regmap_write(rpc->regmap, RPCIF_DRCMR, rpc->command); @@ -549,9 +568,24 @@ ssize_t rpcif_dirmap_read(struct device *dev, u64 offs, size_t len, void *buf) else memcpy_fromio(buf, rpc->dirmap + from, len); + return len; +} + +ssize_t rpcif_dirmap_read(struct device *dev, u64 offs, size_t len, void *buf) +{ + struct rpcif_priv *rpc = dev_get_drvdata(dev); + size_t read; + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + read = rpcif_dirmap_read_impl(rpc, offs, len, buf); + pm_runtime_put(dev); - return len; + return read; } EXPORT_SYMBOL(rpcif_dirmap_read); -- 2.51.0 From 687cac9559d8e9277830bdfb68b57d7403695b1d Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 24 Apr 2025 09:59:54 +0100 Subject: [PATCH 14/16] memory: renesas-rpc-if: Add RZ/G3E xSPI support Add support for RZ/G3E xSPI. Compared to RPC-IF, it can support writes on memory-mapped area. Introduce struct rpcif_impl for holding the function pointers and data to handle the differences between xspi and rpc-if interface. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250424090000.136804-7-biju.das.jz@bp.renesas.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/renesas-rpc-if.c | 440 +++++++++++++++++++++++++- drivers/memory/renesas-xspi-if-regs.h | 105 ++++++ include/memory/renesas-rpc-if.h | 4 + 3 files changed, 542 insertions(+), 7 deletions(-) create mode 100644 drivers/memory/renesas-xspi-if-regs.h diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index eea38f448e03..4b2e903f2b0d 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -19,6 +19,7 @@ #include #include "renesas-rpc-if-regs.h" +#include "renesas-xspi-if-regs.h" static const struct regmap_range rpcif_volatile_ranges[] = { regmap_reg_range(RPCIF_SMRDR0, RPCIF_SMRDR1), @@ -31,8 +32,31 @@ static const struct regmap_access_table rpcif_volatile_table = { .n_yes_ranges = ARRAY_SIZE(rpcif_volatile_ranges), }; +static const struct regmap_range xspi_volatile_ranges[] = { + regmap_reg_range(XSPI_CDD0BUF0, XSPI_CDD0BUF0), +}; + +static const struct regmap_access_table xspi_volatile_table = { + .yes_ranges = xspi_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(xspi_volatile_ranges), +}; + +struct rpcif_priv; + +struct rpcif_impl { + int (*hw_init)(struct rpcif_priv *rpc, bool hyperflash); + void (*prepare)(struct rpcif_priv *rpc, const struct rpcif_op *op, + u64 *offs, size_t *len); + int (*manual_xfer)(struct rpcif_priv *rpc); + size_t (*dirmap_read)(struct rpcif_priv *rpc, u64 offs, size_t len, + void *buf); + u32 status_reg; + u32 status_mask; +}; + struct rpcif_info { const struct regmap_config *regmap_config; + const struct rpcif_impl *impl; enum rpcif_type type; u8 strtim; }; @@ -49,6 +73,8 @@ struct rpcif_priv { enum rpcif_data_dir dir; u8 bus_size; u8 xfer_size; + u8 addr_nbytes; /* Specified for xSPI */ + u32 proto; /* Specified for xSPI */ void *buffer; u32 xferlen; u32 smcr; @@ -149,6 +175,33 @@ static const struct regmap_config rpcif_regmap_config = { .volatile_table = &rpcif_volatile_table, }; +static int xspi_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct rpcif_priv *xspi = context; + + *val = readl(xspi->base + reg); + return 0; +} + +static int xspi_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct rpcif_priv *xspi = context; + + writel(val, xspi->base + reg); + return 0; +} + +static const struct regmap_config xspi_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .reg_read = xspi_reg_read, + .reg_write = xspi_reg_write, + .fast_io = true, + .max_register = XSPI_INTE, + .volatile_table = &xspi_volatile_table, +}; + int rpcif_sw_init(struct rpcif *rpcif, struct device *dev) { struct rpcif_priv *rpc = dev_get_drvdata(dev); @@ -156,6 +209,7 @@ int rpcif_sw_init(struct rpcif *rpcif, struct device *dev) rpcif->dev = dev; rpcif->dirmap = rpc->dirmap; rpcif->size = rpc->size; + rpcif->xspi = rpc->info->type == XSPI_RZ_G3E; return 0; } EXPORT_SYMBOL(rpcif_sw_init); @@ -231,6 +285,33 @@ static int rpcif_hw_init_impl(struct rpcif_priv *rpc, bool hyperflash) return 0; } +static int xspi_hw_init_impl(struct rpcif_priv *xspi, bool hyperflash) +{ + int ret; + + ret = reset_control_reset(xspi->rstc); + if (ret) + return ret; + + regmap_write(xspi->regmap, XSPI_WRAPCFG, 0x0); + + regmap_update_bits(xspi->regmap, XSPI_LIOCFGCS0, + XSPI_LIOCFG_PRTMD(0x3ff) | XSPI_LIOCFG_CSMIN(0xf) | + XSPI_LIOCFG_CSASTEX | XSPI_LIOCFG_CSNEGEX, + XSPI_LIOCFG_PRTMD(0) | XSPI_LIOCFG_CSMIN(0) | + XSPI_LIOCFG_CSASTEX | XSPI_LIOCFG_CSNEGEX); + + regmap_update_bits(xspi->regmap, XSPI_CCCTL0CS0, XSPI_CCCTL0_CAEN, 0); + + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, + XSPI_CDCTL0_TRREQ | XSPI_CDCTL0_CSSEL, 0); + + regmap_update_bits(xspi->regmap, XSPI_INTE, XSPI_INTE_CMDCMPE, + XSPI_INTE_CMDCMPE); + + return 0; +} + int rpcif_hw_init(struct device *dev, bool hyperflash) { struct rpcif_priv *rpc = dev_get_drvdata(dev); @@ -240,7 +321,7 @@ int rpcif_hw_init(struct device *dev, bool hyperflash) if (ret) return ret; - ret = rpcif_hw_init_impl(rpc, hyperflash); + ret = rpc->info->impl->hw_init(rpc, hyperflash); pm_runtime_put(dev); @@ -252,9 +333,9 @@ static int wait_msg_xfer_end(struct rpcif_priv *rpc) { u32 sts; - return regmap_read_poll_timeout(rpc->regmap, RPCIF_CMNSR, sts, - sts & RPCIF_CMNSR_TEND, 0, - USEC_PER_SEC); + return regmap_read_poll_timeout(rpc->regmap, rpc->info->impl->status_reg, + sts, sts & rpc->info->impl->status_mask, + 0, USEC_PER_SEC); } static u8 rpcif_bits_set(struct rpcif_priv *rpc, u32 nbytes) @@ -354,12 +435,67 @@ static void rpcif_prepare_impl(struct rpcif_priv *rpc, const struct rpcif_op *op } } +static void xspi_prepare_impl(struct rpcif_priv *xspi, const struct rpcif_op *op, + u64 *offs, size_t *len) +{ + xspi->smadr = 0; + xspi->addr_nbytes = 0; + xspi->command = 0; + xspi->option = 0; + xspi->dummy = 0; + xspi->xferlen = 0; + xspi->proto = 0; + + if (op->cmd.buswidth) + xspi->command = op->cmd.opcode; + + if (op->ocmd.buswidth) + xspi->command = (xspi->command << 8) | op->ocmd.opcode; + + if (op->addr.buswidth) { + xspi->addr_nbytes = op->addr.nbytes; + if (offs && len) + xspi->smadr = *offs; + else + xspi->smadr = op->addr.val; + } + + if (op->dummy.buswidth) + xspi->dummy = op->dummy.ncycles; + + xspi->dir = op->data.dir; + if (op->data.buswidth) { + u32 nbytes; + + xspi->buffer = op->data.buf.in; + + if (offs && len) + nbytes = *len; + else + nbytes = op->data.nbytes; + xspi->xferlen = nbytes; + } + + if (op->cmd.buswidth == 1) { + if (op->addr.buswidth == 2 || op->data.buswidth == 2) + xspi->proto = PROTO_1S_2S_2S; + else if (op->addr.buswidth == 4 || op->data.buswidth == 4) + xspi->proto = PROTO_1S_4S_4S; + } else if (op->cmd.buswidth == 2 && + (op->addr.buswidth == 2 || op->data.buswidth == 2)) { + xspi->proto = PROTO_2S_2S_2S; + } else if (op->cmd.buswidth == 4 && + (op->addr.buswidth == 4 || op->data.buswidth == 4)) { + xspi->proto = PROTO_4S_4S_4S; + } +} + void rpcif_prepare(struct device *dev, const struct rpcif_op *op, u64 *offs, size_t *len) { struct rpcif_priv *rpc = dev_get_drvdata(dev); - rpcif_prepare_impl(rpc, op, offs, len); + rpc->info->impl->prepare(rpc, op, offs, len); } EXPORT_SYMBOL(rpcif_prepare); @@ -484,6 +620,146 @@ err_out: return ret; } +static int xspi_manual_xfer_impl(struct rpcif_priv *xspi) +{ + u32 pos = 0, max = 8; + int ret = 0; + + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, XSPI_CDCTL0_TRNUM(0x3), + XSPI_CDCTL0_TRNUM(0)); + + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, XSPI_CDCTL0_TRREQ, 0); + + regmap_write(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_CMDSIZE(0x1) | XSPI_CDTBUF_CMD_FIELD(xspi->command)); + + regmap_write(xspi->regmap, XSPI_CDABUF0, 0); + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, XSPI_CDTBUF_ADDSIZE(0x7), + XSPI_CDTBUF_ADDSIZE(xspi->addr_nbytes)); + + regmap_write(xspi->regmap, XSPI_CDABUF0, xspi->smadr); + + regmap_update_bits(xspi->regmap, XSPI_LIOCFGCS0, XSPI_LIOCFG_PRTMD(0x3ff), + XSPI_LIOCFG_PRTMD(xspi->proto)); + + switch (xspi->dir) { + case RPCIF_DATA_OUT: + while (pos < xspi->xferlen) { + u32 bytes_left = xspi->xferlen - pos; + u32 nbytes, data[2], *p = data; + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_TRTYPE, XSPI_CDTBUF_TRTYPE); + + nbytes = bytes_left >= max ? max : bytes_left; + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_DATASIZE(0xf), + XSPI_CDTBUF_DATASIZE(nbytes)); + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_ADDSIZE(0x7), + XSPI_CDTBUF_ADDSIZE(xspi->addr_nbytes)); + + memcpy(data, xspi->buffer + pos, nbytes); + + if (nbytes > 4) { + regmap_write(xspi->regmap, XSPI_CDD0BUF0, *p++); + regmap_write(xspi->regmap, XSPI_CDD1BUF0, *p); + } else { + regmap_write(xspi->regmap, XSPI_CDD0BUF0, *p); + } + + regmap_write(xspi->regmap, XSPI_CDABUF0, xspi->smadr + pos); + + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, + XSPI_CDCTL0_TRREQ, XSPI_CDCTL0_TRREQ); + + ret = wait_msg_xfer_end(xspi); + if (ret) + goto err_out; + + regmap_update_bits(xspi->regmap, XSPI_INTC, + XSPI_INTC_CMDCMPC, XSPI_INTC_CMDCMPC); + + pos += nbytes; + } + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, XSPI_CDCTL0_TRREQ, 0); + break; + case RPCIF_DATA_IN: + while (pos < xspi->xferlen) { + u32 bytes_left = xspi->xferlen - pos; + u32 nbytes, data[2], *p = data; + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_TRTYPE, + ~(u32)XSPI_CDTBUF_TRTYPE); + + /* nbytes can be up to 8 bytes */ + nbytes = bytes_left >= max ? max : bytes_left; + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_DATASIZE(0xf), + XSPI_CDTBUF_DATASIZE(nbytes)); + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_ADDSIZE(0x7), + XSPI_CDTBUF_ADDSIZE(xspi->addr_nbytes)); + + if (xspi->addr_nbytes) + regmap_write(xspi->regmap, XSPI_CDABUF0, + xspi->smadr + pos); + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_LATE(0x1f), + XSPI_CDTBUF_LATE(xspi->dummy)); + + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, + XSPI_CDCTL0_TRREQ, XSPI_CDCTL0_TRREQ); + + ret = wait_msg_xfer_end(xspi); + if (ret) + goto err_out; + + if (nbytes > 4) { + regmap_read(xspi->regmap, XSPI_CDD0BUF0, p++); + regmap_read(xspi->regmap, XSPI_CDD1BUF0, p); + } else { + regmap_read(xspi->regmap, XSPI_CDD0BUF0, p); + } + + memcpy(xspi->buffer + pos, data, nbytes); + + regmap_update_bits(xspi->regmap, XSPI_INTC, + XSPI_INTC_CMDCMPC, XSPI_INTC_CMDCMPC); + + pos += nbytes; + } + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, + XSPI_CDCTL0_TRREQ, 0); + break; + default: + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_TRTYPE, XSPI_CDTBUF_TRTYPE); + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, + XSPI_CDCTL0_TRREQ, XSPI_CDCTL0_TRREQ); + + ret = wait_msg_xfer_end(xspi); + if (ret) + goto err_out; + + regmap_update_bits(xspi->regmap, XSPI_INTC, + XSPI_INTC_CMDCMPC, XSPI_INTC_CMDCMPC); + } + + return ret; + +err_out: + xspi_hw_init_impl(xspi, false); + return ret; +} + int rpcif_manual_xfer(struct device *dev) { struct rpcif_priv *rpc = dev_get_drvdata(dev); @@ -493,7 +769,7 @@ int rpcif_manual_xfer(struct device *dev) if (ret) return ret; - ret = rpcif_manual_xfer_impl(rpc); + ret = rpc->info->impl->manual_xfer(rpc); pm_runtime_put(dev); @@ -571,6 +847,42 @@ static size_t rpcif_dirmap_read_impl(struct rpcif_priv *rpc, u64 offs, return len; } +static size_t xspi_dirmap_read_impl(struct rpcif_priv *xspi, u64 offs, + size_t len, void *buf) +{ + loff_t from = offs & (xspi->size - 1); + size_t size = xspi->size - from; + u8 addsize = xspi->addr_nbytes - 1; + + if (len > size) + len = size; + + regmap_update_bits(xspi->regmap, XSPI_CMCFG0CS0, + XSPI_CMCFG0_FFMT(0x3) | XSPI_CMCFG0_ADDSIZE(0x3), + XSPI_CMCFG0_FFMT(0) | XSPI_CMCFG0_ADDSIZE(addsize)); + + regmap_update_bits(xspi->regmap, XSPI_CMCFG1CS0, + XSPI_CMCFG1_RDCMD(0xffff) | XSPI_CMCFG1_RDLATE(0x1f), + XSPI_CMCFG1_RDCMD_UPPER_BYTE(xspi->command) | + XSPI_CMCFG1_RDLATE(xspi->dummy)); + + regmap_update_bits(xspi->regmap, XSPI_BMCTL0, XSPI_BMCTL0_CS0ACC(0xff), + XSPI_BMCTL0_CS0ACC(0x01)); + + regmap_update_bits(xspi->regmap, XSPI_BMCFG, + XSPI_BMCFG_WRMD | XSPI_BMCFG_MWRCOMB | + XSPI_BMCFG_MWRSIZE(0xff) | XSPI_BMCFG_PREEN, + 0 | XSPI_BMCFG_MWRCOMB | XSPI_BMCFG_MWRSIZE(0x0f) | + XSPI_BMCFG_PREEN); + + regmap_update_bits(xspi->regmap, XSPI_LIOCFGCS0, XSPI_LIOCFG_PRTMD(0x3ff), + XSPI_LIOCFG_PRTMD(xspi->proto)); + + memcpy_fromio(buf, xspi->dirmap + from, len); + + return len; +} + ssize_t rpcif_dirmap_read(struct device *dev, u64 offs, size_t len, void *buf) { struct rpcif_priv *rpc = dev_get_drvdata(dev); @@ -581,7 +893,7 @@ ssize_t rpcif_dirmap_read(struct device *dev, u64 offs, size_t len, void *buf) if (ret) return ret; - read = rpcif_dirmap_read_impl(rpc, offs, len, buf); + read = rpc->info->impl->dirmap_read(rpc, offs, len, buf); pm_runtime_put(dev); @@ -589,6 +901,72 @@ ssize_t rpcif_dirmap_read(struct device *dev, u64 offs, size_t len, void *buf) } EXPORT_SYMBOL(rpcif_dirmap_read); +/** + * xspi_dirmap_write - Write data to xspi memory. + * @dev: xspi device + * @offs: offset + * @len: Number of bytes to be written. + * @buf: Buffer holding write data. + * + * This function writes data into xspi memory. + * + * Returns number of bytes written on success, else negative errno. + */ +ssize_t xspi_dirmap_write(struct device *dev, u64 offs, size_t len, const void *buf) +{ + struct rpcif_priv *xspi = dev_get_drvdata(dev); + loff_t from = offs & (xspi->size - 1); + u8 addsize = xspi->addr_nbytes - 1; + size_t size = xspi->size - from; + ssize_t writebytes; + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + if (len > size) + len = size; + + if (len > MWRSIZE_MAX) + writebytes = MWRSIZE_MAX; + else + writebytes = len; + + regmap_update_bits(xspi->regmap, XSPI_CMCFG0CS0, + XSPI_CMCFG0_FFMT(0x3) | XSPI_CMCFG0_ADDSIZE(0x3), + XSPI_CMCFG0_FFMT(0) | XSPI_CMCFG0_ADDSIZE(addsize)); + + regmap_update_bits(xspi->regmap, XSPI_CMCFG2CS0, + XSPI_CMCFG2_WRCMD_UPPER(0xff) | XSPI_CMCFG2_WRLATE(0x1f), + XSPI_CMCFG2_WRCMD_UPPER(xspi->command) | + XSPI_CMCFG2_WRLATE(xspi->dummy)); + + regmap_update_bits(xspi->regmap, XSPI_BMCTL0, + XSPI_BMCTL0_CS0ACC(0xff), XSPI_BMCTL0_CS0ACC(0x03)); + + regmap_update_bits(xspi->regmap, XSPI_BMCFG, + XSPI_BMCFG_WRMD | XSPI_BMCFG_MWRCOMB | + XSPI_BMCFG_MWRSIZE(0xff) | XSPI_BMCFG_PREEN, + 0 | XSPI_BMCFG_MWRCOMB | XSPI_BMCFG_MWRSIZE(0x0f) | + XSPI_BMCFG_PREEN); + + regmap_update_bits(xspi->regmap, XSPI_LIOCFGCS0, XSPI_LIOCFG_PRTMD(0x3ff), + XSPI_LIOCFG_PRTMD(xspi->proto)); + + memcpy_toio(xspi->dirmap + from, buf, writebytes); + + /* Request to push the pending data */ + if (writebytes < MWRSIZE_MAX) + regmap_update_bits(xspi->regmap, XSPI_BMCTL1, + XSPI_BMCTL1_MWRPUSH, XSPI_BMCTL1_MWRPUSH); + + pm_runtime_put(dev); + + return writebytes; +} +EXPORT_SYMBOL_GPL(xspi_dirmap_write); + static int rpcif_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -641,6 +1019,25 @@ static int rpcif_probe(struct platform_device *pdev) if (IS_ERR(rpc->rstc)) return PTR_ERR(rpc->rstc); + /* + * The enabling/disabling of spi/spix2 clocks at runtime leading to + * flash write failure. So, enable these clocks during probe() and + * disable it in remove(). + */ + if (rpc->info->type == XSPI_RZ_G3E) { + struct clk *spi_clk; + + spi_clk = devm_clk_get_enabled(dev, "spix2"); + if (IS_ERR(spi_clk)) + return dev_err_probe(dev, PTR_ERR(spi_clk), + "cannot get enabled spix2 clk\n"); + + spi_clk = devm_clk_get_enabled(dev, "spi"); + if (IS_ERR(spi_clk)) + return dev_err_probe(dev, PTR_ERR(spi_clk), + "cannot get enabled spi clk\n"); + } + vdev = platform_device_alloc(name, pdev->id); if (!vdev) return -ENOMEM; @@ -666,32 +1063,61 @@ static void rpcif_remove(struct platform_device *pdev) platform_device_unregister(rpc->vdev); } +struct rpcif_impl rpcif_impl = { + .hw_init = rpcif_hw_init_impl, + .prepare = rpcif_prepare_impl, + .manual_xfer = rpcif_manual_xfer_impl, + .dirmap_read = rpcif_dirmap_read_impl, + .status_reg = RPCIF_CMNSR, + .status_mask = RPCIF_CMNSR_TEND, +}; + +struct rpcif_impl xspi_impl = { + .hw_init = xspi_hw_init_impl, + .prepare = xspi_prepare_impl, + .manual_xfer = xspi_manual_xfer_impl, + .dirmap_read = xspi_dirmap_read_impl, + .status_reg = XSPI_INTS, + .status_mask = XSPI_INTS_CMDCMP, +}; + static const struct rpcif_info rpcif_info_r8a7796 = { .regmap_config = &rpcif_regmap_config, + .impl = &rpcif_impl, .type = RPCIF_RCAR_GEN3, .strtim = 6, }; static const struct rpcif_info rpcif_info_gen3 = { .regmap_config = &rpcif_regmap_config, + .impl = &rpcif_impl, .type = RPCIF_RCAR_GEN3, .strtim = 7, }; static const struct rpcif_info rpcif_info_rz_g2l = { .regmap_config = &rpcif_regmap_config, + .impl = &rpcif_impl, .type = RPCIF_RZ_G2L, .strtim = 7, }; static const struct rpcif_info rpcif_info_gen4 = { .regmap_config = &rpcif_regmap_config, + .impl = &rpcif_impl, .type = RPCIF_RCAR_GEN4, .strtim = 15, }; +static const struct rpcif_info xspi_info_r9a09g047 = { + .regmap_config = &xspi_regmap_config, + .impl = &xspi_impl, + .type = XSPI_RZ_G3E, +}; + static const struct of_device_id rpcif_of_match[] = { { .compatible = "renesas,r8a7796-rpc-if", .data = &rpcif_info_r8a7796 }, + { .compatible = "renesas,r9a09g047-xspi", .data = &xspi_info_r9a09g047 }, { .compatible = "renesas,rcar-gen3-rpc-if", .data = &rpcif_info_gen3 }, { .compatible = "renesas,rcar-gen4-rpc-if", .data = &rpcif_info_gen4 }, { .compatible = "renesas,rzg2l-rpc-if", .data = &rpcif_info_rz_g2l }, diff --git a/drivers/memory/renesas-xspi-if-regs.h b/drivers/memory/renesas-xspi-if-regs.h new file mode 100644 index 000000000000..53f801d591f2 --- /dev/null +++ b/drivers/memory/renesas-xspi-if-regs.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * RZ xSPI Interface Registers Definitions + * + * Copyright (C) 2025 Renesas Electronics Corporation + */ + +#ifndef __RENESAS_XSPI_IF_REGS_H__ +#define __RENESAS_XSPI_IF_REGS_H__ + +#include + +/* xSPI Wrapper Configuration Register */ +#define XSPI_WRAPCFG 0x0000 + +/* xSPI Bridge Configuration Register */ +#define XSPI_BMCFG 0x0008 +#define XSPI_BMCFG_WRMD BIT(0) +#define XSPI_BMCFG_MWRCOMB BIT(7) +#define XSPI_BMCFG_MWRSIZE(val) (((val) & 0xff) << 8) +#define XSPI_BMCFG_PREEN BIT(16) + +/* xSPI Command Map Configuration Register 0 CS0 */ +#define XSPI_CMCFG0CS0 0x0010 +#define XSPI_CMCFG0_FFMT(val) (((val) & 0x03) << 0) +#define XSPI_CMCFG0_ADDSIZE(val) (((val) & 0x03) << 2) + +/* xSPI Command Map Configuration Register 1 CS0 */ +#define XSPI_CMCFG1CS0 0x0014 +#define XSPI_CMCFG1_RDCMD(val) (((val) & 0xffff) << 0) +#define XSPI_CMCFG1_RDCMD_UPPER_BYTE(val) (((val) & 0xff) << 8) +#define XSPI_CMCFG1_RDLATE(val) (((val) & 0x1f) << 16) + +/* xSPI Command Map Configuration Register 2 CS0 */ +#define XSPI_CMCFG2CS0 0x0018 +#define XSPI_CMCFG2_WRCMD(val) (((val) & 0xffff) << 0) +#define XSPI_CMCFG2_WRCMD_UPPER(val) (((val) & 0xff) << 8) +#define XSPI_CMCFG2_WRLATE(val) (((val) & 0x1f) << 16) + +/* xSPI Link I/O Configuration Register CS0 */ +#define XSPI_LIOCFGCS0 0x0050 +#define XSPI_LIOCFG_PRTMD(val) (((val) & 0x3ff) << 0) +#define XSPI_LIOCFG_CSMIN(val) (((val) & 0x0f) << 16) +#define XSPI_LIOCFG_CSASTEX BIT(20) +#define XSPI_LIOCFG_CSNEGEX BIT(21) + +/* xSPI Bridge Map Control Register 0 */ +#define XSPI_BMCTL0 0x0060 +#define XSPI_BMCTL0_CS0ACC(val) (((val) & 0x03) << 0) + +/* xSPI Bridge Map Control Register 1 */ +#define XSPI_BMCTL1 0x0064 +#define XSPI_BMCTL1_MWRPUSH BIT(8) + +/* xSPI Command Manual Control Register 0 */ +#define XSPI_CDCTL0 0x0070 +#define XSPI_CDCTL0_TRREQ BIT(0) +#define XSPI_CDCTL0_CSSEL BIT(3) +#define XSPI_CDCTL0_TRNUM(val) (((val) & 0x03) << 4) + +/* xSPI Command Manual Type Buf */ +#define XSPI_CDTBUF0 0x0080 +#define XSPI_CDTBUF_CMDSIZE(val) (((val) & 0x03) << 0) +#define XSPI_CDTBUF_ADDSIZE(val) (((val) & 0x07) << 2) +#define XSPI_CDTBUF_DATASIZE(val) (((val) & 0x0f) << 5) +#define XSPI_CDTBUF_LATE(val) (((val) & 0x1f) << 9) +#define XSPI_CDTBUF_TRTYPE BIT(15) +#define XSPI_CDTBUF_CMD(val) (((val) & 0xffff) << 16) +#define XSPI_CDTBUF_CMD_FIELD(val) (((val) & 0xff) << 24) + +/* xSPI Command Manual Address Buff */ +#define XSPI_CDABUF0 0x0084 + +/* xSPI Command Manual Data 0 Buf */ +#define XSPI_CDD0BUF0 0x0088 + +/* xSPI Command Manual Data 1 Buf */ +#define XSPI_CDD1BUF0 0x008c + +/* xSPI Command Calibration Control Register 0 CS0 */ +#define XSPI_CCCTL0CS0 0x0130 +#define XSPI_CCCTL0_CAEN BIT(0) + +/* xSPI Interrupt Status Register */ +#define XSPI_INTS 0x0190 +#define XSPI_INTS_CMDCMP BIT(0) + +/* xSPI Interrupt Clear Register */ +#define XSPI_INTC 0x0194 +#define XSPI_INTC_CMDCMPC BIT(0) + +/* xSPI Interrupt Enable Register */ +#define XSPI_INTE 0x0198 +#define XSPI_INTE_CMDCMPE BIT(0) + +/* Maximum data size of MWRSIZE*/ +#define MWRSIZE_MAX 64 + +/* xSPI Protocol mode */ +#define PROTO_1S_2S_2S 0x48 +#define PROTO_2S_2S_2S 0x49 +#define PROTO_1S_4S_4S 0x090 +#define PROTO_4S_4S_4S 0x092 + +#endif /* __RENESAS_XSPI_IF_REGS_H__ */ diff --git a/include/memory/renesas-rpc-if.h b/include/memory/renesas-rpc-if.h index b8fa30fd6b50..53663c4e5ae3 100644 --- a/include/memory/renesas-rpc-if.h +++ b/include/memory/renesas-rpc-if.h @@ -61,12 +61,14 @@ enum rpcif_type { RPCIF_RCAR_GEN3, RPCIF_RCAR_GEN4, RPCIF_RZ_G2L, + XSPI_RZ_G3E, }; struct rpcif { struct device *dev; void __iomem *dirmap; size_t size; + bool xspi; }; int rpcif_sw_init(struct rpcif *rpc, struct device *dev); @@ -75,5 +77,7 @@ void rpcif_prepare(struct device *dev, const struct rpcif_op *op, u64 *offs, size_t *len); int rpcif_manual_xfer(struct device *dev); ssize_t rpcif_dirmap_read(struct device *dev, u64 offs, size_t len, void *buf); +ssize_t xspi_dirmap_write(struct device *dev, u64 offs, size_t len, + const void *buf); #endif // __RENESAS_RPC_IF_H -- 2.51.0 From 798dc3f19c9e3855c18c3afb610bc5d27195ef44 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 7 May 2025 17:21:44 +0100 Subject: [PATCH 15/16] memory: renesas-rpc-if: Add missing static keyword Fix the below sparse warnings: symbol 'rpcif_impl' was not declared. Should it be static? symbol 'xspi_impl' was not declared. Should it be static? Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202505072013.1EqwjtaR-lkp@intel.com/ Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20250507162146.140494-1-biju.das.jz@bp.renesas.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/renesas-rpc-if.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 4b2e903f2b0d..4a417b693080 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -1063,7 +1063,7 @@ static void rpcif_remove(struct platform_device *pdev) platform_device_unregister(rpc->vdev); } -struct rpcif_impl rpcif_impl = { +static const struct rpcif_impl rpcif_impl = { .hw_init = rpcif_hw_init_impl, .prepare = rpcif_prepare_impl, .manual_xfer = rpcif_manual_xfer_impl, @@ -1072,7 +1072,7 @@ struct rpcif_impl rpcif_impl = { .status_mask = RPCIF_CMNSR_TEND, }; -struct rpcif_impl xspi_impl = { +static const struct rpcif_impl xspi_impl = { .hw_init = xspi_hw_init_impl, .prepare = xspi_prepare_impl, .manual_xfer = xspi_manual_xfer_impl, -- 2.51.0 From b0b8d3aeadb5c49bf78305a1bc844e5a9378257c Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 24 Apr 2025 09:59:55 +0100 Subject: [PATCH 16/16] spi: rpc-if: Add write support for memory-mapped area Add write support for memory-mapped area as xSPI interface require it. Signed-off-by: Biju Das Link: https://patch.msgid.link/20250424090000.136804-8-biju.das.jz@bp.renesas.com Signed-off-by: Mark Brown --- drivers/spi/spi-rpc-if.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index e0c66a24a3cb..627cffea5d5c 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -75,6 +75,19 @@ static bool rpcif_spi_mem_supports_op(struct spi_mem *mem, return true; } +static ssize_t xspi_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, const void *buf) +{ + struct rpcif *rpc = spi_controller_get_devdata(desc->mem->spi->controller); + + if (offs + desc->info.offset + len > U32_MAX) + return -EINVAL; + + rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len); + + return xspi_dirmap_write(rpc->dev, offs, len, buf); +} + static ssize_t rpcif_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, void *buf) { @@ -103,7 +116,7 @@ static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) if (!rpc->dirmap) return -EOPNOTSUPP; - if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) + if (!rpc->xspi && desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) return -EOPNOTSUPP; return 0; @@ -125,6 +138,7 @@ static const struct spi_controller_mem_ops rpcif_spi_mem_ops = { .exec_op = rpcif_spi_mem_exec_op, .dirmap_create = rpcif_spi_mem_dirmap_create, .dirmap_read = rpcif_spi_mem_dirmap_read, + .dirmap_write = xspi_spi_mem_dirmap_write, }; static int rpcif_spi_probe(struct platform_device *pdev) -- 2.51.0