From d071004e623b7433573019d67cba79e345d83006 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 14 Nov 2024 15:59:44 +0800 Subject: [PATCH 01/16] tools/power turbostat: Consolidate graphics sysfs access Currently, there is an inconsistency in how graphics sysfs knobs are accessed: graphics residency sysfs knobs are opened and closed for each read, while graphics frequency sysfs knobs are opened once and remain open until turbostat exits. This inconsistency is confusing and adds unnecessary code complexity. Consolidate the access method by opening the sysfs files once and reusing the file pointers for subsequent accesses. This approach simplifies the code and ensures a consistent method for accessing graphics sysfs knobs. Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index c0596ccf92cd..e5b100b8db24 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -5764,27 +5764,24 @@ int snapshot_proc_interrupts(void) */ int snapshot_graphics(int idx) { - FILE *fp; int retval; + if (gfx_info[idx].fp == NULL) + gfx_info[idx].fp = fopen_or_die(gfx_info[idx].path, "r"); + else + rewind(gfx_info[idx].fp); + switch (idx) { case GFX_rc6: case SAM_mc6: - fp = fopen_or_die(gfx_info[idx].path, "r"); - retval = fscanf(fp, "%lld", &gfx_info[idx].val_ull); + retval = fscanf(gfx_info[idx].fp, "%lld", &gfx_info[idx].val_ull); if (retval != 1) err(1, "rc6"); - fclose(fp); return 0; case GFX_MHz: case GFX_ACTMHz: case SAM_MHz: case SAM_ACTMHz: - if (gfx_info[idx].fp == NULL) - gfx_info[idx].fp = fopen_or_die(gfx_info[idx].path, "r"); - else - rewind(gfx_info[idx].fp); - retval = fscanf(gfx_info[idx].fp, "%d", &gfx_info[idx].val); if (retval != 1) err(1, "MHz"); -- 2.51.0 From c7538f33853b11d0ff2a81efb78bde125d1fc49f Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 14 Nov 2024 15:59:45 +0800 Subject: [PATCH 02/16] tools/power turbostat: Cache graphics sysfs file descriptors during probe Snapshots of the graphics sysfs knobs are taken based on file descriptors. To optimize this process, open the files and cache the file descriptors during the graphics probe phase. As a result, the previously cached pathnames become redundant and are removed. This change aims to streamline the code without altering its functionality. No functional change intended. Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 82 +++++++++++---------------- 1 file changed, 32 insertions(+), 50 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index e5b100b8db24..28513172ffce 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -376,7 +376,6 @@ enum gfx_sysfs_idx { }; struct gfx_sysfs_info { - const char *path; FILE *fp; unsigned int val; unsigned long long val_ull; @@ -5766,10 +5765,7 @@ int snapshot_graphics(int idx) { int retval; - if (gfx_info[idx].fp == NULL) - gfx_info[idx].fp = fopen_or_die(gfx_info[idx].path, "r"); - else - rewind(gfx_info[idx].fp); + rewind(gfx_info[idx].fp); switch (idx) { case GFX_rc6: @@ -6474,6 +6470,12 @@ static void probe_intel_uncore_frequency(void) probe_intel_uncore_frequency_legacy(); } +static void set_graphics_fp(char *path, int idx) +{ + if (!access(path, R_OK)) + gfx_info[idx].fp = fopen_or_die(path, "r"); +} + static void probe_graphics(void) { /* Xe graphics sysfs knobs */ @@ -6481,7 +6483,6 @@ static void probe_graphics(void) FILE *fp; char buf[8]; bool gt0_is_gt; - int idx; fp = fopen("/sys/class/drm/card0/device/tile0/gt0/gtidle/name", "r"); if (!fp) @@ -6500,28 +6501,17 @@ static void probe_graphics(void) else goto next; - idx = gt0_is_gt ? GFX_rc6 : SAM_mc6; - gfx_info[idx].path = "/sys/class/drm/card0/device/tile0/gt0/gtidle/idle_residency_ms"; + set_graphics_fp("/sys/class/drm/card0/device/tile0/gt0/gtidle/idle_residency_ms", gt0_is_gt ? GFX_rc6 : SAM_mc6); - idx = gt0_is_gt ? GFX_MHz : SAM_MHz; - if (!access("/sys/class/drm/card0/device/tile0/gt0/freq0/cur_freq", R_OK)) - gfx_info[idx].path = "/sys/class/drm/card0/device/tile0/gt0/freq0/cur_freq"; + set_graphics_fp("/sys/class/drm/card0/device/tile0/gt0/freq0/cur_freq", gt0_is_gt ? GFX_MHz : SAM_MHz); - idx = gt0_is_gt ? GFX_ACTMHz : SAM_ACTMHz; - if (!access("/sys/class/drm/card0/device/tile0/gt0/freq0/act_freq", R_OK)) - gfx_info[idx].path = "/sys/class/drm/card0/device/tile0/gt0/freq0/act_freq"; + set_graphics_fp("/sys/class/drm/card0/device/tile0/gt0/freq0/act_freq", gt0_is_gt ? GFX_ACTMHz : SAM_ACTMHz); - idx = gt0_is_gt ? SAM_mc6 : GFX_rc6; - if (!access("/sys/class/drm/card0/device/tile0/gt1/gtidle/idle_residency_ms", R_OK)) - gfx_info[idx].path = "/sys/class/drm/card0/device/tile0/gt1/gtidle/idle_residency_ms"; + set_graphics_fp("/sys/class/drm/card0/device/tile0/gt1/gtidle/idle_residency_ms", gt0_is_gt ? SAM_mc6 : GFX_rc6); - idx = gt0_is_gt ? SAM_MHz : GFX_MHz; - if (!access("/sys/class/drm/card0/device/tile0/gt1/freq0/cur_freq", R_OK)) - gfx_info[idx].path = "/sys/class/drm/card0/device/tile0/gt1/freq0/cur_freq"; + set_graphics_fp("/sys/class/drm/card0/device/tile0/gt1/freq0/cur_freq", gt0_is_gt ? SAM_MHz : GFX_MHz); - idx = gt0_is_gt ? SAM_ACTMHz : GFX_ACTMHz; - if (!access("/sys/class/drm/card0/device/tile0/gt1/freq0/act_freq", R_OK)) - gfx_info[idx].path = "/sys/class/drm/card0/device/tile0/gt1/freq0/act_freq"; + set_graphics_fp("/sys/class/drm/card0/device/tile0/gt1/freq0/act_freq", gt0_is_gt ? SAM_ACTMHz : GFX_ACTMHz); goto end; } @@ -6529,52 +6519,44 @@ static void probe_graphics(void) next: /* New i915 graphics sysfs knobs */ if (!access("/sys/class/drm/card0/gt/gt0/rc6_residency_ms", R_OK)) { - gfx_info[GFX_rc6].path = "/sys/class/drm/card0/gt/gt0/rc6_residency_ms"; + set_graphics_fp("/sys/class/drm/card0/gt/gt0/rc6_residency_ms", GFX_rc6); - if (!access("/sys/class/drm/card0/gt/gt0/rps_cur_freq_mhz", R_OK)) - gfx_info[GFX_MHz].path = "/sys/class/drm/card0/gt/gt0/rps_cur_freq_mhz"; + set_graphics_fp("/sys/class/drm/card0/gt/gt0/rps_cur_freq_mhz", GFX_MHz); - if (!access("/sys/class/drm/card0/gt/gt0/rps_act_freq_mhz", R_OK)) - gfx_info[GFX_ACTMHz].path = "/sys/class/drm/card0/gt/gt0/rps_act_freq_mhz"; + set_graphics_fp("/sys/class/drm/card0/gt/gt0/rps_act_freq_mhz", GFX_ACTMHz); - if (!access("/sys/class/drm/card0/gt/gt1/rc6_residency_ms", R_OK)) - gfx_info[SAM_mc6].path = "/sys/class/drm/card0/gt/gt1/rc6_residency_ms"; + set_graphics_fp("/sys/class/drm/card0/gt/gt1/rc6_residency_ms", SAM_mc6); - if (!access("/sys/class/drm/card0/gt/gt1/rps_cur_freq_mhz", R_OK)) - gfx_info[SAM_MHz].path = "/sys/class/drm/card0/gt/gt1/rps_cur_freq_mhz"; + set_graphics_fp("/sys/class/drm/card0/gt/gt1/rps_cur_freq_mhz", SAM_MHz); - if (!access("/sys/class/drm/card0/gt/gt1/rps_act_freq_mhz", R_OK)) - gfx_info[SAM_ACTMHz].path = "/sys/class/drm/card0/gt/gt1/rps_act_freq_mhz"; + set_graphics_fp("/sys/class/drm/card0/gt/gt1/rps_act_freq_mhz", SAM_ACTMHz); goto end; } /* Fall back to traditional i915 graphics sysfs knobs */ - if (!access("/sys/class/drm/card0/power/rc6_residency_ms", R_OK)) - gfx_info[GFX_rc6].path = "/sys/class/drm/card0/power/rc6_residency_ms"; + set_graphics_fp("/sys/class/drm/card0/power/rc6_residency_ms", GFX_rc6); - if (!access("/sys/class/drm/card0/gt_cur_freq_mhz", R_OK)) - gfx_info[GFX_MHz].path = "/sys/class/drm/card0/gt_cur_freq_mhz"; - else if (!access("/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz", R_OK)) - gfx_info[GFX_MHz].path = "/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz"; + set_graphics_fp("/sys/class/drm/card0/gt_cur_freq_mhz", GFX_MHz); + if (!gfx_info[GFX_MHz].fp) + set_graphics_fp("/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz", GFX_MHz); - if (!access("/sys/class/drm/card0/gt_act_freq_mhz", R_OK)) - gfx_info[GFX_ACTMHz].path = "/sys/class/drm/card0/gt_act_freq_mhz"; - else if (!access("/sys/class/graphics/fb0/device/drm/card0/gt_act_freq_mhz", R_OK)) - gfx_info[GFX_ACTMHz].path = "/sys/class/graphics/fb0/device/drm/card0/gt_act_freq_mhz"; + set_graphics_fp("/sys/class/drm/card0/gt_act_freq_mhz", GFX_ACTMHz); + if (!gfx_info[GFX_ACTMHz].fp) + set_graphics_fp("/sys/class/graphics/fb0/device/drm/card0/gt_act_freq_mhz", GFX_ACTMHz); end: - if (gfx_info[GFX_rc6].path) + if (gfx_info[GFX_rc6].fp) BIC_PRESENT(BIC_GFX_rc6); - if (gfx_info[GFX_MHz].path) + if (gfx_info[GFX_MHz].fp) BIC_PRESENT(BIC_GFXMHz); - if (gfx_info[GFX_ACTMHz].path) + if (gfx_info[GFX_ACTMHz].fp) BIC_PRESENT(BIC_GFXACTMHz); - if (gfx_info[SAM_mc6].path) + if (gfx_info[SAM_mc6].fp) BIC_PRESENT(BIC_SAM_mc6); - if (gfx_info[SAM_MHz].path) + if (gfx_info[SAM_MHz].fp) BIC_PRESENT(BIC_SAMMHz); - if (gfx_info[SAM_ACTMHz].path) + if (gfx_info[SAM_ACTMHz].fp) BIC_PRESENT(BIC_SAMACTMHz); } -- 2.51.0 From 03109e2f0d18dcb84218bd91c4fbf864193ca934 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 14 Nov 2024 15:59:46 +0800 Subject: [PATCH 03/16] tools/power turbostat: Add support for /sys/class/drm/card1 On some machines, the graphics device is enumerated as /sys/class/drm/card1 instead of /sys/class/drm/card0. The current implementation does not handle this scenario, resulting in the loss of graphics C6 residency and frequency information. Add support for /sys/class/drm/card1, ensuring that turbostat can retrieve and display the graphics columns for these platforms. Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 38 ++++++++++++++++++++------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 28513172ffce..b250676c174e 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -6476,8 +6476,14 @@ static void set_graphics_fp(char *path, int idx) gfx_info[idx].fp = fopen_or_die(path, "r"); } +/* Enlarge this if there are /sys/class/drm/card2 ... */ +#define GFX_MAX_CARDS 2 + static void probe_graphics(void) { + char path[PATH_MAX]; + int i; + /* Xe graphics sysfs knobs */ if (!access("/sys/class/drm/card0/device/tile0/gt0/gtidle/idle_residency_ms", R_OK)) { FILE *fp; @@ -6518,22 +6524,36 @@ static void probe_graphics(void) next: /* New i915 graphics sysfs knobs */ - if (!access("/sys/class/drm/card0/gt/gt0/rc6_residency_ms", R_OK)) { - set_graphics_fp("/sys/class/drm/card0/gt/gt0/rc6_residency_ms", GFX_rc6); + for (i = 0; i < GFX_MAX_CARDS; i++) { + snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt0/rc6_residency_ms", i); + if (!access(path, R_OK)) + break; + } - set_graphics_fp("/sys/class/drm/card0/gt/gt0/rps_cur_freq_mhz", GFX_MHz); + if (i == GFX_MAX_CARDS) + goto legacy_i915; - set_graphics_fp("/sys/class/drm/card0/gt/gt0/rps_act_freq_mhz", GFX_ACTMHz); + snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt0/rc6_residency_ms", i); + set_graphics_fp(path, GFX_rc6); - set_graphics_fp("/sys/class/drm/card0/gt/gt1/rc6_residency_ms", SAM_mc6); + snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt0/rps_cur_freq_mhz", i); + set_graphics_fp(path, GFX_MHz); - set_graphics_fp("/sys/class/drm/card0/gt/gt1/rps_cur_freq_mhz", SAM_MHz); + snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt0/rps_act_freq_mhz", i); + set_graphics_fp(path, GFX_ACTMHz); - set_graphics_fp("/sys/class/drm/card0/gt/gt1/rps_act_freq_mhz", SAM_ACTMHz); + snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt1/rc6_residency_ms", i); + set_graphics_fp(path, SAM_mc6); - goto end; - } + snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt1/rps_cur_freq_mhz", i); + set_graphics_fp(path, SAM_MHz); + + snprintf(path, PATH_MAX, "/sys/class/drm/card%d/gt/gt1/rps_act_freq_mhz", i); + set_graphics_fp(path, SAM_ACTMHz); + + goto end; +legacy_i915: /* Fall back to traditional i915 graphics sysfs knobs */ set_graphics_fp("/sys/class/drm/card0/power/rc6_residency_ms", GFX_rc6); -- 2.51.0 From bcfab87108b33f20d847fd71a2a93114dd2ce83e Mon Sep 17 00:00:00 2001 From: Patryk Wlazlyn Date: Thu, 24 Oct 2024 15:17:45 +0200 Subject: [PATCH 04/16] tools/power turbostat: Force --no-perf in --dump mode Force the --no-perf early to prevent using it as a source. User asks for raw values, but perf returns them relative to the opening of the file descriptor. Signed-off-by: Patryk Wlazlyn Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index b250676c174e..1fed799a5537 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -9897,6 +9897,12 @@ void cmdline(int argc, char **argv) break; case 'D': dump_only++; + /* + * Force the no_perf early to prevent using it as a source. + * User asks for raw values, but perf returns them relative + * to the opening of the file descriptor. + */ + no_perf = 1; break; case 'e': /* --enable specified counter */ -- 2.51.0 From 1da0daf746342dfdc114e4dc8fbf3ece28666d4f Mon Sep 17 00:00:00 2001 From: Patryk Wlazlyn Date: Wed, 13 Nov 2024 15:48:22 +0100 Subject: [PATCH 05/16] tools/power turbostat: Fix child's argument forwarding Add '+' to optstring when early scanning for --no-msr and --no-perf. It causes option processing to stop as soon as a nonoption argument is encountered, effectively skipping child's arguments. Fixes: 3e4048466c39 ("tools/power turbostat: Add --no-msr option") Signed-off-by: Patryk Wlazlyn 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 1fed799a5537..9025c2945737 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -9873,7 +9873,7 @@ void cmdline(int argc, char **argv) * Parse some options early, because they may make other options invalid, * like adding the MSR counter with --add and at the same time using --no-msr. */ - while ((opt = getopt_long_only(argc, argv, "MPn:", long_options, &option_index)) != -1) { + while ((opt = getopt_long_only(argc, argv, "+MPn:", long_options, &option_index)) != -1) { switch (opt) { case 'M': no_msr = 1; -- 2.51.0 From e5f687b89bc2a892256f48e14a568970b59a4812 Mon Sep 17 00:00:00 2001 From: Patryk Wlazlyn Date: Wed, 2 Oct 2024 15:05:15 +0200 Subject: [PATCH 06/16] tools/power turbostat: Add RAPL psys as a built-in counter Introduce the counter as a part of global, platform counters structure. We open the counter for only one cpu, but otherwise treat it as an ordinary RAPL counter, allowing for grouped perf read. The counter is disabled by default, because it's interpretation may require additional, platform specific information, making it unsuitable for general use. Signed-off-by: Patryk Wlazlyn Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.8 | 2 + tools/power/x86/turbostat/turbostat.c | 93 ++++++++++++++++++++++++--- 2 files changed, 85 insertions(+), 10 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index 56c7ff6efcda..95eb02346d3a 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 @@ -190,6 +190,8 @@ The system configuration dump (if --quiet is not used) is followed by statistics .PP \fBRAMWatt\fP Watts consumed by the DRAM DIMMS -- available only on server processors. .PP +\fBSysWatt\fP Watts consumed by the whole platform (RAPL PSYS). Disabled by default. May require platform specific information to interpret the data, making it not suitable for general use. +.PP \fBPKG_%\fP percent of the interval that RAPL throttling was active on the Package. Note that the system summary is the sum of the package throttling time, and thus may be higher than 100% on a multi-package system. Note that the meaning of this field is model specific. For example, some hardware increments this counter when RAPL responds to thermal limits, but does not increment this counter when RAPL responds to power limits. Comparing PkgWatt and PkgTmp to system limits is necessary. .PP \fBRAM_%\fP percent of the interval that RAPL throttling was active on DRAM. diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 9025c2945737..88c7f896c5b2 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -200,6 +200,8 @@ struct msr_counter bic[] = { { 0x0, "SAMMHz", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "SAMAMHz", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "Die%c6", NULL, 0, 0, 0, NULL, 0 }, + { 0x0, "SysWatt", NULL, 0, 0, 0, NULL, 0 }, + { 0x0, "Sys_J", NULL, 0, 0, 0, NULL, 0 }, }; #define MAX_BIC (sizeof(bic) / sizeof(struct msr_counter)) @@ -262,6 +264,8 @@ struct msr_counter bic[] = { #define BIC_SAMMHz (1ULL << 56) #define BIC_SAMACTMHz (1ULL << 57) #define BIC_Diec6 (1ULL << 58) +#define BIC_SysWatt (1ULL << 59) +#define BIC_Sys_J (1ULL << 60) #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__) @@ -269,7 +273,7 @@ struct msr_counter bic[] = { #define BIC_IDLE (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_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_SysWatt | BIC_Sys_J) 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; @@ -507,12 +511,15 @@ enum rapl_msrs { RAPL_AMD_PWR_UNIT = BIT(14), /* 0xc0010299 MSR_AMD_RAPL_POWER_UNIT */ RAPL_AMD_CORE_ENERGY_STAT = BIT(15), /* 0xc001029a MSR_AMD_CORE_ENERGY_STATUS */ RAPL_AMD_PKG_ENERGY_STAT = BIT(16), /* 0xc001029b MSR_AMD_PKG_ENERGY_STATUS */ + RAPL_PLATFORM_ENERGY_LIMIT = BIT(17), /* 0x64c MSR_PLATFORM_ENERGY_LIMIT */ + RAPL_PLATFORM_ENERGY_STATUS = BIT(18), /* 0x64d MSR_PLATFORM_ENERGY_STATUS */ }; #define RAPL_PKG (RAPL_PKG_ENERGY_STATUS | RAPL_PKG_POWER_LIMIT) #define RAPL_DRAM (RAPL_DRAM_ENERGY_STATUS | RAPL_DRAM_POWER_LIMIT) #define RAPL_CORE (RAPL_CORE_ENERGY_STATUS | RAPL_CORE_POWER_LIMIT) #define RAPL_GFX (RAPL_GFX_POWER_LIMIT | RAPL_GFX_ENERGY_STATUS) +#define RAPL_PSYS (RAPL_PLATFORM_ENERGY_STATUS | RAPL_PLATFORM_ENERGY_LIMIT) #define RAPL_PKG_ALL (RAPL_PKG | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO) #define RAPL_DRAM_ALL (RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_DRAM_POWER_INFO) @@ -713,7 +720,7 @@ static const struct platform_features skl_features = { .has_ext_cst_msrs = 1, .trl_msrs = TRL_BASE, .tcc_offset_bits = 6, - .rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_GFX, + .rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_GFX | RAPL_PSYS, .enable_tsc_tweak = 1, }; @@ -730,7 +737,7 @@ static const struct platform_features cnl_features = { .has_ext_cst_msrs = 1, .trl_msrs = TRL_BASE, .tcc_offset_bits = 6, - .rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_GFX, + .rapl_msrs = RAPL_PKG_ALL | RAPL_CORE_ALL | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_GFX | RAPL_PSYS, .enable_tsc_tweak = 1, }; @@ -797,7 +804,7 @@ static const struct platform_features icx_features = { .has_irtl_msrs = 1, .has_cst_prewake_bit = 1, .trl_msrs = TRL_BASE | TRL_CORECOUNT, - .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, + .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_PSYS, .has_fixed_rapl_unit = 1, }; @@ -813,7 +820,7 @@ static const struct platform_features spr_features = { .has_irtl_msrs = 1, .has_cst_prewake_bit = 1, .trl_msrs = TRL_BASE | TRL_CORECOUNT, - .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, + .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_PSYS, }; static const struct platform_features srf_features = { @@ -829,7 +836,7 @@ static const struct platform_features srf_features = { .has_irtl_msrs = 1, .has_cst_prewake_bit = 1, .trl_msrs = TRL_BASE | TRL_CORECOUNT, - .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, + .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_PSYS, }; static const struct platform_features grr_features = { @@ -845,7 +852,7 @@ static const struct platform_features grr_features = { .has_irtl_msrs = 1, .has_cst_prewake_bit = 1, .trl_msrs = TRL_BASE | TRL_CORECOUNT, - .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL, + .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_PSYS, }; static const struct platform_features slv_features = { @@ -1108,6 +1115,7 @@ enum rapl_rci_index { RAPL_RCI_INDEX_PKG_PERF_STATUS = 4, RAPL_RCI_INDEX_DRAM_PERF_STATUS = 5, RAPL_RCI_INDEX_CORE_ENERGY = 6, + RAPL_RCI_INDEX_ENERGY_PLATFORM = 7, NUM_RAPL_COUNTERS, }; @@ -1134,6 +1142,7 @@ struct rapl_counter_info_t { struct rapl_counter_info_t *rapl_counter_info_perdomain; unsigned int rapl_counter_info_perdomain_size; +#define RAPL_COUNTER_FLAG_PLATFORM_COUNTER (1u << 0) #define RAPL_COUNTER_FLAG_USE_MSR_SUM (1u << 1) struct rapl_counter_arch_info { @@ -1255,6 +1264,19 @@ static const struct rapl_counter_arch_info rapl_counter_arch_infos[] = { .compat_scale = 1.0, .flags = 0, }, + { + .feature_mask = RAPL_PSYS, + .perf_subsys = "power", + .perf_name = "energy-psys", + .msr = MSR_PLATFORM_ENERGY_STATUS, + .msr_mask = 0x00000000FFFFFFFF, + .msr_shift = 0, + .platform_rapl_msr_scale = &rapl_energy_units, + .rci_index = RAPL_RCI_INDEX_ENERGY_PLATFORM, + .bic = BIC_SysWatt | BIC_Sys_J, + .compat_scale = 1.0, + .flags = RAPL_COUNTER_FLAG_PLATFORM_COUNTER | RAPL_COUNTER_FLAG_USE_MSR_SUM, + }, }; struct rapl_counter { @@ -1682,6 +1704,7 @@ enum { IDX_PP1_ENERGY, IDX_PKG_PERF, IDX_DRAM_PERF, + IDX_PSYS_ENERGY, IDX_COUNT, }; @@ -1726,6 +1749,9 @@ off_t idx_to_offset(int idx) case IDX_DRAM_PERF: offset = MSR_DRAM_PERF_STATUS; break; + case IDX_PSYS_ENERGY: + offset = MSR_PLATFORM_ENERGY_STATUS; + break; default: offset = -1; } @@ -1756,6 +1782,9 @@ int offset_to_idx(off_t offset) case MSR_DRAM_PERF_STATUS: idx = IDX_DRAM_PERF; break; + case MSR_PLATFORM_ENERGY_STATUS: + idx = IDX_PSYS_ENERGY; + break; default: idx = -1; } @@ -1777,6 +1806,8 @@ int idx_valid(int idx) return platform->rapl_msrs & RAPL_PKG_PERF_STATUS; case IDX_DRAM_PERF: return platform->rapl_msrs & RAPL_DRAM_PERF_STATUS; + case IDX_PSYS_ENERGY: + return platform->rapl_msrs & RAPL_PSYS; default: return 0; } @@ -1848,6 +1879,10 @@ struct system_summary { struct pkg_data packages; } average; +struct platform_counters { + struct rapl_counter energy_psys; /* MSR_PLATFORM_ENERGY_STATUS */ +} platform_counters_odd, platform_counters_even; + struct cpu_topology { int physical_package_id; int die_id; @@ -2512,6 +2547,11 @@ void print_header(char *delim) ppmt = ppmt->next; } + if (DO_BIC(BIC_SysWatt)) + outp += sprintf(outp, "%sSysWatt", (printed++ ? delim : "")); + if (DO_BIC(BIC_Sys_J)) + outp += sprintf(outp, "%sSys_J", (printed++ ? delim : "")); + outp += sprintf(outp, "\n"); } @@ -2519,6 +2559,7 @@ int dump_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p { int i; struct msr_counter *mp; + struct platform_counters *pplat_cnt = p == package_odd ? &platform_counters_odd : &platform_counters_even; outp += sprintf(outp, "t %p, c %p, p %p\n", t, c, p); @@ -2590,6 +2631,7 @@ int dump_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p outp += sprintf(outp, "Joules COR: %0llX\n", p->energy_cores.raw_value); outp += sprintf(outp, "Joules GFX: %0llX\n", p->energy_gfx.raw_value); outp += sprintf(outp, "Joules RAM: %0llX\n", p->energy_dram.raw_value); + outp += sprintf(outp, "Joules PSYS: %0llX\n", pplat_cnt->energy_psys.raw_value); outp += sprintf(outp, "Throttle PKG: %0llX\n", p->rapl_pkg_perf_status.raw_value); outp += sprintf(outp, "Throttle RAM: %0llX\n", p->rapl_dram_perf_status.raw_value); outp += sprintf(outp, "PTM: %dC\n", p->pkg_temp_c); @@ -2628,6 +2670,9 @@ double rapl_counter_get_value(const struct rapl_counter *c, enum rapl_unit desir */ int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) { + static int count; + + struct platform_counters *pplat_cnt = NULL; double interval_float, tsc; char *fmt8; int i; @@ -2637,6 +2682,11 @@ int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data char *delim = "\t"; int printed = 0; + if (t == &average.threads) { + pplat_cnt = count & 1 ? &platform_counters_odd : &platform_counters_even; + ++count; + } + /* if showing only 1st thread in core and this isn't one, bail out */ if (show_core_only && !is_cpu_first_thread_in_core(t, c, p)) return 0; @@ -3093,6 +3143,13 @@ int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data } } + if (DO_BIC(BIC_SysWatt) && (t == &average.threads)) + outp += sprintf(outp, fmt8, (printed++ ? delim : ""), + rapl_counter_get_value(&pplat_cnt->energy_psys, RAPL_UNIT_WATTS, interval_float)); + if (DO_BIC(BIC_Sys_J) && (t == &average.threads)) + outp += sprintf(outp, fmt8, (printed++ ? delim : ""), + rapl_counter_get_value(&pplat_cnt->energy_psys, RAPL_UNIT_JOULES, interval_float)); + done: if (*(outp - 1) != '\n') outp += sprintf(outp, "\n"); @@ -3400,6 +3457,11 @@ int delta_cpu(struct thread_data *t, struct core_data *c, return retval; } +void delta_platform(struct platform_counters *new, struct platform_counters *old) +{ + old->energy_psys.raw_value = new->energy_psys.raw_value - old->energy_psys.raw_value; +} + void rapl_counter_clear(struct rapl_counter *c) { c->raw_value = 0; @@ -4129,6 +4191,9 @@ static size_t cstate_counter_info_count_perf(const struct cstate_counter_info_t void write_rapl_counter(struct rapl_counter *rc, struct rapl_counter_info_t *rci, unsigned int idx) { + if (rci->source[idx] == COUNTER_SOURCE_NONE) + return; + rc->raw_value = rci->data[idx]; rc->unit = rci->unit[idx]; rc->scale = rci->scale[idx]; @@ -4136,6 +4201,7 @@ void write_rapl_counter(struct rapl_counter *rc, struct rapl_counter_info_t *rci int get_rapl_counters(int cpu, unsigned int domain, struct core_data *c, struct pkg_data *p) { + struct platform_counters *pplat_cnt = p == package_odd ? &platform_counters_odd : &platform_counters_even; unsigned long long perf_data[NUM_RAPL_COUNTERS + 1]; struct rapl_counter_info_t *rci; @@ -4163,6 +4229,7 @@ int get_rapl_counters(int cpu, unsigned int domain, struct core_data *c, struct for (unsigned int i = 0, pi = 1; i < NUM_RAPL_COUNTERS; ++i) { switch (rci->source[i]) { case COUNTER_SOURCE_NONE: + rci->data[i] = 0; break; case COUNTER_SOURCE_PERF: @@ -4201,7 +4268,7 @@ int get_rapl_counters(int cpu, unsigned int domain, struct core_data *c, struct } } - BUILD_BUG_ON(NUM_RAPL_COUNTERS != 7); + BUILD_BUG_ON(NUM_RAPL_COUNTERS != 8); write_rapl_counter(&p->energy_pkg, rci, RAPL_RCI_INDEX_ENERGY_PKG); write_rapl_counter(&p->energy_cores, rci, RAPL_RCI_INDEX_ENERGY_CORES); write_rapl_counter(&p->energy_dram, rci, RAPL_RCI_INDEX_DRAM); @@ -4209,6 +4276,7 @@ int get_rapl_counters(int cpu, unsigned int domain, struct core_data *c, struct write_rapl_counter(&p->rapl_pkg_perf_status, rci, RAPL_RCI_INDEX_PKG_PERF_STATUS); write_rapl_counter(&p->rapl_dram_perf_status, rci, RAPL_RCI_INDEX_DRAM_PERF_STATUS); write_rapl_counter(&c->core_energy, rci, RAPL_RCI_INDEX_CORE_ENERGY); + write_rapl_counter(&pplat_cnt->energy_psys, rci, RAPL_RCI_INDEX_ENERGY_PLATFORM); return 0; } @@ -6144,6 +6212,7 @@ restart: re_initialize(); goto restart; } + delta_platform(&platform_counters_odd, &platform_counters_even); compute_average(EVEN_COUNTERS); format_all_counters(EVEN_COUNTERS); flush_output_stdout(); @@ -6167,6 +6236,7 @@ restart: re_initialize(); goto restart; } + delta_platform(&platform_counters_even, &platform_counters_odd); compute_average(ODD_COUNTERS); format_all_counters(ODD_COUNTERS); flush_output_stdout(); @@ -6945,8 +7015,8 @@ void rapl_probe_intel(void) unsigned long long msr; unsigned int time_unit; double tdp; - const unsigned long long bic_watt_bits = BIC_PkgWatt | BIC_CorWatt | BIC_RAMWatt | BIC_GFXWatt; - const unsigned long long bic_joules_bits = BIC_Pkg_J | BIC_Cor_J | BIC_RAM_J | BIC_GFX_J; + const unsigned long long bic_watt_bits = BIC_SysWatt | BIC_PkgWatt | BIC_CorWatt | BIC_RAMWatt | BIC_GFXWatt; + const unsigned long long bic_joules_bits = BIC_Sys_J | BIC_Pkg_J | BIC_Cor_J | BIC_RAM_J | BIC_GFX_J; if (rapl_joules) bic_enabled &= ~bic_watt_bits; @@ -7606,6 +7676,9 @@ void rapl_perf_init(void) domain_visited[next_domain] = 1; + if ((cai->flags & RAPL_COUNTER_FLAG_PLATFORM_COUNTER) && (cpu != base_cpu)) + continue; + struct rapl_counter_info_t *rci = &rapl_counter_info_perdomain[next_domain]; /* Check if the counter is enabled and accessible */ -- 2.51.0 From 86d237734091201d2ab2c1d2e1063893621c770f Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sat, 30 Nov 2024 16:22:00 -0500 Subject: [PATCH 07/16] tools/power turbostat: 2024.11.30 since 2024.07.26: assorted minor bug fixes assorted platform specific tweaks initial RAPL PSYS (SysWatt) support Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.8 | 2 +- tools/power/x86/turbostat/turbostat.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index 95eb02346d3a..a7f7ed01421c 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 @@ -190,7 +190,7 @@ The system configuration dump (if --quiet is not used) is followed by statistics .PP \fBRAMWatt\fP Watts consumed by the DRAM DIMMS -- available only on server processors. .PP -\fBSysWatt\fP Watts consumed by the whole platform (RAPL PSYS). Disabled by default. May require platform specific information to interpret the data, making it not suitable for general use. +\fBSysWatt\fP Watts consumed by the whole platform (RAPL PSYS). Disabled by default. Enable with --enable SysWatt. .PP \fBPKG_%\fP percent of the interval that RAPL throttling was active on the Package. Note that the system summary is the sum of the package throttling time, and thus may be higher than 100% on a multi-package system. Note that the meaning of this field is model specific. For example, some hardware increments this counter when RAPL responds to thermal limits, but does not increment this counter when RAPL responds to power limits. Comparing PkgWatt and PkgTmp to system limits is necessary. .PP diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 88c7f896c5b2..58a487c225a7 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -9236,7 +9236,7 @@ int get_and_dump_counters(void) void print_version() { - fprintf(outf, "turbostat version 2024.07.26 - Len Brown \n"); + fprintf(outf, "turbostat version 2024.11.30 - Len Brown \n"); } #define COMMAND_LINE_SIZE 2048 -- 2.51.0 From f69e63756f7822fcdad8a34f9967e8b243e883ee Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 2 Oct 2024 18:31:47 +0100 Subject: [PATCH 08/16] printf: Remove unused 'bprintf' bprintf() is unused. Remove it. It was added in the commit 4370aa4aa753 ("vsprintf: add binary printf") but as far as I can see was never used, unlike the other two functions in that patch. Link: https://lore.kernel.org/20241002173147.210107-1-linux@treblig.org Reviewed-by: Andy Shevchenko Acked-by: Petr Mladek Signed-off-by: Dr. David Alan Gilbert Signed-off-by: Steven Rostedt (Google) --- include/linux/string.h | 1 - lib/vsprintf.c | 23 ----------------------- 2 files changed, 24 deletions(-) diff --git a/include/linux/string.h b/include/linux/string.h index 0dd27afcfaf7..493ac4862c77 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -335,7 +335,6 @@ int __sysfs_match_string(const char * const *array, size_t n, const char *s); #ifdef CONFIG_BINARY_PRINTF int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args); int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf); -int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) __printf(3, 4); #endif extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 6ac02bbb7df1..9d3dac38a3f4 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -3428,29 +3428,6 @@ out: } EXPORT_SYMBOL_GPL(bstr_printf); -/** - * bprintf - Parse a format string and place args' binary value in a buffer - * @bin_buf: The buffer to place args' binary value - * @size: The size of the buffer(by words(32bits), not characters) - * @fmt: The format string to use - * @...: Arguments for the format string - * - * The function returns the number of words(u32) written - * into @bin_buf. - */ -int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) -{ - va_list args; - int ret; - - va_start(args, fmt); - ret = vbin_printf(bin_buf, size, fmt, args); - va_end(args); - - return ret; -} -EXPORT_SYMBOL_GPL(bprintf); - #endif /* CONFIG_BINARY_PRINTF */ /** -- 2.51.0 From 9022ed0e7e65734d83a0648648589b9fbea8e8c9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 1 Dec 2024 09:23:33 -0800 Subject: [PATCH 09/16] strscpy: write destination buffer only once The point behind strscpy() was to once and for all avoid all the problems with 'strncpy()' and later broken "fixed" versions like strlcpy() that just made things worse. So strscpy not only guarantees NUL-termination (unlike strncpy), it also doesn't do unnecessary padding at the destination. But at the same time also avoids byte-at-a-time reads and writes by _allowing_ some extra NUL writes - within the size, of course - so that the whole copy can be done with word operations. It is also stable in the face of a mutable source string: it explicitly does not read the source buffer multiple times (so an implementation using "strnlen()+memcpy()" would be wrong), and does not read the source buffer past the size (like the mis-design that is strlcpy does). Finally, the return value is designed to be simple and unambiguous: if the string cannot be copied fully, it returns an actual negative error, making error handling clearer and simpler (and the caller already knows the size of the buffer). Otherwise it returns the string length of the result. However, there was one final stability issue that can be important to callers: the stability of the destination buffer. In particular, the same way we shouldn't read the source buffer more than once, we should avoid doing multiple writes to the destination buffer: first writing a potentially non-terminated string, and then terminating it with NUL at the end does not result in a stable result buffer. Yes, it gives the right result in the end, but if the rule for the destination buffer was that it is _always_ NUL-terminated even when accessed concurrently with updates, the final byte of the buffer needs to always _stay_ as a NUL byte. [ Note that "final byte is NUL" here is literally about the final byte in the destination array, not the terminating NUL at the end of the string itself. There is no attempt to try to make concurrent reads and writes give any kind of consistent string length or contents, but we do want to guarantee that there is always at least that final terminating NUL character at the end of the destination array if it existed before ] This is relevant in the kernel for the tsk->comm[] array, for example. Even without locking (for either readers or writers), we want to know that while the buffer contents may be garbled, it is always a valid C string and always has a NUL character at 'comm[TASK_COMM_LEN-1]' (and never has any "out of thin air" data). So avoid any "copy possibly non-terminated string, and terminate later" behavior, and write the destination buffer only once. Signed-off-by: Linus Torvalds --- lib/string.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/string.c b/lib/string.c index 76327b51e36f..eb4486ed40d2 100644 --- a/lib/string.c +++ b/lib/string.c @@ -104,6 +104,12 @@ char *strncpy(char *dest, const char *src, size_t count) EXPORT_SYMBOL(strncpy); #endif +#ifdef __BIG_ENDIAN +# define ALLBUTLAST_BYTE_MASK (~255ul) +#else +# define ALLBUTLAST_BYTE_MASK (~0ul >> 8) +#endif + ssize_t sized_strscpy(char *dest, const char *src, size_t count) { const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; @@ -147,13 +153,18 @@ ssize_t sized_strscpy(char *dest, const char *src, size_t count) *(unsigned long *)(dest+res) = c & zero_bytemask(data); return res + find_zero(data); } + count -= sizeof(unsigned long); + if (unlikely(!count)) { + c &= ALLBUTLAST_BYTE_MASK; + *(unsigned long *)(dest+res) = c; + return -E2BIG; + } *(unsigned long *)(dest+res) = c; res += sizeof(unsigned long); - count -= sizeof(unsigned long); max -= sizeof(unsigned long); } - while (count) { + while (count > 1) { char c; c = src[res]; @@ -164,11 +175,11 @@ ssize_t sized_strscpy(char *dest, const char *src, size_t count) count--; } - /* Hit buffer length without finding a NUL; force NUL-termination. */ - if (res) - dest[res-1] = '\0'; + /* Force NUL-termination. */ + dest[res] = '\0'; - return -E2BIG; + /* Return E2BIG if the source didn't stop */ + return src[res] ? -E2BIG : res; } EXPORT_SYMBOL(sized_strscpy); -- 2.51.0 From 40384c840ea1944d7c5a392e8975ed088ecf0b37 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 1 Dec 2024 14:28:56 -0800 Subject: [PATCH 10/16] Linux 6.13-rc1 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index e34a97473fb6..93ab62cef244 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 -PATCHLEVEL = 12 +PATCHLEVEL = 13 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc1 NAME = Baby Opossum Posse # *DOCUMENTATION* -- 2.51.0 From f4d3d7340e719dd3d2c23ce8d6c360e2f93ba7e4 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Tue, 22 Oct 2024 17:22:52 +0530 Subject: [PATCH 11/16] dt-bindings: clock: qcom: Add QCS615 GCC clocks Add device tree bindings for global clock controller on QCS615 SoCs. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Taniya Das Link: https://lore.kernel.org/r/20241022-qcs615-clock-driver-v4-3-3d716ad0d987@quicinc.com Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,qcs615-gcc.yaml | 59 +++++ include/dt-bindings/clock/qcom,qcs615-gcc.h | 211 ++++++++++++++++++ 2 files changed, 270 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,qcs615-gcc.yaml create mode 100644 include/dt-bindings/clock/qcom,qcs615-gcc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,qcs615-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,qcs615-gcc.yaml new file mode 100644 index 000000000000..4a828e102d25 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,qcs615-gcc.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,qcs615-gcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller on QCS615 + +maintainers: + - Taniya Das + +description: | + Qualcomm global clock control module provides the clocks, resets and power + domains on QCS615. + + See also: include/dt-bindings/clock/qcom,qcs615-gcc.h + +properties: + compatible: + const: qcom,qcs615-gcc + + clocks: + items: + - description: Board XO source + - description: Board active XO source + - description: Sleep clock source + + clock-names: + items: + - const: bi_tcxo + - const: bi_tcxo_ao + - const: sleep_clk + +required: + - compatible + - clocks + - clock-names + - '#power-domain-cells' + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + clock-controller@100000 { + compatible = "qcom,qcs615-gcc"; + reg = <0x00100000 0x1f0000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>; + clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk"; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; +... diff --git a/include/dt-bindings/clock/qcom,qcs615-gcc.h b/include/dt-bindings/clock/qcom,qcs615-gcc.h new file mode 100644 index 000000000000..9704091636b8 --- /dev/null +++ b/include/dt-bindings/clock/qcom,qcs615-gcc.h @@ -0,0 +1,211 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_GCC_QCS615_H +#define _DT_BINDINGS_CLK_QCOM_GCC_QCS615_H + +/* GCC clocks */ +#define GPLL0_OUT_AUX2_DIV 0 +#define GPLL3_OUT_AUX2_DIV 1 +#define GPLL0 2 +#define GPLL3 3 +#define GPLL4 4 +#define GPLL6 5 +#define GPLL6_OUT_MAIN 6 +#define GPLL7 7 +#define GPLL8 8 +#define GPLL8_OUT_MAIN 9 +#define GCC_AGGRE_UFS_PHY_AXI_CLK 10 +#define GCC_AGGRE_USB2_SEC_AXI_CLK 11 +#define GCC_AGGRE_USB3_PRIM_AXI_CLK 12 +#define GCC_AHB2PHY_EAST_CLK 13 +#define GCC_AHB2PHY_WEST_CLK 14 +#define GCC_BOOT_ROM_AHB_CLK 15 +#define GCC_CAMERA_AHB_CLK 16 +#define GCC_CAMERA_HF_AXI_CLK 17 +#define GCC_CAMERA_XO_CLK 18 +#define GCC_CE1_AHB_CLK 19 +#define GCC_CE1_AXI_CLK 20 +#define GCC_CE1_CLK 21 +#define GCC_CFG_NOC_USB2_SEC_AXI_CLK 22 +#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 23 +#define GCC_CPUSS_AHB_CLK 24 +#define GCC_CPUSS_AHB_CLK_SRC 25 +#define GCC_CPUSS_GNOC_CLK 26 +#define GCC_DDRSS_GPU_AXI_CLK 27 +#define GCC_DISP_AHB_CLK 28 +#define GCC_DISP_GPLL0_DIV_CLK_SRC 29 +#define GCC_DISP_HF_AXI_CLK 30 +#define GCC_DISP_XO_CLK 31 +#define GCC_EMAC_AXI_CLK 32 +#define GCC_EMAC_PTP_CLK 33 +#define GCC_EMAC_PTP_CLK_SRC 34 +#define GCC_EMAC_RGMII_CLK 35 +#define GCC_EMAC_RGMII_CLK_SRC 36 +#define GCC_EMAC_SLV_AHB_CLK 37 +#define GCC_GP1_CLK 38 +#define GCC_GP1_CLK_SRC 39 +#define GCC_GP2_CLK 40 +#define GCC_GP2_CLK_SRC 41 +#define GCC_GP3_CLK 42 +#define GCC_GP3_CLK_SRC 43 +#define GCC_GPU_CFG_AHB_CLK 44 +#define GCC_GPU_GPLL0_CLK_SRC 45 +#define GCC_GPU_GPLL0_DIV_CLK_SRC 46 +#define GCC_GPU_IREF_CLK 47 +#define GCC_GPU_MEMNOC_GFX_CLK 48 +#define GCC_GPU_SNOC_DVM_GFX_CLK 49 +#define GCC_PCIE0_PHY_REFGEN_CLK 50 +#define GCC_PCIE_0_AUX_CLK 51 +#define GCC_PCIE_0_AUX_CLK_SRC 52 +#define GCC_PCIE_0_CFG_AHB_CLK 53 +#define GCC_PCIE_0_CLKREF_CLK 54 +#define GCC_PCIE_0_MSTR_AXI_CLK 55 +#define GCC_PCIE_0_PIPE_CLK 56 +#define GCC_PCIE_0_SLV_AXI_CLK 57 +#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 58 +#define GCC_PCIE_PHY_AUX_CLK 59 +#define GCC_PCIE_PHY_REFGEN_CLK_SRC 60 +#define GCC_PDM2_CLK 61 +#define GCC_PDM2_CLK_SRC 62 +#define GCC_PDM_AHB_CLK 63 +#define GCC_PDM_XO4_CLK 64 +#define GCC_PRNG_AHB_CLK 65 +#define GCC_QMIP_CAMERA_NRT_AHB_CLK 66 +#define GCC_QMIP_DISP_AHB_CLK 67 +#define GCC_QMIP_PCIE_AHB_CLK 68 +#define GCC_QMIP_VIDEO_VCODEC_AHB_CLK 69 +#define GCC_QSPI_CNOC_PERIPH_AHB_CLK 70 +#define GCC_QSPI_CORE_CLK 71 +#define GCC_QSPI_CORE_CLK_SRC 72 +#define GCC_QUPV3_WRAP0_CORE_2X_CLK 73 +#define GCC_QUPV3_WRAP0_CORE_CLK 74 +#define GCC_QUPV3_WRAP0_S0_CLK 75 +#define GCC_QUPV3_WRAP0_S0_CLK_SRC 76 +#define GCC_QUPV3_WRAP0_S1_CLK 77 +#define GCC_QUPV3_WRAP0_S1_CLK_SRC 78 +#define GCC_QUPV3_WRAP0_S2_CLK 79 +#define GCC_QUPV3_WRAP0_S2_CLK_SRC 80 +#define GCC_QUPV3_WRAP0_S3_CLK 81 +#define GCC_QUPV3_WRAP0_S3_CLK_SRC 82 +#define GCC_QUPV3_WRAP0_S4_CLK 83 +#define GCC_QUPV3_WRAP0_S4_CLK_SRC 84 +#define GCC_QUPV3_WRAP0_S5_CLK 85 +#define GCC_QUPV3_WRAP0_S5_CLK_SRC 86 +#define GCC_QUPV3_WRAP1_CORE_2X_CLK 87 +#define GCC_QUPV3_WRAP1_CORE_CLK 88 +#define GCC_QUPV3_WRAP1_S0_CLK 89 +#define GCC_QUPV3_WRAP1_S0_CLK_SRC 90 +#define GCC_QUPV3_WRAP1_S1_CLK 91 +#define GCC_QUPV3_WRAP1_S1_CLK_SRC 92 +#define GCC_QUPV3_WRAP1_S2_CLK 93 +#define GCC_QUPV3_WRAP1_S2_CLK_SRC 94 +#define GCC_QUPV3_WRAP1_S3_CLK 95 +#define GCC_QUPV3_WRAP1_S3_CLK_SRC 96 +#define GCC_QUPV3_WRAP1_S4_CLK 97 +#define GCC_QUPV3_WRAP1_S4_CLK_SRC 98 +#define GCC_QUPV3_WRAP1_S5_CLK 99 +#define GCC_QUPV3_WRAP1_S5_CLK_SRC 100 +#define GCC_QUPV3_WRAP_0_M_AHB_CLK 101 +#define GCC_QUPV3_WRAP_0_S_AHB_CLK 102 +#define GCC_QUPV3_WRAP_1_M_AHB_CLK 103 +#define GCC_QUPV3_WRAP_1_S_AHB_CLK 104 +#define GCC_RX1_USB2_CLKREF_CLK 105 +#define GCC_RX3_USB2_CLKREF_CLK 106 +#define GCC_SDCC1_AHB_CLK 107 +#define GCC_SDCC1_APPS_CLK 108 +#define GCC_SDCC1_APPS_CLK_SRC 109 +#define GCC_SDCC1_ICE_CORE_CLK 110 +#define GCC_SDCC1_ICE_CORE_CLK_SRC 111 +#define GCC_SDCC2_AHB_CLK 112 +#define GCC_SDCC2_APPS_CLK 113 +#define GCC_SDCC2_APPS_CLK_SRC 114 +#define GCC_SDR_CORE_CLK 115 +#define GCC_SDR_CSR_HCLK 116 +#define GCC_SDR_PRI_MI2S_CLK 117 +#define GCC_SDR_SEC_MI2S_CLK 118 +#define GCC_SDR_WR0_MEM_CLK 119 +#define GCC_SDR_WR1_MEM_CLK 120 +#define GCC_SDR_WR2_MEM_CLK 121 +#define GCC_SYS_NOC_CPUSS_AHB_CLK 122 +#define GCC_UFS_CARD_CLKREF_CLK 123 +#define GCC_UFS_MEM_CLKREF_CLK 124 +#define GCC_UFS_PHY_AHB_CLK 125 +#define GCC_UFS_PHY_AXI_CLK 126 +#define GCC_UFS_PHY_AXI_CLK_SRC 127 +#define GCC_UFS_PHY_ICE_CORE_CLK 128 +#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 129 +#define GCC_UFS_PHY_PHY_AUX_CLK 130 +#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 131 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 132 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 133 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK 134 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 135 +#define GCC_USB20_SEC_MASTER_CLK 136 +#define GCC_USB20_SEC_MASTER_CLK_SRC 137 +#define GCC_USB20_SEC_MOCK_UTMI_CLK 138 +#define GCC_USB20_SEC_MOCK_UTMI_CLK_SRC 139 +#define GCC_USB20_SEC_SLEEP_CLK 140 +#define GCC_USB2_PRIM_CLKREF_CLK 141 +#define GCC_USB2_SEC_CLKREF_CLK 142 +#define GCC_USB2_SEC_PHY_AUX_CLK 143 +#define GCC_USB2_SEC_PHY_AUX_CLK_SRC 144 +#define GCC_USB2_SEC_PHY_COM_AUX_CLK 145 +#define GCC_USB2_SEC_PHY_PIPE_CLK 146 +#define GCC_USB30_PRIM_MASTER_CLK 147 +#define GCC_USB30_PRIM_MASTER_CLK_SRC 148 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK 149 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 150 +#define GCC_USB30_PRIM_SLEEP_CLK 151 +#define GCC_USB3_PRIM_CLKREF_CLK 152 +#define GCC_USB3_PRIM_PHY_AUX_CLK 153 +#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 154 +#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 155 +#define GCC_USB3_PRIM_PHY_PIPE_CLK 156 +#define GCC_USB3_SEC_CLKREF_CLK 157 +#define GCC_VIDEO_AHB_CLK 158 +#define GCC_VIDEO_AXI0_CLK 159 +#define GCC_VIDEO_XO_CLK 160 +#define GCC_VSENSOR_CLK_SRC 161 +#define GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK 162 +#define GCC_UFS_PHY_AXI_HW_CTL_CLK 163 +#define GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK 164 +#define GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK 165 +#define GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK 166 + +/* GCC Resets */ +#define GCC_EMAC_BCR 0 +#define GCC_QUSB2PHY_PRIM_BCR 1 +#define GCC_QUSB2PHY_SEC_BCR 2 +#define GCC_USB30_PRIM_BCR 3 +#define GCC_USB2_PHY_SEC_BCR 4 +#define GCC_USB3_DP_PHY_SEC_BCR 5 +#define GCC_USB3PHY_PHY_SEC_BCR 6 +#define GCC_PCIE_0_BCR 7 +#define GCC_PCIE_0_PHY_BCR 8 +#define GCC_PCIE_PHY_BCR 9 +#define GCC_PCIE_PHY_COM_BCR 10 +#define GCC_UFS_PHY_BCR 11 +#define GCC_USB20_SEC_BCR 12 +#define GCC_USB3_PHY_PRIM_SP0_BCR 13 +#define GCC_USB3PHY_PHY_PRIM_SP0_BCR 14 +#define GCC_SDCC1_BCR 15 +#define GCC_SDCC2_BCR 16 + +/* GCC power domains */ +#define EMAC_GDSC 0 +#define PCIE_0_GDSC 1 +#define UFS_PHY_GDSC 2 +#define USB20_SEC_GDSC 3 +#define USB30_PRIM_GDSC 4 +#define HLOS1_VOTE_AGGRE_NOC_MMU_AUDIO_TBU_GDSC 5 +#define HLOS1_VOTE_AGGRE_NOC_MMU_TBU1_GDSC 6 +#define HLOS1_VOTE_AGGRE_NOC_MMU_TBU2_GDSC 7 +#define HLOS1_VOTE_AGGRE_NOC_MMU_PCIE_TBU_GDSC 8 +#define HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC 9 +#define HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC 10 +#define HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC 11 + +#endif -- 2.51.0 From 2a5711c7dc6f20e132f99b13731952bdb3530acf Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 17 Aug 2024 11:46:04 +0200 Subject: [PATCH 12/16] dt-bindings: clock: qcom,sc7280-lpasscorecc: order properties to match convention By convention we expect first "compatible", then "reg" and then rest. Order properties to match convention and what is in "required:" block. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240817094605.27185-1-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- .../clock/qcom,sc7280-lpasscorecc.yaml | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/qcom,sc7280-lpasscorecc.yaml b/Documentation/devicetree/bindings/clock/qcom,sc7280-lpasscorecc.yaml index deee5423d66e..5e6737c39897 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sc7280-lpasscorecc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sc7280-lpasscorecc.yaml @@ -18,12 +18,6 @@ description: | include/dt-bindings/clock/qcom,lpassaudiocc-sc7280.h properties: - clocks: true - - clock-names: true - - reg: true - compatible: enum: - qcom,sc7280-lpassaoncc @@ -31,12 +25,18 @@ properties: - qcom,sc7280-lpasscorecc - qcom,sc7280-lpasshm - power-domains: - maxItems: 1 + reg: true + + clocks: true + + clock-names: true '#clock-cells': const: 1 + power-domains: + maxItems: 1 + '#power-domain-cells': const: 1 @@ -57,8 +57,6 @@ required: - '#clock-cells' - '#power-domain-cells' -additionalProperties: false - allOf: - if: properties: @@ -125,6 +123,9 @@ allOf: reg: maxItems: 1 + +additionalProperties: false + examples: - | #include -- 2.51.0 From 9d40c5a698de6ba629f2abc8dd43b8a2db469307 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 17 Aug 2024 11:46:05 +0200 Subject: [PATCH 13/16] dt-bindings: clock: qcom,sc7280-lpasscorecc: add top-level constraints Properties with variable number of items per each device are expected to have widest constraints in top-level "properties:" block and further customized (narrowed) in "if:then:". Add missing top-level constraints for reg, clocks and clock-names. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240817094605.27185-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,sc7280-lpasscorecc.yaml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/qcom,sc7280-lpasscorecc.yaml b/Documentation/devicetree/bindings/clock/qcom,sc7280-lpasscorecc.yaml index 5e6737c39897..488d63959424 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sc7280-lpasscorecc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sc7280-lpasscorecc.yaml @@ -25,11 +25,17 @@ properties: - qcom,sc7280-lpasscorecc - qcom,sc7280-lpasshm - reg: true + reg: + minItems: 1 + maxItems: 2 - clocks: true + clocks: + minItems: 1 + maxItems: 3 - clock-names: true + clock-names: + minItems: 1 + maxItems: 3 '#clock-cells': const: 1 -- 2.51.0 From e8f81b561360d45832cfd546a1ce566745d184d9 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 21 Dec 2024 13:24:10 +0100 Subject: [PATCH 14/16] dt-bindings: clock: qcom,x1e80100-gpucc: Extend for X1P42100 To make it easier for X1P4 and X1E to share a common device tree base, extend the existing latter's GPUCC bindings and reuse them on the former platform. While not in the same file, it only makes sense to introduce the new compatible in this commit as well. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20241221-topic-x1p4_clk-v1-2-dbaeccb74884@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,sm8450-gpucc.yaml | 1 + include/dt-bindings/clock/qcom,x1e80100-gpucc.h | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml index 5c65f5ecf0f3..02968632fb3a 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml @@ -32,6 +32,7 @@ properties: - qcom,sm8550-gpucc - qcom,sm8650-gpucc - qcom,x1e80100-gpucc + - qcom,x1p42100-gpucc clocks: items: diff --git a/include/dt-bindings/clock/qcom,x1e80100-gpucc.h b/include/dt-bindings/clock/qcom,x1e80100-gpucc.h index 61a3a8f3ac43..27b8f50541fd 100644 --- a/include/dt-bindings/clock/qcom,x1e80100-gpucc.h +++ b/include/dt-bindings/clock/qcom,x1e80100-gpucc.h @@ -33,9 +33,22 @@ #define GPU_CC_SLEEP_CLK 23 #define GPU_CC_XO_CLK_SRC 24 #define GPU_CC_XO_DIV_CLK_SRC 25 +#define GPU_CC_CX_ACCU_SHIFT_CLK 26 +#define GPU_CC_GX_ACCU_SHIFT_CLK 27 /* GDSCs */ #define GPU_CX_GDSC 0 #define GPU_GX_GDSC 1 +/* GPU_CC resets */ +#define GPU_CC_ACD_BCR 0 +#define GPU_CC_CB_BCR 1 +#define GPU_CC_CX_BCR 2 +#define GPU_CC_FAST_HUB_BCR 3 +#define GPU_CC_FF_BCR 4 +#define GPU_CC_GFX3D_AON_BCR 5 +#define GPU_CC_GMU_BCR 6 +#define GPU_CC_GX_BCR 7 +#define GPU_CC_XO_BCR 8 + #endif -- 2.51.0 From 089c09ee12317def57ab6a5159269315743083e3 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 21 Dec 2024 13:24:09 +0100 Subject: [PATCH 15/16] dt-bindings: clock: qcom,x1e80100-gcc: Add X1P42100 X1P42100 is based on X1E80100 and largely reuses the X1E80100's GCC block, adding a couple wires here and there. Add a compatible for the X1P4 with a fallback to X1E80100. There are some additions in the smaller one, that will be added in the future. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20241221-topic-x1p4_clk-v1-1-dbaeccb74884@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/clock/qcom,x1e80100-gcc.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/qcom,x1e80100-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,x1e80100-gcc.yaml index 5951a60ab081..28797d0c5d8d 100644 --- a/Documentation/devicetree/bindings/clock/qcom,x1e80100-gcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,x1e80100-gcc.yaml @@ -17,7 +17,11 @@ description: | properties: compatible: - const: qcom,x1e80100-gcc + oneOf: + - items: + - const: qcom,x1p42100-gcc + - const: qcom,x1e80100-gcc + - const: qcom,x1e80100-gcc clocks: items: -- 2.51.0 From 99c21c7ca6423913783ea50e2c16be3cc097f17b Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 21 Dec 2024 13:24:11 +0100 Subject: [PATCH 16/16] clk: qcom: Add X1P42100 GPUCC driver The 8-core X1s have a different GPU subsystem compared to their bigger cousins, including the clocks part. Add the GPU clock controller driver to drive these. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20241221-topic-x1p4_clk-v1-3-dbaeccb74884@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gpucc-x1p42100.c | 587 ++++++++++++++++++++++++++++++ 3 files changed, 597 insertions(+) create mode 100644 drivers/clk/qcom/gpucc-x1p42100.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index ef89d686cbc4..32b34b22ef01 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -64,6 +64,15 @@ config CLK_X1E80100_TCSRCC Support for the TCSR clock controller on X1E80100 devices. Say Y if you want to use peripheral devices such as SD/UFS. +config CLK_X1P42100_GPUCC + tristate "X1P42100 Graphics Clock Controller" + depends on ARM64 || COMPILE_TEST + select CLK_X1E8010_GCC + help + Support for the graphics clock controller on X1P42100 devices. + Say Y if you want to support graphics controller devices and + functionality such as 3D graphics. + config CLK_QCM2290_GPUCC tristate "QCM2290 Graphics Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index b09dbdc210eb..7b5dd918c705 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_CLK_X1E80100_DISPCC) += dispcc-x1e80100.o obj-$(CONFIG_CLK_X1E80100_GCC) += gcc-x1e80100.o obj-$(CONFIG_CLK_X1E80100_GPUCC) += gpucc-x1e80100.o obj-$(CONFIG_CLK_X1E80100_TCSRCC) += tcsrcc-x1e80100.o +obj-$(CONFIG_CLK_X1P42100_GPUCC) += gpucc-x1p42100.o obj-$(CONFIG_CLK_QCM2290_GPUCC) += gpucc-qcm2290.o obj-$(CONFIG_IPQ_APSS_PLL) += apss-ipq-pll.o obj-$(CONFIG_IPQ_APSS_6018) += apss-ipq6018.o diff --git a/drivers/clk/qcom/gpucc-x1p42100.c b/drivers/clk/qcom/gpucc-x1p42100.c new file mode 100644 index 000000000000..dba783339613 --- /dev/null +++ b/drivers/clk/qcom/gpucc-x1p42100.c @@ -0,0 +1,587 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_GPLL0_OUT_MAIN, + DT_GPLL0_OUT_MAIN_DIV, +}; + +enum { + P_BI_TCXO, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_GPU_CC_PLL0_OUT_MAIN, + P_GPU_CC_PLL1_OUT_MAIN, +}; + +static const struct pll_vco lucid_ole_vco[] = { + { 249600000, 2300000000, 0 }, +}; + +/* 560.0 MHz Configuration */ +static const struct alpha_pll_config gpu_cc_pll0_config = { + .l = 0x1d, + .alpha = 0x2aaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll gpu_cc_pll0 = { + .offset = 0x0, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_pll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +/* 440.0 MHz Configuration */ +static const struct alpha_pll_config gpu_cc_pll1_config = { + .l = 0x16, + .alpha = 0xeaaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll gpu_cc_pll1 = { + .offset = 0x1000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_pll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct parent_map gpu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .index = DT_GPLL0_OUT_MAIN }, + { .index = DT_GPLL0_OUT_MAIN_DIV }, +}; + +static const struct parent_map gpu_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_MAIN, 1 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpu_cc_pll0.clkr.hw }, + { .hw = &gpu_cc_pll1.clkr.hw }, + { .index = DT_GPLL0_OUT_MAIN }, + { .index = DT_GPLL0_OUT_MAIN_DIV }, +}; + +static const struct parent_map gpu_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpu_cc_pll1.clkr.hw }, + { .index = DT_GPLL0_OUT_MAIN }, + { .index = DT_GPLL0_OUT_MAIN_DIV }, +}; + +static const struct freq_tbl ftbl_gpu_cc_ff_clk_src[] = { + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_ff_clk_src = { + .cmd_rcgr = 0x9474, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_0, + .freq_tbl = ftbl_gpu_cc_ff_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_ff_clk_src", + .parent_data = gpu_cc_parent_data_0, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(220000000, P_GPU_CC_PLL1_OUT_MAIN, 2, 0, 0), + F(550000000, P_GPU_CC_PLL1_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .cmd_rcgr = 0x9318, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_1, + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_gmu_clk_src", + .parent_data = gpu_cc_parent_data_1, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gpu_cc_hub_clk_src = { + .cmd_rcgr = 0x93ec, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_2, + .freq_tbl = ftbl_gpu_cc_ff_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_hub_clk_src", + .parent_data = gpu_cc_parent_data_2, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_branch gpu_cc_ahb_clk = { + .halt_reg = 0x911c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x911c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_crc_ahb_clk = { + .halt_reg = 0x9120, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9120, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_crc_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_accu_shift_clk = { + .halt_reg = 0x9480, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9480, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_cx_accu_shift_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_ff_clk = { + .halt_reg = 0x914c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x914c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_cx_ff_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpu_cc_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x913c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x913c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_cx_gmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpu_cc_gmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_clk = { + .halt_reg = 0x9144, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9144, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_freq_measure_clk = { + .halt_reg = 0x9008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_freq_measure_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_accu_shift_clk = { + .halt_reg = 0x947c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x947c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_gx_accu_shift_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gmu_clk = { + .halt_reg = 0x90bc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x90bc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_gx_gmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpu_cc_gmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_vsense_clk = { + .halt_reg = 0x90b0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x90b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_gx_vsense_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hub_aon_clk = { + .halt_reg = 0x93e8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x93e8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_hub_aon_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hub_cx_int_clk = { + .halt_reg = 0x9148, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9148, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_hub_cx_int_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_memnoc_gfx_clk = { + .halt_reg = 0x9150, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9150, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_memnoc_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_mnd1x_0_gfx3d_clk = { + .halt_reg = 0x9288, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9288, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_mnd1x_0_gfx3d_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_mnd1x_1_gfx3d_clk = { + .halt_reg = 0x928c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x928c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_mnd1x_1_gfx3d_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_sleep_clk = { + .halt_reg = 0x9134, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9134, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gpu_cc_cx_gdsc = { + .gdscr = 0x9108, + .gds_hw_ctrl = 0x953c, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gpu_cc_cx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gpu_cc_gx_gdsc = { + .gdscr = 0x905c, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gpu_cc_gx_gdsc", + .power_on = gdsc_gx_do_nothing_enable, + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = CLAMP_IO | POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct clk_regmap *gpu_cc_x1p42100_clocks[] = { + [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr, + [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, + [GPU_CC_CX_ACCU_SHIFT_CLK] = &gpu_cc_cx_accu_shift_clk.clkr, + [GPU_CC_CX_FF_CLK] = &gpu_cc_cx_ff_clk.clkr, + [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, + [GPU_CC_FF_CLK_SRC] = &gpu_cc_ff_clk_src.clkr, + [GPU_CC_FREQ_MEASURE_CLK] = &gpu_cc_freq_measure_clk.clkr, + [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, + [GPU_CC_GX_ACCU_SHIFT_CLK] = &gpu_cc_gx_accu_shift_clk.clkr, + [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, + [GPU_CC_GX_VSENSE_CLK] = &gpu_cc_gx_vsense_clk.clkr, + [GPU_CC_HUB_AON_CLK] = &gpu_cc_hub_aon_clk.clkr, + [GPU_CC_HUB_CLK_SRC] = &gpu_cc_hub_clk_src.clkr, + [GPU_CC_HUB_CX_INT_CLK] = &gpu_cc_hub_cx_int_clk.clkr, + [GPU_CC_MEMNOC_GFX_CLK] = &gpu_cc_memnoc_gfx_clk.clkr, + [GPU_CC_MND1X_0_GFX3D_CLK] = &gpu_cc_mnd1x_0_gfx3d_clk.clkr, + [GPU_CC_MND1X_1_GFX3D_CLK] = &gpu_cc_mnd1x_1_gfx3d_clk.clkr, + [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, + [GPU_CC_PLL1] = &gpu_cc_pll1.clkr, + [GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr, +}; + +static struct gdsc *gpu_cc_x1p42100_gdscs[] = { + [GPU_CX_GDSC] = &gpu_cc_cx_gdsc, + [GPU_GX_GDSC] = &gpu_cc_gx_gdsc, +}; + +static const struct qcom_reset_map gpu_cc_x1p42100_resets[] = { + [GPU_CC_ACD_BCR] = { 0x9358 }, + [GPU_CC_CB_BCR] = { 0x93a0 }, + [GPU_CC_CX_BCR] = { 0x9104 }, + [GPU_CC_FAST_HUB_BCR] = { 0x93e4 }, + [GPU_CC_FF_BCR] = { 0x9470 }, + [GPU_CC_GFX3D_AON_BCR] = { 0x9198 }, + [GPU_CC_GMU_BCR] = { 0x9314 }, + [GPU_CC_GX_BCR] = { 0x9058 }, + [GPU_CC_XO_BCR] = { 0x9000 }, +}; + +static const struct regmap_config gpu_cc_x1p42100_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x9988, + .fast_io = true, +}; + +static struct qcom_cc_desc gpu_cc_x1p42100_desc = { + .config = &gpu_cc_x1p42100_regmap_config, + .clks = gpu_cc_x1p42100_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_x1p42100_clocks), + .resets = gpu_cc_x1p42100_resets, + .num_resets = ARRAY_SIZE(gpu_cc_x1p42100_resets), + .gdscs = gpu_cc_x1p42100_gdscs, + .num_gdscs = ARRAY_SIZE(gpu_cc_x1p42100_gdscs), +}; + +static const struct of_device_id gpu_cc_x1p42100_match_table[] = { + { .compatible = "qcom,x1p42100-gpucc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpu_cc_x1p42100_match_table); + +static int gpu_cc_x1p42100_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) + return ret; + + regmap = qcom_cc_map(pdev, &gpu_cc_x1p42100_desc); + if (IS_ERR(regmap)) { + pm_runtime_put(&pdev->dev); + return PTR_ERR(regmap); + } + + clk_lucid_ole_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); + clk_lucid_ole_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + + /* Keep some clocks always enabled */ + qcom_branch_set_clk_en(regmap, 0x93a4); /* GPU_CC_CB_CLK */ + qcom_branch_set_clk_en(regmap, 0x9004); /* GPU_CC_CXO_AON_CLK */ + qcom_branch_set_clk_en(regmap, 0x900c); /* GPU_CC_DEMET_CLK */ + + ret = qcom_cc_really_probe(&pdev->dev, &gpu_cc_x1p42100_desc, regmap); + + pm_runtime_put(&pdev->dev); + + return ret; +} + +static struct platform_driver gpu_cc_x1p42100_driver = { + .probe = gpu_cc_x1p42100_probe, + .driver = { + .name = "gpucc-x1p42100", + .of_match_table = gpu_cc_x1p42100_match_table, + }, +}; + +module_platform_driver(gpu_cc_x1p42100_driver); + +MODULE_DESCRIPTION("QTI GPUCC X1P42100 Driver"); +MODULE_LICENSE("GPL"); -- 2.51.0