* [PATCH 1/5] media: synopsys: Add support for RAW16 Bayer formats
From: Guoniu Zhou @ 2026-04-15 3:46 UTC (permalink / raw)
To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Laurent Pinchart, Frank Li
Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
linux-rockchip, Guoniu Zhou
In-Reply-To: <20260415-csi2_imx95-v1-0-7d63f3508719@oss.nxp.com>
This enables the driver to handle higher bit-depth raw image data
from image sensors that support 16-bit output.
Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index ce17f986279e..46e2a4315ac2 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -252,6 +252,26 @@ static const struct dw_mipi_csi2rx_format formats[] = {
.depth = 12,
.csi_dt = MIPI_CSI2_DT_RAW12,
},
+ {
+ .code = MEDIA_BUS_FMT_SBGGR16_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RAW16,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGBRG16_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RAW16,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGRBG16_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RAW16,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SRGGB16_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RAW16,
+ },
};
static inline struct dw_mipi_csi2rx_device *to_csi2(struct v4l2_subdev *sd)
--
2.34.1
^ permalink raw reply related
* [PATCH 0/5] media: synopsys: enhancements and i.MX95 support
From: Guoniu Zhou @ 2026-04-15 3:46 UTC (permalink / raw)
To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Laurent Pinchart, Frank Li
Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
linux-rockchip, Guoniu Zhou
This series enhances the Synopsys DesignWare MIPI CSI-2 receiver driver
with multiple stream support and adds i.MX95 platform support.
The i.MX95 variant is similar to i.MX93 but uses IDI instead of IPI. Since
IDI is software transparent, only a different register map is needed.
Tested on i.MX93 and i.MX95 platforms.
Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
Guoniu Zhou (5):
media: synopsys: Add support for RAW16 Bayer formats
media: synopsys: Add support for multiple streams
media: synopsys: Add PHY stopstate wait for i.MX93
media: dt-bindings: add NXP i.MX95 compatible string
media: synopsys: Add support for i.MX95
.../bindings/media/rockchip,rk3568-mipi-csi2.yaml | 5 +-
drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 125 ++++++++++++++++++---
2 files changed, 111 insertions(+), 19 deletions(-)
---
base-commit: 4fbeef21f5387234111b5d52924e77757626faa5
change-id: 20260414-csi2_imx95-65ad0e7f630a
Best regards,
--
Guoniu Zhou <guoniu.zhou@oss.nxp.com>
^ permalink raw reply
* [PATCH RFC v3 11/11] ACPI: RISC-V: Add support for RISC-V Quality of Service Controller (RQSC)
From: Drew Fustini @ 2026-04-15 1:54 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Drew Fustini
Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
devicetree, Paul Walmsley
In-Reply-To: <20260414-ssqosid-cbqri-rqsc-v7-0-v3-0-b3b2e7e9847a@kernel.org>
Call acpi_parse_rqsc() from acpi_arch_init() to discover CBQRI
controllers when an RQSC table is present. The RQSC table is optional;
AE_NOT_FOUND is silenced since many systems will not have QoS
controllers. Other ACPI failures are reported as errors.
Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
drivers/acpi/riscv/init.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/drivers/acpi/riscv/init.c b/drivers/acpi/riscv/init.c
index 7c00f7995e86..8a74dff42dce 100644
--- a/drivers/acpi/riscv/init.c
+++ b/drivers/acpi/riscv/init.c
@@ -4,12 +4,35 @@
* Author: Sunil V L <sunilvl@ventanamicro.com>
*/
+#define pr_fmt(fmt) "ACPI: RQSC: " fmt
+
#include <linux/acpi.h>
#include "init.h"
void __init acpi_arch_init(void)
{
+ struct acpi_table_header *rqsc;
+ acpi_status status;
+ int rc;
+
riscv_acpi_init_gsi_mapping();
+
if (IS_ENABLED(CONFIG_ACPI_RIMT))
riscv_acpi_rimt_init();
+
+ if (IS_ENABLED(CONFIG_RISCV_ISA_SSQOSID) && !acpi_disabled) {
+ status = acpi_get_table(ACPI_SIG_RQSC, 0, &rqsc);
+ if (status == AE_NOT_FOUND) {
+ /* RQSC is optional; silence on systems without it */
+ } else if (ACPI_FAILURE(status)) {
+ pr_err("failed to get ACPI RQSC table: %s\n",
+ acpi_format_exception(status));
+ } else {
+ rc = acpi_parse_rqsc(rqsc);
+ if (rc < 0)
+ pr_err("failed to parse ACPI RQSC table: %d\n",
+ rc);
+ acpi_put_table(rqsc);
+ }
+ }
}
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v3 10/11] ACPI: RISC-V: Parse RISC-V Quality of Service Controller (RQSC) table
From: Drew Fustini @ 2026-04-15 1:54 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Drew Fustini
Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
devicetree, Paul Walmsley
In-Reply-To: <20260414-ssqosid-cbqri-rqsc-v7-0-v3-0-b3b2e7e9847a@kernel.org>
Add parser for the ACPI RQSC table which describes the capacity and
bandwidth QoS controllers in a system. For each table entry, allocate a
cbqri_controller struct and populate it with the controller type, MMIO
base address, RCID/MCID counts, and resource identifiers (cache ID for
capacity controllers, proximity domain for bandwidth controllers).
Cache controller cpumasks are resolved via
acpi_pptt_get_cpumask_from_cache_id(). Bandwidth controller cpumasks
are derived from the proximity domain's NUMA node. Controllers with
invalid addresses or failed cpumask lookups are skipped with a warning.
The populated controller list is consumed by qos_resctrl_setup() in
arch/riscv/kernel/qos/ to probe the hardware and register resctrl
domains.
Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
MAINTAINERS | 1 +
arch/riscv/include/asm/acpi.h | 10 ++++
drivers/acpi/riscv/Makefile | 1 +
drivers/acpi/riscv/rqsc.c | 136 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 148 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index af9698a16439..d5ec7d29bf11 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22786,6 +22786,7 @@ S: Supported
F: arch/riscv/include/asm/qos.h
F: arch/riscv/include/asm/resctrl.h
F: arch/riscv/kernel/qos/
+F: drivers/acpi/riscv/rqsc.c
F: include/linux/riscv_qos.h
RISC-V RPMI AND MPXY DRIVERS
diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
index 6e13695120bc..62296a2a519b 100644
--- a/arch/riscv/include/asm/acpi.h
+++ b/arch/riscv/include/asm/acpi.h
@@ -71,6 +71,16 @@ int acpi_get_riscv_isa(struct acpi_table_header *table,
void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size,
u32 *cboz_size, u32 *cbop_size);
+
+#ifdef CONFIG_RISCV_ISA_SSQOSID
+int __init acpi_parse_rqsc(struct acpi_table_header *table);
+#else
+static inline int acpi_parse_rqsc(struct acpi_table_header *table)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_RISCV_ISA_SSQOSID */
+
#else
static inline void acpi_init_rintc_map(void) { }
static inline struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu)
diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile
index 1284a076fa88..d7ae8729987a 100644
--- a/drivers/acpi/riscv/Makefile
+++ b/drivers/acpi/riscv/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-y += rhct.o init.o irq.o
+obj-$(CONFIG_RISCV_ISA_SSQOSID) += rqsc.o
obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o
obj-$(CONFIG_ACPI_RIMT) += rimt.o
diff --git a/drivers/acpi/riscv/rqsc.c b/drivers/acpi/riscv/rqsc.c
new file mode 100644
index 000000000000..f647051be0bf
--- /dev/null
+++ b/drivers/acpi/riscv/rqsc.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Tenstorrent
+ * Author: Drew Fustini <fustini@kernel.org>
+ */
+
+#define pr_fmt(fmt) "ACPI: RQSC: " fmt
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/riscv_qos.h>
+
+#define CBQRI_CTRL_SIZE 0x1000
+
+int __init acpi_parse_rqsc(struct acpi_table_header *table)
+{
+ struct acpi_table_rqsc *rqsc;
+ struct acpi_table_rqsc_fields *end;
+ struct acpi_table_rqsc_fields *node;
+ int err;
+ int num_controllers = 0;
+
+ rqsc = (struct acpi_table_rqsc *)table;
+
+ end = ACPI_ADD_PTR(struct acpi_table_rqsc_fields, rqsc, rqsc->header.length);
+
+ for (node = ACPI_ADD_PTR(struct acpi_table_rqsc_fields, rqsc,
+ sizeof(struct acpi_table_rqsc));
+ node < end;
+ node = ACPI_ADD_PTR(struct acpi_table_rqsc_fields, node, node->length)
+ ) {
+ struct cbqri_controller *ctrl;
+
+ if (node->length < sizeof(*node)) {
+ pr_err("malformed RQSC entry: length %u < %zu, aborting\n",
+ node->length, sizeof(*node));
+ err = -EINVAL;
+ goto err_free_controllers;
+ }
+
+ ctrl = kzalloc_obj(*ctrl, GFP_KERNEL);
+ if (!ctrl) {
+ err = -ENOMEM;
+ goto err_free_controllers;
+ }
+
+ ctrl->type = node->type;
+ /* reg[1] is the MMIO base address per the RQSC table layout */
+ ctrl->addr = node->reg[1];
+ ctrl->size = CBQRI_CTRL_SIZE;
+ ctrl->rcid_count = node->rcid;
+ ctrl->mcid_count = node->mcid;
+
+ if (!ctrl->addr) {
+ pr_warn("skipping controller with invalid addr=0x0\n");
+ kfree(ctrl);
+ continue;
+ }
+
+ if (node->nres == 0) {
+ pr_warn("controller at %pa has no resource descriptors, skipping\n",
+ &ctrl->addr);
+ kfree(ctrl);
+ continue;
+ }
+
+ if (node->length < sizeof(*node) + sizeof(node->res[0])) {
+ pr_warn("controller at %pa: node too short for resource descriptor, skipping\n",
+ &ctrl->addr);
+ kfree(ctrl);
+ continue;
+ }
+
+ if (node->nres > 1)
+ pr_warn("controller at %pa has %u resource descriptors, using first\n",
+ &ctrl->addr, node->nres);
+
+ pr_debug("Found controller with type %u addr %pa size %pa rcid %u mcid %u\n",
+ ctrl->type, &ctrl->addr, &ctrl->size,
+ ctrl->rcid_count, ctrl->mcid_count);
+ if (ctrl->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
+ ctrl->cache.cache_id = (u32)node->res[0].id1;
+ ctrl->cache.cache_level =
+ find_acpi_cache_level_from_id(ctrl->cache.cache_id);
+
+ if (acpi_pptt_get_cache_size_from_id(ctrl->cache.cache_id,
+ &ctrl->cache.cache_size)) {
+ pr_warn("failed to determine size for cache id 0x%x\n",
+ ctrl->cache.cache_id);
+ ctrl->cache.cache_size = 0;
+ }
+
+ pr_debug("Cache controller has ID 0x%x level %u size %u\n",
+ ctrl->cache.cache_id, ctrl->cache.cache_level,
+ ctrl->cache.cache_size);
+
+ /*
+ * For CBQRI, any cpu (technically a hart in RISC-V terms)
+ * can access the memory-mapped registers of any CBQRI
+ * controller in the system.
+ */
+ err = acpi_pptt_get_cpumask_from_cache_id(ctrl->cache.cache_id,
+ &ctrl->cache.cpu_mask);
+ if (err) {
+ pr_warn("Failed to get cpumask for cache id 0x%x (%d), skipping\n",
+ ctrl->cache.cache_id, err);
+ kfree(ctrl);
+ continue;
+ }
+
+ } else if (ctrl->type == CBQRI_CONTROLLER_TYPE_BANDWIDTH) {
+ ctrl->mem.prox_dom = (u32)node->res[0].id1;
+ cpumask_copy(&ctrl->mem.cpu_mask,
+ cpumask_of_node(pxm_to_node(ctrl->mem.prox_dom)));
+ pr_debug("Memory controller with proximity domain %u\n",
+ ctrl->mem.prox_dom);
+ }
+
+ /* List shared with RISC-V QoS resctrl implementation */
+ list_add_tail(&ctrl->list, &cbqri_controllers);
+ num_controllers++;
+ }
+
+ pr_info("found %d CBQRI controllers\n", num_controllers);
+ return 0;
+
+err_free_controllers:
+ while (!list_empty(&cbqri_controllers)) {
+ struct cbqri_controller *ctrl;
+
+ ctrl = list_first_entry(&cbqri_controllers, struct cbqri_controller, list);
+ list_del(&ctrl->list);
+ kfree(ctrl);
+ }
+ return err;
+}
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v3 09/11] DO NOT MERGE: include: acpi: actbl2: Add structs for RQSC table
From: Drew Fustini @ 2026-04-15 1:54 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Drew Fustini
Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
devicetree, Paul Walmsley
In-Reply-To: <20260414-ssqosid-cbqri-rqsc-v7-0-v3-0-b3b2e7e9847a@kernel.org>
Add structs for the RQSC table which describes the properties of the
RISC-V QoS controllers (CBQRI) in the system. The table also describes
the topological arrangement of the QoS controllers and resources in the
system. The topology is expressed in terms of the location of the
resources within the system and the relation between the QoS Controller
and the resource it manages.
Note: This is a placeholder for RFC review purposes. The actbl2.h
change must go through upstream ACPICA first and will be replaced by
the auto-generated ACPICA commit once the RQSC spec is ratified.
Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/chapter2.adoc
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
include/acpi/actbl2.h | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
index 5c0b55e7b3e4..d6f272e848fa 100644
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -55,6 +55,7 @@
#define ACPI_SIG_RGRT "RGRT" /* Regulatory Graphics Resource Table */
#define ACPI_SIG_RHCT "RHCT" /* RISC-V Hart Capabilities Table */
#define ACPI_SIG_RIMT "RIMT" /* RISC-V IO Mapping Table */
+#define ACPI_SIG_RQSC "RQSC" /* RISC-V Quality of Service Controller */
#define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */
#define ACPI_SIG_SDEI "SDEI" /* Software Delegated Exception Interface Table */
#define ACPI_SIG_SDEV "SDEV" /* Secure Devices table */
@@ -3351,6 +3352,41 @@ enum acpi_rgrt_image_type {
ACPI_RGRT_TYPE_RESERVED = 2 /* 2 and greater are reserved */
};
+/*******************************************************************************
+ *
+ * RQSC - RISC-V Quality of Service Controller
+ * Version 1
+ *
+ ******************************************************************************/
+
+struct acpi_table_rqsc_fields_res {
+ u8 type;
+ u8 resv;
+ u16 length;
+ u16 flags;
+ u8 resv2;
+ u8 id_type;
+ u64 id1;
+ u32 id2;
+};
+
+struct acpi_table_rqsc_fields {
+ u8 type;
+ u8 resv;
+ u16 length;
+ u32 reg[3];
+ u16 rcid;
+ u16 mcid;
+ u16 flags;
+ u16 nres;
+ struct acpi_table_rqsc_fields_res res[];
+};
+
+struct acpi_table_rqsc {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 num;
+};
+
/*******************************************************************************
*
* RHCT - RISC-V Hart Capabilities Table
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v3 08/11] ACPI: PPTT: Add acpi_pptt_get_cache_size_from_id helper
From: Drew Fustini @ 2026-04-15 1:54 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Drew Fustini
Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
devicetree, Paul Walmsley
In-Reply-To: <20260414-ssqosid-cbqri-rqsc-v7-0-v3-0-b3b2e7e9847a@kernel.org>
Add helper to look up a cache's size from its cache ID in the PPTT
table. This is needed by the RISC-V RQSC parser to determine the cache
size for CBQRI capacity controllers.
The implementation follows the pattern established by
find_acpi_cache_level_from_id() and acpi_pptt_get_cpumask_from_cache_id():
uses acpi_get_pptt(), upgrade_pptt_cache(), checks all three cache types,
and uses the do/while empty-detection loop.
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
drivers/acpi/pptt.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 8 +++++++
2 files changed, 71 insertions(+)
diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c
index de5f8c018333..36e375551b43 100644
--- a/drivers/acpi/pptt.c
+++ b/drivers/acpi/pptt.c
@@ -1063,3 +1063,66 @@ int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id, cpumask_t *cpus)
return 0;
}
+
+/**
+ * acpi_pptt_get_cache_size_from_id() - Get the size of the specified cache
+ * @cache_id: The id field of the cache
+ * @size: Where to store the cache size in bytes
+ *
+ * Determine the size of the cache identified by cache_id. This allows the
+ * property to be found even if the CPUs are offline.
+ *
+ * The PPTT table must be rev 3 or later.
+ *
+ * Return: -ENOENT if the PPTT doesn't exist, the revision isn't supported or
+ * the cache cannot be found. Otherwise returns 0 and sets *size.
+ */
+int acpi_pptt_get_cache_size_from_id(u32 cache_id, u32 *size)
+{
+ int cpu;
+ struct acpi_table_header *table;
+
+ table = acpi_get_pptt();
+ if (!table)
+ return -ENOENT;
+
+ if (table->revision < 3)
+ return -ENOENT;
+
+ for_each_possible_cpu(cpu) {
+ bool empty;
+ int level = 1;
+ u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
+ struct acpi_pptt_processor *cpu_node;
+
+ cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
+ if (!cpu_node)
+ continue;
+
+ do {
+ int cache_type[] = {CACHE_TYPE_INST, CACHE_TYPE_DATA, CACHE_TYPE_UNIFIED};
+
+ empty = true;
+ for (int i = 0; i < ARRAY_SIZE(cache_type); i++) {
+ struct acpi_pptt_cache *cache;
+ struct acpi_pptt_cache_v1_full *cache_v1;
+
+ cache = acpi_find_cache_node(table, acpi_cpu_id, cache_type[i],
+ level, &cpu_node);
+ if (!cache)
+ continue;
+
+ empty = false;
+
+ cache_v1 = upgrade_pptt_cache(cache);
+ if (cache_v1 && cache_v1->cache_id == cache_id) {
+ *size = cache->size;
+ return 0;
+ }
+ }
+ level++;
+ } while (!empty);
+ }
+
+ return -ENOENT;
+}
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 4d2f0bed7a06..0596ec18f522 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -1547,6 +1547,7 @@ int find_acpi_cpu_topology_package(unsigned int cpu);
int find_acpi_cpu_topology_hetero_id(unsigned int cpu);
void acpi_pptt_get_cpus_from_container(u32 acpi_cpu_id, cpumask_t *cpus);
int find_acpi_cache_level_from_id(u32 cache_id);
+int acpi_pptt_get_cache_size_from_id(u32 cache_id, u32 *size);
int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id, cpumask_t *cpus);
#else
static inline int acpi_pptt_cpu_is_thread(unsigned int cpu)
@@ -1571,10 +1572,17 @@ static inline int find_acpi_cpu_topology_hetero_id(unsigned int cpu)
}
static inline void acpi_pptt_get_cpus_from_container(u32 acpi_cpu_id,
cpumask_t *cpus) { }
+
static inline int find_acpi_cache_level_from_id(u32 cache_id)
{
return -ENOENT;
}
+
+static inline int acpi_pptt_get_cache_size_from_id(u32 cache_id, u32 *size)
+{
+ return -ENOENT;
+}
+
static inline int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id,
cpumask_t *cpus)
{
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v3 07/11] RISC-V: QoS: enable resctrl support for Ssqosid
From: Drew Fustini @ 2026-04-15 1:54 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Drew Fustini
Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
devicetree, Paul Walmsley
In-Reply-To: <20260414-ssqosid-cbqri-rqsc-v7-0-v3-0-b3b2e7e9847a@kernel.org>
Wire up the RISC-V QoS resctrl implementation:
Add a late_initcall that checks for the Ssqosid extension and, if
present, calls qos_resctrl_setup() to probe CBQRI controllers and
initialize the resctrl filesystem, then registers CPU hotplug callbacks.
Make CONFIG_RISCV_ISA_SSQOSID select ARCH_HAS_CPU_RESCTRL and
RESCTRL_FS, and depends on MISC_FILESYSTEMS.
Add qos_resctrl.o to the build when CONFIG_RISCV_ISA_SSQOSID is set.
Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
arch/riscv/Kconfig | 3 +++
arch/riscv/kernel/qos/Makefile | 2 +-
arch/riscv/kernel/qos/qos.c | 32 ++++++++++++++++++++++++++++++++
3 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 92d2265a0c61..b2fef15b3d4f 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -597,7 +597,10 @@ config RISCV_ISA_SVNAPOT
config RISCV_ISA_SSQOSID
bool "Ssqosid extension support for supervisor mode Quality of Service ID"
+ depends on MISC_FILESYSTEMS
default n
+ select ARCH_HAS_CPU_RESCTRL
+ select RESCTRL_FS
help
Adds support for the Ssqosid ISA extension (Supervisor-mode
Quality of Service ID).
diff --git a/arch/riscv/kernel/qos/Makefile b/arch/riscv/kernel/qos/Makefile
index 9f996263a86d..9ed0c13a854d 100644
--- a/arch/riscv/kernel/qos/Makefile
+++ b/arch/riscv/kernel/qos/Makefile
@@ -1,2 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos.o
+obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos.o qos_resctrl.o
diff --git a/arch/riscv/kernel/qos/qos.c b/arch/riscv/kernel/qos/qos.c
index a3c2b910e2e0..560607abf10a 100644
--- a/arch/riscv/kernel/qos/qos.c
+++ b/arch/riscv/kernel/qos/qos.c
@@ -1,8 +1,40 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/riscv_qos.h>
+
+#include <asm/csr.h>
#include <asm/qos.h>
+#include "internal.h"
+
/* cached value of srmcfg csr for each cpu */
DEFINE_PER_CPU(u32, cpu_srmcfg);
/* default srmcfg value for each cpu, set via resctrl cpu assignment */
DEFINE_PER_CPU(u32, cpu_srmcfg_default);
+
+static int __init qos_arch_late_init(void)
+{
+ int err;
+
+ if (!riscv_isa_extension_available(NULL, SSQOSID))
+ return -ENODEV;
+
+ err = qos_resctrl_setup();
+ if (err)
+ return err;
+
+ err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "qos:online",
+ qos_resctrl_online_cpu,
+ qos_resctrl_offline_cpu);
+ if (err < 0) {
+ resctrl_exit();
+ return err;
+ }
+
+ return 0;
+}
+late_initcall(qos_arch_late_init);
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v3 06/11] RISC-V: QoS: add resctrl setup and domain management
From: Drew Fustini @ 2026-04-15 1:54 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Drew Fustini
Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
devicetree, Paul Walmsley
In-Reply-To: <20260414-ssqosid-cbqri-rqsc-v7-0-v3-0-b3b2e7e9847a@kernel.org>
Add the setup and domain management layer: domain allocation
(qos_new_domain), controller value initialization
(qos_init_domain_ctrlval), resource struct initialization for cache and
bandwidth resources, domain registration with the resctrl filesystem
(qos_resctrl_add_controller_domain), and the top-level setup function
(qos_resctrl_setup) that probes all controllers and calls resctrl_init().
Also add qos_resctrl_online_cpu() and qos_resctrl_offline_cpu() for CPU
hotplug integration.
Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
arch/riscv/kernel/qos/qos_resctrl.c | 295 +++++++++++++++++++++++++++++++++++-
1 file changed, 294 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/kernel/qos/qos_resctrl.c b/arch/riscv/kernel/qos/qos_resctrl.c
index a4a120f89840..8d7e3b0abb75 100644
--- a/arch/riscv/kernel/qos/qos_resctrl.c
+++ b/arch/riscv/kernel/qos/qos_resctrl.c
@@ -675,7 +675,23 @@ void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domai
void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
{
- /* not implemented for the RISC-V resctrl implementation */
+ struct cbqri_resctrl_res *hw_res;
+ struct rdt_ctrl_domain *d;
+ enum resctrl_conf_type t;
+ u32 default_ctrl;
+ int i;
+
+ lockdep_assert_cpus_held();
+
+ hw_res = container_of(r, struct cbqri_resctrl_res, resctrl_res);
+ default_ctrl = resctrl_get_default_ctrl(r);
+
+ list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
+ for (i = 0; i < hw_res->max_rcid; i++) {
+ for (t = 0; t < CDP_NUM_TYPES; t++)
+ resctrl_arch_update_one(r, d, i, t, default_ctrl);
+ }
+ }
}
void resctrl_arch_pre_mount(void)
@@ -797,3 +813,280 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
spin_unlock(&ctrl->lock);
return val;
}
+
+static struct rdt_ctrl_domain *qos_new_domain(struct cbqri_controller *ctrl)
+{
+ struct cbqri_resctrl_dom *hw_dom;
+ struct rdt_ctrl_domain *domain;
+
+ hw_dom = kzalloc_obj(*hw_dom, GFP_KERNEL);
+ if (!hw_dom)
+ return NULL;
+
+ /* associate this cbqri_controller with the domain */
+ hw_dom->hw_ctrl = ctrl;
+
+ /* the rdt_domain struct from inside the cbqri_resctrl_dom struct */
+ domain = &hw_dom->resctrl_ctrl_dom;
+
+ INIT_LIST_HEAD(&domain->hdr.list);
+
+ return domain;
+}
+
+static int qos_init_domain_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain *d)
+{
+ struct cbqri_resctrl_res *hw_res;
+ int err = 0;
+ int i;
+
+ hw_res = container_of(r, struct cbqri_resctrl_res, resctrl_res);
+
+ for (i = 0; i < hw_res->max_rcid; i++) {
+ err = resctrl_arch_update_one(r, d, i, 0, resctrl_get_default_ctrl(r));
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int qos_init_cache_resource(struct cbqri_controller *ctrl,
+ struct cbqri_resctrl_res *cbqri_res,
+ enum resctrl_res_level rid, char *name,
+ enum resctrl_scope scope)
+{
+ struct rdt_resource *res = &cbqri_res->resctrl_res;
+
+ /* Already initialized by a previous controller at this cache level */
+ if (res->name) {
+ if (cbqri_res->max_rcid != ctrl->rcid_count ||
+ res->cache.cbm_len != ctrl->cc.ncblks) {
+ pr_err("%s controllers have mismatched capabilities\n",
+ name);
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ cbqri_res->max_rcid = ctrl->rcid_count;
+ cbqri_res->max_mcid = ctrl->mcid_count;
+ res->rid = rid;
+ res->name = name;
+ res->alloc_capable = ctrl->alloc_capable;
+ res->schema_fmt = RESCTRL_SCHEMA_BITMAP;
+ res->ctrl_scope = scope;
+ res->cache.cbm_len = ctrl->cc.ncblks;
+ res->cache.shareable_bits = resctrl_get_default_ctrl(res);
+ res->cache.min_cbm_bits = 1;
+ return 0;
+}
+
+static int qos_init_membw_resource(struct cbqri_controller *ctrl,
+ struct cbqri_resctrl_res *cbqri_res)
+{
+ struct rdt_resource *res = &cbqri_res->resctrl_res;
+
+ if (res->name) {
+ if (cbqri_res->max_rcid != ctrl->rcid_count ||
+ res->membw.max_bw != DIV_ROUND_UP(ctrl->bc.mrbwb * 100,
+ ctrl->bc.nbwblks)) {
+ pr_err("MB controllers have mismatched capabilities\n");
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ cbqri_res->max_rcid = ctrl->rcid_count;
+ cbqri_res->max_mcid = ctrl->mcid_count;
+ res->rid = RDT_RESOURCE_MBA;
+ res->name = "MB";
+ res->alloc_capable = ctrl->alloc_capable;
+ res->schema_fmt = RESCTRL_SCHEMA_RANGE;
+ /*
+ * resctrl requires a cache scope for MBA domains. Use L3 as a
+ * proxy until the framework supports non-cache scopes for
+ * bandwidth resources.
+ */
+ res->ctrl_scope = RESCTRL_L3_CACHE;
+ res->membw.delay_linear = true;
+ res->membw.arch_needs_linear = true;
+ res->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
+ res->membw.min_bw = 1;
+ res->membw.max_bw = DIV_ROUND_UP(ctrl->bc.mrbwb * 100, ctrl->bc.nbwblks);
+ res->membw.bw_gran = 1;
+ return 0;
+}
+
+static int qos_resctrl_add_controller_domain(struct cbqri_controller *ctrl)
+{
+ struct rdt_ctrl_domain *domain;
+ struct cbqri_resctrl_res *cbqri_res = NULL;
+ struct rdt_resource *res = NULL;
+ struct list_head *pos = NULL;
+ int err;
+
+ domain = qos_new_domain(ctrl);
+ if (!domain)
+ return -ENOSPC;
+
+ switch (ctrl->type) {
+ case CBQRI_CONTROLLER_TYPE_CAPACITY:
+ cpumask_copy(&domain->hdr.cpu_mask, &ctrl->cache.cpu_mask);
+ domain->hdr.id = ctrl->cache.cache_id;
+
+ if (ctrl->cache.cache_level == 2) {
+ cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_L2];
+ err = qos_init_cache_resource(ctrl, cbqri_res,
+ RDT_RESOURCE_L2, "L2",
+ RESCTRL_L2_CACHE);
+ } else if (ctrl->cache.cache_level == 3) {
+ cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_L3];
+ err = qos_init_cache_resource(ctrl, cbqri_res,
+ RDT_RESOURCE_L3, "L3",
+ RESCTRL_L3_CACHE);
+ } else {
+ pr_err("unknown cache level %d\n", ctrl->cache.cache_level);
+ err = -ENODEV;
+ }
+ if (err)
+ goto err_free_domain;
+ res = &cbqri_res->resctrl_res;
+ break;
+
+ case CBQRI_CONTROLLER_TYPE_BANDWIDTH:
+ cpumask_copy(&domain->hdr.cpu_mask, &ctrl->mem.cpu_mask);
+ domain->hdr.id = ctrl->mem.prox_dom;
+ if (ctrl->alloc_capable) {
+ cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_MBA];
+ err = qos_init_membw_resource(ctrl, cbqri_res);
+ if (err)
+ goto err_free_domain;
+ res = &cbqri_res->resctrl_res;
+ }
+ break;
+
+ default:
+ pr_err("unknown controller type %d\n", ctrl->type);
+ err = -ENODEV;
+ goto err_free_domain;
+ }
+
+ if (!res)
+ goto out;
+
+ err = qos_init_domain_ctrlval(res, domain);
+ if (err)
+ goto err_free_domain;
+
+ if (resctrl_find_domain(&res->ctrl_domains, domain->hdr.id, &pos)) {
+ pr_err("duplicate domain id %d for resource %s\n",
+ domain->hdr.id, res->name);
+ err = -EEXIST;
+ goto err_free_domain;
+ }
+ if (pos)
+ list_add_tail(&domain->hdr.list, pos);
+ else
+ list_add_tail(&domain->hdr.list, &res->ctrl_domains);
+
+ err = resctrl_online_ctrl_domain(res, domain);
+ if (err) {
+ pr_err("failed to online domain %d\n", domain->hdr.id);
+ list_del(&domain->hdr.list);
+ goto err_free_domain;
+ }
+
+out:
+ return 0;
+
+err_free_domain:
+ kfree(container_of(domain, struct cbqri_resctrl_dom, resctrl_ctrl_dom));
+ return err;
+}
+
+int qos_resctrl_setup(void)
+{
+ struct rdt_ctrl_domain *domain, *domain_temp;
+ struct cbqri_controller *ctrl;
+ struct cbqri_resctrl_res *res;
+ int err = 0;
+ int i = 0;
+
+ max_rmid = U32_MAX;
+
+ for (i = 0; i < RDT_NUM_RESOURCES; i++) {
+ res = &cbqri_resctrl_resources[i];
+ INIT_LIST_HEAD(&res->resctrl_res.ctrl_domains);
+ INIT_LIST_HEAD(&res->resctrl_res.mon_domains);
+ res->resctrl_res.rid = i;
+ }
+
+ list_for_each_entry(ctrl, &cbqri_controllers, list) {
+ err = cbqri_probe_controller(ctrl);
+ if (err) {
+ pr_err("%s(): failed (%d)\n", __func__, err);
+ goto err_free_controllers_list;
+ }
+
+ err = qos_resctrl_add_controller_domain(ctrl);
+ if (err) {
+ pr_err("%s(): failed to add controller domain (%d)\n", __func__, err);
+ goto err_free_controllers_list;
+ }
+
+ /*
+ * CDP (code data prioritization) on x86 is similar to
+ * the AT (access type) field in CBQRI. CDP only supports
+ * caches so this must be a CBQRI capacity controller.
+ */
+ if (ctrl->type == CBQRI_CONTROLLER_TYPE_CAPACITY &&
+ ctrl->cc.supports_alloc_at_code) {
+ if (ctrl->cache.cache_level == 2)
+ exposed_cdp_l2_capable = true;
+ else
+ exposed_cdp_l3_capable = true;
+ }
+ }
+ pr_debug("alloc=%d cdp_l2=%d cdp_l3=%d\n",
+ exposed_alloc_capable,
+ exposed_cdp_l2_capable, exposed_cdp_l3_capable);
+
+ err = resctrl_init();
+ if (err)
+ goto err_free_controllers_list;
+
+ return 0;
+
+err_free_controllers_list:
+ for (i = 0; i < RDT_NUM_RESOURCES; i++) {
+ res = &cbqri_resctrl_resources[i];
+ list_for_each_entry_safe(domain, domain_temp, &res->resctrl_res.ctrl_domains,
+ hdr.list) {
+ resctrl_offline_ctrl_domain(&res->resctrl_res, domain);
+ list_del(&domain->hdr.list);
+ kfree(container_of(domain, struct cbqri_resctrl_dom, resctrl_ctrl_dom));
+ }
+ }
+
+ list_for_each_entry(ctrl, &cbqri_controllers, list) {
+ if (!ctrl->base)
+ break;
+ iounmap(ctrl->base);
+ ctrl->base = NULL;
+ release_mem_region(ctrl->addr, ctrl->size);
+ }
+
+ return err;
+}
+
+int qos_resctrl_online_cpu(unsigned int cpu)
+{
+ resctrl_online_cpu(cpu);
+ return 0;
+}
+
+int qos_resctrl_offline_cpu(unsigned int cpu)
+{
+ resctrl_offline_cpu(cpu);
+ return 0;
+}
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v3 05/11] RISC-V: QoS: add resctrl arch callbacks for CBQRI controllers
From: Drew Fustini @ 2026-04-15 1:53 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Drew Fustini
Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
devicetree, Paul Walmsley
In-Reply-To: <20260414-ssqosid-cbqri-rqsc-v7-0-v3-0-b3b2e7e9847a@kernel.org>
Implement the resctrl architecture callbacks required by the resctrl
filesystem and expose them via arch/riscv/include/asm/resctrl.h.
These include capability reporting, CDP enable/disable, CLOSID/RMID
encoding, scheduler integration (sched_in, set_closid_rmid,
sync_cpu_closid_rmid), domain config read/write (update_one,
update_domains, get_config), and stub implementations for monitoring
operations not yet supported on RISC-V.
The function prototypes and inline stubs are declared in
include/linux/riscv_qos.h alongside the implementations in
arch/riscv/kernel/qos/qos_resctrl.c.
Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
MAINTAINERS | 1 +
arch/riscv/include/asm/resctrl.h | 7 +
arch/riscv/kernel/qos/qos_resctrl.c | 367 ++++++++++++++++++++++++++++++++++++
include/linux/riscv_qos.h | 33 ++++
4 files changed, 408 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 6a66d7047c51..af9698a16439 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22784,6 +22784,7 @@ R: yunhui cui <cuiyunhui@bytedance.com>
L: linux-riscv@lists.infradead.org
S: Supported
F: arch/riscv/include/asm/qos.h
+F: arch/riscv/include/asm/resctrl.h
F: arch/riscv/kernel/qos/
F: include/linux/riscv_qos.h
diff --git a/arch/riscv/include/asm/resctrl.h b/arch/riscv/include/asm/resctrl.h
new file mode 100644
index 000000000000..48ad45cbe25c
--- /dev/null
+++ b/arch/riscv/include/asm/resctrl.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_RISCV_RESCTRL_H
+#define _ASM_RISCV_RESCTRL_H
+
+#include <linux/riscv_qos.h>
+
+#endif /* _ASM_RISCV_RESCTRL_H */
diff --git a/arch/riscv/kernel/qos/qos_resctrl.c b/arch/riscv/kernel/qos/qos_resctrl.c
index 6d294f2f2504..a4a120f89840 100644
--- a/arch/riscv/kernel/qos/qos_resctrl.c
+++ b/arch/riscv/kernel/qos/qos_resctrl.c
@@ -2,6 +2,7 @@
#define pr_fmt(fmt) "qos: resctrl: " fmt
+#include <linux/cpu.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/io-64-nonatomic-lo-hi.h>
@@ -430,3 +431,369 @@ static int cbqri_probe_controller(struct cbqri_controller *ctrl)
release_mem_region(ctrl->addr, ctrl->size);
return err;
}
+
+bool resctrl_arch_alloc_capable(void)
+{
+ return exposed_alloc_capable;
+}
+
+bool resctrl_arch_mon_capable(void)
+{
+ /* Monitoring not yet implemented */
+ return false;
+}
+
+bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
+{
+ switch (rid) {
+ case RDT_RESOURCE_L2:
+ return is_cdp_l2_enabled;
+
+ case RDT_RESOURCE_L3:
+ return is_cdp_l3_enabled;
+
+ default:
+ return false;
+ }
+}
+
+int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
+{
+ switch (rid) {
+ case RDT_RESOURCE_L2:
+ if (!exposed_cdp_l2_capable)
+ return -ENODEV;
+ is_cdp_l2_enabled = enable;
+ break;
+
+ case RDT_RESOURCE_L3:
+ if (!exposed_cdp_l3_capable)
+ return -ENODEV;
+ is_cdp_l3_enabled = enable;
+ break;
+
+ default:
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
+{
+ if (l >= RDT_NUM_RESOURCES)
+ return NULL;
+
+ return &cbqri_resctrl_resources[l].resctrl_res;
+}
+
+bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
+{
+ return false;
+}
+
+void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r,
+ enum resctrl_event_id evtid)
+{
+ /* RISC-V can always read an rmid, nothing needs allocating */
+ return NULL;
+}
+
+void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
+ enum resctrl_event_id evtid, void *arch_mon_ctx)
+{
+ /* No arch-private monitoring context to free */
+}
+
+void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+ enum resctrl_event_id evtid, u32 rmid, u32 closid,
+ u32 cntr_id, bool assign)
+{
+ /* MBM counter assignment not supported */
+}
+
+int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+ u32 unused, u32 rmid, int cntr_id,
+ enum resctrl_event_id eventid, u64 *val)
+{
+ /* MBM counter assignment not supported */
+ return -EOPNOTSUPP;
+}
+
+bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
+{
+ /* MBM counter assignment not supported */
+ return false;
+}
+
+int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable)
+{
+ /* MBM counter assignment not supported */
+ return 0;
+}
+
+void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+ u32 unused, u32 rmid, int cntr_id,
+ enum resctrl_event_id eventid)
+{
+ /* MBM counter assignment not supported */
+}
+
+bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r)
+{
+ /* CBQRI does not have I/O-specific allocation */
+ return false;
+}
+
+int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable)
+{
+ /* CBQRI does not have I/O-specific allocation */
+ return 0;
+}
+
+/*
+ * Note about terminology between x86 (Intel RDT/AMD QoS) and RISC-V:
+ * CLOSID on x86 is RCID on RISC-V
+ * RMID on x86 is MCID on RISC-V
+ */
+u32 resctrl_arch_get_num_closid(struct rdt_resource *res)
+{
+ struct cbqri_resctrl_res *hw_res;
+
+ hw_res = container_of(res, struct cbqri_resctrl_res, resctrl_res);
+
+ return hw_res->max_rcid;
+}
+
+u32 resctrl_arch_system_num_rmid_idx(void)
+{
+ return max_rmid;
+}
+
+u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
+{
+ return rmid;
+}
+
+void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
+{
+ *closid = RISCV_RESCTRL_EMPTY_CLOSID;
+ *rmid = idx;
+}
+
+void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid)
+{
+ u32 srmcfg;
+
+ WARN_ON_ONCE((closid & SRMCFG_RCID_MASK) != closid);
+ WARN_ON_ONCE((rmid & SRMCFG_MCID_MASK) != rmid);
+
+ srmcfg = rmid << SRMCFG_MCID_SHIFT;
+ srmcfg |= closid;
+ WRITE_ONCE(per_cpu(cpu_srmcfg_default, cpu), srmcfg);
+}
+
+void resctrl_arch_sched_in(struct task_struct *tsk)
+{
+ __switch_to_srmcfg(tsk);
+}
+
+void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
+{
+ u32 srmcfg;
+
+ WARN_ON_ONCE((closid & SRMCFG_RCID_MASK) != closid);
+ WARN_ON_ONCE((rmid & SRMCFG_MCID_MASK) != rmid);
+
+ srmcfg = rmid << SRMCFG_MCID_SHIFT;
+ srmcfg |= closid;
+ WRITE_ONCE(tsk->thread.srmcfg, srmcfg);
+}
+
+void resctrl_arch_sync_cpu_closid_rmid(void *info)
+{
+ struct resctrl_cpu_defaults *r = info;
+
+ lockdep_assert_preemption_disabled();
+
+ if (r) {
+ resctrl_arch_set_cpu_default_closid_rmid(smp_processor_id(),
+ r->closid, r->rmid);
+ }
+
+ resctrl_arch_sched_in(current);
+}
+
+bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
+{
+ return (READ_ONCE(tsk->thread.srmcfg) & SRMCFG_RCID_MASK) == closid;
+}
+
+bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
+{
+ u32 tsk_rmid;
+
+ tsk_rmid = READ_ONCE(tsk->thread.srmcfg);
+ tsk_rmid >>= SRMCFG_MCID_SHIFT;
+ tsk_rmid &= SRMCFG_MCID_MASK;
+
+ return tsk_rmid == rmid;
+}
+
+int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
+ u32 closid, u32 rmid, enum resctrl_event_id eventid,
+ void *arch_priv, u64 *val, void *arch_mon_ctx)
+{
+ /*
+ * Cache occupancy and bandwidth monitoring are not yet implemented
+ * for RISC-V CBQRI. This will be added in a future series once the
+ * resctrl framework supports monitoring domains at non-L3 scopes.
+ */
+ return -EOPNOTSUPP;
+}
+
+void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+ u32 closid, u32 rmid, enum resctrl_event_id eventid)
+{
+ /* Monitoring not yet supported; nothing to reset */
+}
+
+void resctrl_arch_mon_event_config_read(void *info)
+{
+ /* Monitoring not yet supported; no event config */
+}
+
+void resctrl_arch_mon_event_config_write(void *info)
+{
+ /* Monitoring not yet supported; no event config */
+}
+
+void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domain *d)
+{
+ /* Monitoring not yet supported; nothing to reset */
+}
+
+void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
+{
+ /* not implemented for the RISC-V resctrl implementation */
+}
+
+void resctrl_arch_pre_mount(void)
+{
+ /* All controllers discovered at boot via late_initcall; nothing to do */
+}
+
+int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
+ u32 closid, enum resctrl_conf_type t, u32 cfg_val)
+{
+ struct cbqri_controller *ctrl;
+ struct cbqri_resctrl_dom *dom;
+ struct cbqri_config cfg;
+ int err = 0;
+
+ dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+ ctrl = dom->hw_ctrl;
+
+ if (!r->alloc_capable)
+ return -EINVAL;
+
+ switch (r->rid) {
+ case RDT_RESOURCE_L2:
+ case RDT_RESOURCE_L3:
+ cfg.cbm = cfg_val;
+ err = cbqri_apply_cache_config(dom, closid, t, &cfg);
+ break;
+ case RDT_RESOURCE_MBA:
+ /* convert from percentage to bandwidth blocks */
+ cfg.rbwb = cfg_val * ctrl->bc.nbwblks / 100;
+ cfg.rbwb = min_t(u64, cfg.rbwb, ctrl->bc.mrbwb);
+ err = cbqri_apply_bw_config(dom, closid, t, &cfg);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err;
+}
+
+int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
+{
+ struct resctrl_staged_config *cfg;
+ enum resctrl_conf_type t;
+ struct rdt_ctrl_domain *d;
+ int err = 0;
+
+ /* Walking r->ctrl_domains, ensure it can't race with cpuhp */
+ lockdep_assert_cpus_held();
+
+ list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
+ for (t = 0; t < CDP_NUM_TYPES; t++) {
+ cfg = &d->staged_config[t];
+ if (!cfg->have_new_ctrl)
+ continue;
+ err = resctrl_arch_update_one(r, d, closid, t, cfg->new_ctrl);
+ if (err) {
+ pr_err("%s(): update failed (err=%d)\n", __func__, err);
+ return err;
+ }
+ }
+ }
+ return err;
+}
+
+u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
+ u32 closid, enum resctrl_conf_type type)
+{
+ struct cbqri_resctrl_dom *hw_dom;
+ struct cbqri_controller *ctrl;
+ u32 val;
+ u32 rbwb;
+ int err;
+
+ hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+
+ ctrl = hw_dom->hw_ctrl;
+
+ val = resctrl_get_default_ctrl(r);
+
+ if (!r->alloc_capable)
+ return val;
+
+ spin_lock(&ctrl->lock);
+
+ switch (r->rid) {
+ case RDT_RESOURCE_L2:
+ case RDT_RESOURCE_L3:
+ /* Clear cc_block_mask before read limit operation */
+ cbqri_set_cbm(ctrl, 0);
+
+ /* Capacity read limit operation for RCID (closid) */
+ err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid, type);
+ if (err < 0) {
+ pr_err("%s(): operation failed: err = %d\n", __func__, err);
+ break;
+ }
+
+ /* Read capacity block mask for RCID (closid) */
+ val = ioread64(ctrl->base + CBQRI_CC_BLOCK_MASK_OFF);
+ break;
+
+ case RDT_RESOURCE_MBA:
+ /* Bandwidth read limit operation for RCID (closid) */
+ err = cbqri_bc_alloc_op(ctrl, CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT, closid);
+ if (err < 0) {
+ pr_err("%s(): operation failed: err = %d\n", __func__, err);
+ break;
+ }
+
+ rbwb = cbqri_get_rbwb(ctrl);
+ val = DIV_ROUND_UP(rbwb * 100, ctrl->bc.nbwblks);
+ break;
+
+ default:
+ break;
+ }
+
+ spin_unlock(&ctrl->lock);
+ return val;
+}
diff --git a/include/linux/riscv_qos.h b/include/linux/riscv_qos.h
index 0f3daae2e84f..1712fb12f6bc 100644
--- a/include/linux/riscv_qos.h
+++ b/include/linux/riscv_qos.h
@@ -3,6 +3,7 @@
#ifndef __LINUX_RISCV_QOS_H
#define __LINUX_RISCV_QOS_H
+#include <linux/resctrl_types.h>
#include <linux/spinlock.h>
#include <linux/types.h>
@@ -73,4 +74,36 @@ struct cbqri_controller {
extern struct list_head cbqri_controllers;
+bool resctrl_arch_alloc_capable(void);
+bool resctrl_arch_mon_capable(void);
+
+struct rdt_resource;
+/*
+ * Note about terminology between x86 (Intel RDT/AMD QoS) and RISC-V:
+ * CLOSID on x86 is RCID on RISC-V
+ * RMID on x86 is MCID on RISC-V
+ * CDP on x86 is AT (access type) on RISC-V
+ */
+u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid);
+void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid);
+void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid);
+void resctrl_arch_sched_in(struct task_struct *tsk);
+void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
+bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid);
+bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
+void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, enum resctrl_event_id evtid);
+void resctrl_arch_mon_ctx_free(struct rdt_resource *r, enum resctrl_event_id evtid,
+ void *arch_mon_ctx);
+
+static inline unsigned int resctrl_arch_round_mon_val(unsigned int val)
+{
+ return val;
+}
+
+/* Not needed for RISC-V */
+static inline void resctrl_arch_enable_mon(void) { }
+static inline void resctrl_arch_disable_mon(void) { }
+static inline void resctrl_arch_enable_alloc(void) { }
+static inline void resctrl_arch_disable_alloc(void) { }
+
#endif /* __LINUX_RISCV_QOS_H */
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v3 04/11] RISC-V: QoS: add CBQRI hardware interface
From: Drew Fustini @ 2026-04-15 1:53 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Drew Fustini
Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
devicetree, Paul Walmsley
In-Reply-To: <20260414-ssqosid-cbqri-rqsc-v7-0-v3-0-b3b2e7e9847a@kernel.org>
Add the CBQRI controller hardware interface layer.
Define data structures representing CBQRI controller properties
(cbqri_controller) and hardware capabilities for capacity and bandwidth
controllers (riscv_cbqri_capacity_caps, riscv_cbqri_bandwidth_caps) in
include/linux/riscv_qos.h.
Define MMIO register offsets, field masks, and internal wrapper structs
(cbqri_resctrl_res, cbqri_resctrl_dom, cbqri_config) in internal.h.
Implement MMIO helpers for capacity block mask and bandwidth reservation,
alloc control operations for capacity and bandwidth controllers, and
probe functions to discover controller capabilities. A per-controller
spinlock serializes multi-step MMIO sequences.
Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
MAINTAINERS | 1 +
arch/riscv/kernel/qos/internal.h | 81 +++++++
arch/riscv/kernel/qos/qos_resctrl.c | 432 ++++++++++++++++++++++++++++++++++++
include/linux/riscv_qos.h | 76 +++++++
4 files changed, 590 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index b17f885411ba..6a66d7047c51 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22785,6 +22785,7 @@ L: linux-riscv@lists.infradead.org
S: Supported
F: arch/riscv/include/asm/qos.h
F: arch/riscv/kernel/qos/
+F: include/linux/riscv_qos.h
RISC-V RPMI AND MPXY DRIVERS
M: Rahul Pathak <rahul@summations.net>
diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h
new file mode 100644
index 000000000000..edbcbd9471b1
--- /dev/null
+++ b/arch/riscv/kernel/qos/internal.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_RISCV_QOS_INTERNAL_H
+#define _ASM_RISCV_QOS_INTERNAL_H
+
+#include <linux/bitfield.h>
+#include <linux/resctrl.h>
+#include <linux/riscv_qos.h>
+
+#define RISCV_RESCTRL_EMPTY_CLOSID ((u32)~0)
+
+#define CBQRI_CC_CAPABILITIES_OFF 0
+#define CBQRI_CC_MON_CTL_OFF 8
+#define CBQRI_CC_MON_CTL_VAL_OFF 16
+#define CBQRI_CC_ALLOC_CTL_OFF 24
+#define CBQRI_CC_BLOCK_MASK_OFF 32
+
+#define CBQRI_BC_CAPABILITIES_OFF 0
+#define CBQRI_BC_MON_CTL_OFF 8
+#define CBQRI_BC_MON_CTR_VAL_OFF 16
+#define CBQRI_BC_ALLOC_CTL_OFF 24
+#define CBQRI_BC_BW_ALLOC_OFF 32
+
+#define CBQRI_CC_CAPABILITIES_VER_MINOR_MASK GENMASK(3, 0)
+#define CBQRI_CC_CAPABILITIES_VER_MAJOR_MASK GENMASK(7, 4)
+
+#define CBQRI_CC_CAPABILITIES_NCBLKS_MASK GENMASK(23, 8)
+#define CBQRI_CC_CAPABILITIES_FRCID_MASK GENMASK(24, 24)
+
+#define CBQRI_BC_CAPABILITIES_VER_MINOR_MASK GENMASK(3, 0)
+#define CBQRI_BC_CAPABILITIES_VER_MAJOR_MASK GENMASK(7, 4)
+
+#define CBQRI_BC_CAPABILITIES_NBWBLKS_MASK GENMASK(23, 8)
+#define CBQRI_BC_CAPABILITIES_MRBWB_MASK GENMASK_ULL(47, 32)
+
+#define CBQRI_CONTROL_REGISTERS_OP_MASK GENMASK(4, 0)
+#define CBQRI_CONTROL_REGISTERS_AT_MASK GENMASK(7, 5)
+#define CBQRI_CONTROL_REGISTERS_AT_DATA 0
+#define CBQRI_CONTROL_REGISTERS_AT_CODE 1
+#define CBQRI_CONTROL_REGISTERS_RCID_MASK GENMASK(19, 8)
+#define CBQRI_CONTROL_REGISTERS_STATUS_MASK GENMASK_ULL(38, 32)
+#define CBQRI_CONTROL_REGISTERS_BUSY_MASK GENMASK_ULL(39, 39)
+#define CBQRI_CONTROL_REGISTERS_RBWB_MASK GENMASK(15, 0)
+
+#define CBQRI_CC_MON_CTL_OP_CONFIG_EVENT 1
+#define CBQRI_CC_MON_CTL_OP_READ_COUNTER 2
+#define CBQRI_CC_MON_CTL_STATUS_SUCCESS 1
+
+#define CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT 1
+#define CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT 2
+#define CBQRI_CC_ALLOC_CTL_OP_FLUSH_RCID 3
+#define CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS 1
+
+#define CBQRI_BC_MON_CTL_OP_CONFIG_EVENT 1
+#define CBQRI_BC_MON_CTL_OP_READ_COUNTER 2
+#define CBQRI_BC_MON_CTL_STATUS_SUCCESS 1
+
+#define CBQRI_BC_ALLOC_CTL_OP_CONFIG_LIMIT 1
+#define CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT 2
+#define CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS 1
+
+int qos_resctrl_setup(void);
+int qos_resctrl_online_cpu(unsigned int cpu);
+int qos_resctrl_offline_cpu(unsigned int cpu);
+
+struct cbqri_resctrl_res {
+ struct rdt_resource resctrl_res;
+ u32 max_rcid;
+ u32 max_mcid;
+};
+
+struct cbqri_resctrl_dom {
+ struct rdt_ctrl_domain resctrl_ctrl_dom;
+ struct cbqri_controller *hw_ctrl;
+};
+
+struct cbqri_config {
+ u64 cbm; /* capacity block mask */
+ u64 rbwb; /* reserved bandwidth blocks */
+};
+
+#endif /* _ASM_RISCV_QOS_INTERNAL_H */
diff --git a/arch/riscv/kernel/qos/qos_resctrl.c b/arch/riscv/kernel/qos/qos_resctrl.c
new file mode 100644
index 000000000000..6d294f2f2504
--- /dev/null
+++ b/arch/riscv/kernel/qos/qos_resctrl.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "qos: resctrl: " fmt
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/resctrl.h>
+#include <linux/riscv_qos.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <asm/csr.h>
+#include <asm/qos.h>
+#include "internal.h"
+
+static struct cbqri_resctrl_res cbqri_resctrl_resources[RDT_NUM_RESOURCES];
+
+static bool exposed_alloc_capable;
+/* CDP (code data prioritization) on x86 is AT (access type) on RISC-V */
+static bool exposed_cdp_l2_capable;
+static bool exposed_cdp_l3_capable;
+static bool is_cdp_l2_enabled;
+static bool is_cdp_l3_enabled;
+
+/* used by resctrl_arch_system_num_rmid_idx() */
+static u32 max_rmid;
+
+LIST_HEAD(cbqri_controllers);
+
+static int cbqri_wait_busy_flag(struct cbqri_controller *ctrl, int reg_offset,
+ u64 *regp);
+
+/* Set capacity block mask (cc_block_mask) */
+static void cbqri_set_cbm(struct cbqri_controller *ctrl, u64 cbm)
+{
+ iowrite64(cbm, ctrl->base + CBQRI_CC_BLOCK_MASK_OFF);
+}
+
+/* Set the Rbwb (reserved bandwidth blocks) field in bc_bw_alloc */
+static void cbqri_set_rbwb(struct cbqri_controller *ctrl, u64 rbwb)
+{
+ u64 reg;
+
+ reg = ioread64(ctrl->base + CBQRI_BC_BW_ALLOC_OFF);
+ reg &= ~CBQRI_CONTROL_REGISTERS_RBWB_MASK;
+ reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_RBWB_MASK, rbwb);
+ iowrite64(reg, ctrl->base + CBQRI_BC_BW_ALLOC_OFF);
+}
+
+/* Get the Rbwb (reserved bandwidth blocks) field in bc_bw_alloc */
+static u64 cbqri_get_rbwb(struct cbqri_controller *ctrl)
+{
+ u64 reg;
+
+ reg = ioread64(ctrl->base + CBQRI_BC_BW_ALLOC_OFF);
+ return FIELD_GET(CBQRI_CONTROL_REGISTERS_RBWB_MASK, reg);
+}
+
+static int cbqri_wait_busy_flag(struct cbqri_controller *ctrl, int reg_offset,
+ u64 *regp)
+{
+ u64 reg;
+ int ret;
+
+ ret = readq_poll_timeout_atomic(ctrl->base + reg_offset, reg,
+ !FIELD_GET(CBQRI_CONTROL_REGISTERS_BUSY_MASK, reg),
+ 0, 1000);
+ if (!ret && regp)
+ *regp = reg;
+
+ return ret;
+}
+
+/* Perform capacity allocation control operation on capacity controller */
+static int cbqri_cc_alloc_op(struct cbqri_controller *ctrl, int operation, int rcid,
+ enum resctrl_conf_type type)
+{
+ int reg_offset = CBQRI_CC_ALLOC_CTL_OFF;
+ int status;
+ u64 reg;
+
+ reg = ioread64(ctrl->base + reg_offset);
+ reg &= ~CBQRI_CONTROL_REGISTERS_OP_MASK;
+ reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_OP_MASK, operation);
+ reg &= ~CBQRI_CONTROL_REGISTERS_RCID_MASK;
+ reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_RCID_MASK, rcid);
+
+ /* CBQRI capacity AT is only supported on L2 and L3 caches for now */
+ if (ctrl->type == CBQRI_CONTROLLER_TYPE_CAPACITY &&
+ ((ctrl->cache.cache_level == 2 && is_cdp_l2_enabled) ||
+ (ctrl->cache.cache_level == 3 && is_cdp_l3_enabled))) {
+ reg &= ~CBQRI_CONTROL_REGISTERS_AT_MASK;
+ switch (type) {
+ case CDP_CODE:
+ reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_AT_MASK,
+ CBQRI_CONTROL_REGISTERS_AT_CODE);
+ break;
+ case CDP_DATA:
+ default:
+ reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_AT_MASK,
+ CBQRI_CONTROL_REGISTERS_AT_DATA);
+ break;
+ }
+ }
+
+ iowrite64(reg, ctrl->base + reg_offset);
+
+ if (cbqri_wait_busy_flag(ctrl, reg_offset, ®) < 0) {
+ pr_err("%s(): BUSY timeout when executing the operation\n", __func__);
+ return -EIO;
+ }
+
+ status = FIELD_GET(CBQRI_CONTROL_REGISTERS_STATUS_MASK, reg);
+ if (status != CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS) {
+ pr_err("%s(): operation %d failed: status=%d\n", __func__, operation, status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * Write a capacity block mask and verify the hardware accepted it by
+ * reading back the value after a CONFIG_LIMIT + READ_LIMIT sequence.
+ */
+static int cbqri_apply_cache_config(struct cbqri_resctrl_dom *hw_dom, u32 closid,
+ enum resctrl_conf_type type, struct cbqri_config *cfg)
+{
+ struct cbqri_controller *ctrl = hw_dom->hw_ctrl;
+ int err = 0;
+ u64 reg;
+
+ spin_lock(&ctrl->lock);
+
+ /* Set capacity block mask (cc_block_mask) */
+ cbqri_set_cbm(ctrl, cfg->cbm);
+
+ /* Capacity config limit operation */
+ err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT, closid, type);
+ if (err < 0) {
+ pr_err("%s(): operation failed: err = %d\n", __func__, err);
+ goto out;
+ }
+
+ /* Clear cc_block_mask before read limit to verify op works */
+ cbqri_set_cbm(ctrl, 0);
+
+ /* Perform a capacity read limit operation to verify blockmask */
+ err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid, type);
+ if (err < 0) {
+ pr_err("%s(): operation failed: err = %d\n", __func__, err);
+ goto out;
+ }
+
+ /* Read capacity blockmask to verify it matches the requested config */
+ reg = ioread64(ctrl->base + CBQRI_CC_BLOCK_MASK_OFF);
+ if (reg != cfg->cbm) {
+ pr_err("%s(): failed to verify allocation (reg:%llx != cbm:%llx)\n",
+ __func__, reg, cfg->cbm);
+ err = -EIO;
+ }
+
+out:
+ spin_unlock(&ctrl->lock);
+ return err;
+}
+
+/* Perform bandwidth allocation control operation on bandwidth controller */
+static int cbqri_bc_alloc_op(struct cbqri_controller *ctrl, int operation, int rcid)
+{
+ int reg_offset = CBQRI_BC_ALLOC_CTL_OFF;
+ int status;
+ u64 reg;
+
+ reg = ioread64(ctrl->base + reg_offset);
+ reg &= ~CBQRI_CONTROL_REGISTERS_OP_MASK;
+ reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_OP_MASK, operation);
+ reg &= ~CBQRI_CONTROL_REGISTERS_RCID_MASK;
+ reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_RCID_MASK, rcid);
+ iowrite64(reg, ctrl->base + reg_offset);
+
+ if (cbqri_wait_busy_flag(ctrl, reg_offset, ®) < 0) {
+ pr_err("%s(): BUSY timeout when executing the operation\n", __func__);
+ return -EIO;
+ }
+
+ status = FIELD_GET(CBQRI_CONTROL_REGISTERS_STATUS_MASK, reg);
+ if (status != CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS) {
+ pr_err("%s(): operation %d failed with status = %d\n",
+ __func__, operation, status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * Write a bandwidth reservation and verify the hardware accepted it by
+ * reading back the value after a CONFIG_LIMIT + READ_LIMIT sequence.
+ */
+static int cbqri_apply_bw_config(struct cbqri_resctrl_dom *hw_dom, u32 closid,
+ enum resctrl_conf_type type, struct cbqri_config *cfg)
+{
+ struct cbqri_controller *ctrl = hw_dom->hw_ctrl;
+ int ret = 0;
+ u64 reg;
+
+ spin_lock(&ctrl->lock);
+
+ /* Set reserved bandwidth blocks */
+ cbqri_set_rbwb(ctrl, cfg->rbwb);
+
+ /* Bandwidth config limit operation */
+ ret = cbqri_bc_alloc_op(ctrl, CBQRI_BC_ALLOC_CTL_OP_CONFIG_LIMIT, closid);
+ if (ret < 0) {
+ pr_err("%s(): operation failed: ret = %d\n", __func__, ret);
+ goto out;
+ }
+
+ /* Clear rbwb before read limit to verify op works */
+ cbqri_set_rbwb(ctrl, 0);
+
+ /* Bandwidth allocation read limit operation to verify */
+ ret = cbqri_bc_alloc_op(ctrl, CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT, closid);
+ if (ret < 0)
+ goto out;
+
+ /* Read bandwidth allocation to verify it matches the requested config */
+ reg = cbqri_get_rbwb(ctrl);
+ if (reg != cfg->rbwb) {
+ pr_err("%s(): failed to verify allocation (reg:%llx != rbwb:%llu)\n",
+ __func__, reg, cfg->rbwb);
+ ret = -EIO;
+ }
+
+out:
+ spin_unlock(&ctrl->lock);
+ return ret;
+}
+
+static int cbqri_probe_feature(struct cbqri_controller *ctrl, int reg_offset,
+ int operation, int *status, bool *access_type_supported)
+{
+ u64 reg, saved_reg;
+ int at;
+
+ /* Keep the initial register value to preserve the WPRI fields */
+ reg = ioread64(ctrl->base + reg_offset);
+ saved_reg = reg;
+
+ /* Execute the requested operation to find if the register is implemented */
+ reg &= ~CBQRI_CONTROL_REGISTERS_OP_MASK;
+ reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_OP_MASK, operation);
+ iowrite64(reg, ctrl->base + reg_offset);
+ if (cbqri_wait_busy_flag(ctrl, reg_offset, ®) < 0) {
+ pr_err("%s(): BUSY timeout when executing the operation\n", __func__);
+ return -EIO;
+ }
+
+ /* Get the operation status */
+ *status = FIELD_GET(CBQRI_CONTROL_REGISTERS_STATUS_MASK, reg);
+
+ /*
+ * Check for the AT support if the register is implemented
+ * (if not, the status value will remain 0)
+ */
+ if (*status != 0) {
+ /* Set the AT field to a valid value */
+ reg = saved_reg;
+ reg &= ~CBQRI_CONTROL_REGISTERS_AT_MASK;
+ reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_AT_MASK,
+ CBQRI_CONTROL_REGISTERS_AT_CODE);
+ iowrite64(reg, ctrl->base + reg_offset);
+ if (cbqri_wait_busy_flag(ctrl, reg_offset, ®) < 0) {
+ pr_err("%s(): BUSY timeout when setting AT field\n", __func__);
+ return -EIO;
+ }
+
+ /*
+ * If the AT field value has been reset to zero,
+ * then the AT support is not present
+ */
+ at = FIELD_GET(CBQRI_CONTROL_REGISTERS_AT_MASK, reg);
+ if (at == CBQRI_CONTROL_REGISTERS_AT_CODE)
+ *access_type_supported = true;
+ else
+ *access_type_supported = false;
+ }
+
+ /* Restore the original register value */
+ iowrite64(saved_reg, ctrl->base + reg_offset);
+ if (cbqri_wait_busy_flag(ctrl, reg_offset, NULL) < 0) {
+ pr_err("%s(): BUSY timeout when restoring the original register value\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int cbqri_probe_cc(struct cbqri_controller *ctrl)
+{
+ int err, status;
+ u64 reg;
+
+ reg = ioread64(ctrl->base + CBQRI_CC_CAPABILITIES_OFF);
+ if (reg == 0)
+ return -ENODEV;
+
+ ctrl->ver_minor = FIELD_GET(CBQRI_CC_CAPABILITIES_VER_MINOR_MASK, reg);
+ ctrl->ver_major = FIELD_GET(CBQRI_CC_CAPABILITIES_VER_MAJOR_MASK, reg);
+ ctrl->cc.supports_alloc_op_flush_rcid =
+ FIELD_GET(CBQRI_CC_CAPABILITIES_FRCID_MASK, reg);
+ ctrl->cc.ncblks = FIELD_GET(CBQRI_CC_CAPABILITIES_NCBLKS_MASK, reg);
+
+ pr_debug("version=%d.%d ncblks=%d cache_level=%d\n",
+ ctrl->ver_major, ctrl->ver_minor,
+ ctrl->cc.ncblks, ctrl->cache.cache_level);
+
+ /* Probe allocation features (monitoring not yet implemented) */
+ err = cbqri_probe_feature(ctrl, CBQRI_CC_ALLOC_CTL_OFF,
+ CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT,
+ &status, &ctrl->cc.supports_alloc_at_code);
+ if (err)
+ return err;
+
+ if (status == CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS) {
+ ctrl->alloc_capable = true;
+ exposed_alloc_capable = true;
+ }
+
+ return 0;
+}
+
+static int cbqri_probe_bc(struct cbqri_controller *ctrl)
+{
+ int err, status;
+ u64 reg;
+
+ reg = ioread64(ctrl->base + CBQRI_BC_CAPABILITIES_OFF);
+ if (reg == 0)
+ return -ENODEV;
+
+ ctrl->ver_minor = FIELD_GET(CBQRI_BC_CAPABILITIES_VER_MINOR_MASK, reg);
+ ctrl->ver_major = FIELD_GET(CBQRI_BC_CAPABILITIES_VER_MAJOR_MASK, reg);
+ ctrl->bc.nbwblks = FIELD_GET(CBQRI_BC_CAPABILITIES_NBWBLKS_MASK, reg);
+ ctrl->bc.mrbwb = FIELD_GET(CBQRI_BC_CAPABILITIES_MRBWB_MASK, reg);
+
+ if (!ctrl->bc.nbwblks) {
+ pr_err("bandwidth controller has nbwblks=0\n");
+ return -EINVAL;
+ }
+
+ pr_debug("version=%d.%d nbwblks=%d mrbwb=%d\n",
+ ctrl->ver_major, ctrl->ver_minor,
+ ctrl->bc.nbwblks, ctrl->bc.mrbwb);
+
+ /* Probe allocation features (monitoring not yet implemented) */
+ err = cbqri_probe_feature(ctrl, CBQRI_BC_ALLOC_CTL_OFF,
+ CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT,
+ &status, &ctrl->bc.supports_alloc_at_code);
+ if (err)
+ return err;
+
+ if (status == CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS) {
+ ctrl->alloc_capable = true;
+ exposed_alloc_capable = true;
+ }
+
+ return 0;
+}
+
+static int cbqri_probe_controller(struct cbqri_controller *ctrl)
+{
+ int err;
+
+ pr_debug("controller info: type=%d addr=%pa size=%pa max-rcid=%u max-mcid=%u\n",
+ ctrl->type, &ctrl->addr, &ctrl->size,
+ ctrl->rcid_count, ctrl->mcid_count);
+
+ if (!ctrl->addr) {
+ pr_warn("%s(): controller has invalid addr=0x0, skipping\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!request_mem_region(ctrl->addr, ctrl->size, "cbqri_controller")) {
+ pr_err("%s(): request_mem_region failed for %pa\n",
+ __func__, &ctrl->addr);
+ return -EBUSY;
+ }
+
+ ctrl->base = ioremap(ctrl->addr, ctrl->size);
+ if (!ctrl->base) {
+ pr_err("%s(): ioremap failed for %pa\n", __func__, &ctrl->addr);
+ err = -ENOMEM;
+ goto err_release;
+ }
+
+ spin_lock_init(&ctrl->lock);
+
+ switch (ctrl->type) {
+ case CBQRI_CONTROLLER_TYPE_CAPACITY:
+ err = cbqri_probe_cc(ctrl);
+ break;
+ case CBQRI_CONTROLLER_TYPE_BANDWIDTH:
+ err = cbqri_probe_bc(ctrl);
+ break;
+ default:
+ pr_err("unknown controller type %d\n", ctrl->type);
+ err = -ENODEV;
+ break;
+ }
+
+ if (err)
+ goto err_iounmap;
+
+ /*
+ * max_rmid is used by resctrl_arch_system_num_rmid_idx()
+ * Find the smallest mcid_count amongst all controllers.
+ */
+ max_rmid = min(max_rmid, ctrl->mcid_count);
+
+ return 0;
+
+err_iounmap:
+ iounmap(ctrl->base);
+ ctrl->base = NULL;
+err_release:
+ release_mem_region(ctrl->addr, ctrl->size);
+ return err;
+}
diff --git a/include/linux/riscv_qos.h b/include/linux/riscv_qos.h
new file mode 100644
index 000000000000..0f3daae2e84f
--- /dev/null
+++ b/include/linux/riscv_qos.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __LINUX_RISCV_QOS_H
+#define __LINUX_RISCV_QOS_H
+
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/qos.h>
+
+enum cbqri_controller_type {
+ CBQRI_CONTROLLER_TYPE_CAPACITY,
+ CBQRI_CONTROLLER_TYPE_BANDWIDTH,
+ CBQRI_CONTROLLER_TYPE_UNKNOWN
+};
+
+/* Capacity Controller hardware capabilities */
+struct riscv_cbqri_capacity_caps {
+ u16 ncblks; /* number of capacity blocks */
+
+ bool supports_alloc_at_code;
+ bool supports_alloc_op_flush_rcid;
+};
+
+/* Bandwidth Controller hardware capabilities */
+struct riscv_cbqri_bandwidth_caps {
+ u16 nbwblks; /* number of bandwidth blocks */
+ u16 mrbwb; /* max reserved bw blocks */
+
+ bool supports_alloc_at_code;
+};
+
+struct cbqri_controller {
+ void __iomem *base;
+ /*
+ * Protects multi-step MMIO register sequences on this controller.
+ * CBQRI operations (e.g. CONFIG_LIMIT, READ_LIMIT) require writing
+ * an operation register, waiting for the busy flag to clear, then
+ * reading back the result. These sequences must be atomic per
+ * controller to prevent interleaving.
+ */
+ spinlock_t lock;
+
+ int ver_major;
+ int ver_minor;
+
+ struct riscv_cbqri_bandwidth_caps bc;
+ struct riscv_cbqri_capacity_caps cc;
+
+ bool alloc_capable;
+
+ phys_addr_t addr;
+ phys_addr_t size;
+ enum cbqri_controller_type type;
+ u32 rcid_count;
+ u32 mcid_count;
+ struct list_head list;
+
+ struct cache_controller {
+ u32 cache_level;
+ u32 cache_size; /* in bytes */
+ struct cpumask cpu_mask;
+ /* Unique Cache ID from the PPTT table's Cache Type Structure */
+ u32 cache_id;
+ } cache;
+
+ struct mem_controller {
+ /* Proximity Domain from SRAT table Memory Affinity Controller */
+ u32 prox_dom;
+ struct cpumask cpu_mask;
+ } mem;
+};
+
+extern struct list_head cbqri_controllers;
+
+#endif /* __LINUX_RISCV_QOS_H */
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v3 03/11] RISC-V: Add support for srmcfg CSR from Ssqosid extension
From: Drew Fustini @ 2026-04-15 1:53 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Drew Fustini
Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
devicetree, Paul Walmsley
In-Reply-To: <20260414-ssqosid-cbqri-rqsc-v7-0-v3-0-b3b2e7e9847a@kernel.org>
Add support for the srmcfg CSR defined in the Ssqosid ISA extension.
The CSR contains two fields:
- Resource Control ID (RCID) for resource allocation
- Monitoring Counter ID (MCID) for tracking resource usage
Requests from a hart to shared resources are tagged with these IDs,
allowing resource usage to be associated with the running task.
Add a srmcfg field to thread_struct with the same format as the CSR so
the scheduler can set the RCID and MCID for each task on context switch.
A per-cpu cpu_srmcfg variable mirrors the CSR state to avoid redundant
writes, as L1D-hot memory access is faster than a CSR read and avoids
traps under virtualization.
Add a per-cpu cpu_srmcfg_default variable to store the default srmcfg
for each CPU, as set by resctrl CPU group assignment. On context switch,
if the next task belongs to the default resource group (srmcfg == 0),
the CPU's default value is used instead. This implements resctrl
resource allocation rule 2: default-group tasks on a CPU assigned to a
specific group receive that group's allocations.
Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
Co-developed-by: Kornel Dulęba <mindal@semihalf.com>
Signed-off-by: Kornel Dulęba <mindal@semihalf.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
MAINTAINERS | 8 ++++++
arch/riscv/Kconfig | 17 +++++++++++++
arch/riscv/include/asm/csr.h | 6 +++++
arch/riscv/include/asm/processor.h | 3 +++
arch/riscv/include/asm/qos.h | 52 ++++++++++++++++++++++++++++++++++++++
arch/riscv/include/asm/switch_to.h | 3 +++
arch/riscv/kernel/Makefile | 2 ++
arch/riscv/kernel/qos/Makefile | 2 ++
arch/riscv/kernel/qos/qos.c | 8 ++++++
9 files changed, 101 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index c3fe46d7c4bc..b17f885411ba 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22778,6 +22778,14 @@ F: drivers/perf/riscv_pmu.c
F: drivers/perf/riscv_pmu_legacy.c
F: drivers/perf/riscv_pmu_sbi.c
+RISC-V QOS RESCTRL SUPPORT
+M: Drew Fustini <fustini@kernel.org>
+R: yunhui cui <cuiyunhui@bytedance.com>
+L: linux-riscv@lists.infradead.org
+S: Supported
+F: arch/riscv/include/asm/qos.h
+F: arch/riscv/kernel/qos/
+
RISC-V RPMI AND MPXY DRIVERS
M: Rahul Pathak <rahul@summations.net>
M: Anup Patel <anup@brainfault.org>
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 90c531e6abf5..92d2265a0c61 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -595,6 +595,23 @@ config RISCV_ISA_SVNAPOT
If you don't know what to do here, say Y.
+config RISCV_ISA_SSQOSID
+ bool "Ssqosid extension support for supervisor mode Quality of Service ID"
+ default n
+ help
+ Adds support for the Ssqosid ISA extension (Supervisor-mode
+ Quality of Service ID).
+
+ Ssqosid defines the srmcfg CSR which allows the system to tag the
+ running process with an RCID (Resource Control ID) and MCID
+ (Monitoring Counter ID). The RCID is used to determine resource
+ allocation. The MCID is used to track resource usage in event
+ counters.
+
+ For example, a cache controller may use the RCID to apply a
+ cache partitioning scheme and use the MCID to track how much
+ cache a process, or a group of processes, is using.
+
config RISCV_ISA_SVPBMT
bool "Svpbmt extension support for supervisor mode page-based memory types"
depends on 64BIT && MMU
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 31b8988f4488..dc13835bd661 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -84,6 +84,11 @@
#define SATP_ASID_MASK _AC(0xFFFF, UL)
#endif
+/* SRMCFG fields */
+#define SRMCFG_RCID_MASK _AC(0x00000FFF, UL)
+#define SRMCFG_MCID_MASK _AC(0x00000FFF, UL)
+#define SRMCFG_MCID_SHIFT 16
+
/* Exception cause high bit - is an interrupt if set */
#define CAUSE_IRQ_FLAG (_AC(1, UL) << (__riscv_xlen - 1))
@@ -328,6 +333,7 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
#define CSR_SATP 0x180
+#define CSR_SRMCFG 0x181
#define CSR_STIMECMP 0x14D
#define CSR_STIMECMPH 0x15D
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 4c3dd94d0f63..feaee2502593 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -123,6 +123,9 @@ struct thread_struct {
/* A forced icache flush is not needed if migrating to the previous cpu. */
unsigned int prev_cpu;
#endif
+#ifdef CONFIG_RISCV_ISA_SSQOSID
+ u32 srmcfg;
+#endif
};
/* Whitelist the fstate from the task_struct for hardened usercopy */
diff --git a/arch/riscv/include/asm/qos.h b/arch/riscv/include/asm/qos.h
new file mode 100644
index 000000000000..aa96bb5a153c
--- /dev/null
+++ b/arch/riscv/include/asm/qos.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_RISCV_QOS_H
+#define _ASM_RISCV_QOS_H
+
+#ifdef CONFIG_RISCV_ISA_SSQOSID
+
+#include <linux/sched.h>
+
+#include <asm/csr.h>
+#include <asm/hwcap.h>
+
+/* cached value of srmcfg csr for each cpu */
+DECLARE_PER_CPU(u32, cpu_srmcfg);
+
+/* default srmcfg value for each cpu, set via resctrl cpu assignment */
+DECLARE_PER_CPU(u32, cpu_srmcfg_default);
+
+static inline void __switch_to_srmcfg(struct task_struct *next)
+{
+ u32 thread_srmcfg;
+
+ thread_srmcfg = READ_ONCE(next->thread.srmcfg);
+
+ /*
+ * Tasks in the default resource group have closid=0 and rmid=0,
+ * so thread.srmcfg is 0. For these tasks, use this CPU's default
+ * srmcfg instead. This implements resctrl rule 2: a default-group
+ * task running on a CPU assigned to a specific group uses that
+ * group's allocations.
+ */
+ if (thread_srmcfg == 0)
+ thread_srmcfg = __this_cpu_read(cpu_srmcfg_default);
+
+ if (thread_srmcfg != __this_cpu_read(cpu_srmcfg)) {
+ __this_cpu_write(cpu_srmcfg, thread_srmcfg);
+ csr_write(CSR_SRMCFG, thread_srmcfg);
+ }
+}
+
+static __always_inline bool has_srmcfg(void)
+{
+ return riscv_has_extension_unlikely(RISCV_ISA_EXT_SSQOSID);
+}
+
+#else /* ! CONFIG_RISCV_ISA_SSQOSID */
+
+struct task_struct;
+static __always_inline bool has_srmcfg(void) { return false; }
+static inline void __switch_to_srmcfg(struct task_struct *next) { }
+
+#endif /* CONFIG_RISCV_ISA_SSQOSID */
+#endif /* _ASM_RISCV_QOS_H */
diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
index 0e71eb82f920..1c7ea53ec012 100644
--- a/arch/riscv/include/asm/switch_to.h
+++ b/arch/riscv/include/asm/switch_to.h
@@ -14,6 +14,7 @@
#include <asm/processor.h>
#include <asm/ptrace.h>
#include <asm/csr.h>
+#include <asm/qos.h>
#ifdef CONFIG_FPU
extern void __fstate_save(struct task_struct *save_to);
@@ -119,6 +120,8 @@ do { \
__switch_to_fpu(__prev, __next); \
if (has_vector() || has_xtheadvector()) \
__switch_to_vector(__prev, __next); \
+ if (has_srmcfg()) \
+ __switch_to_srmcfg(__next); \
if (switch_to_should_flush_icache(__next)) \
local_flush_icache_all(); \
__switch_to_envcfg(__next); \
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index cabb99cadfb6..82157aae6401 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -128,3 +128,5 @@ obj-$(CONFIG_ACPI_NUMA) += acpi_numa.o
obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += bugs.o
obj-$(CONFIG_RISCV_USER_CFI) += usercfi.o
+
+obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos/
diff --git a/arch/riscv/kernel/qos/Makefile b/arch/riscv/kernel/qos/Makefile
new file mode 100644
index 000000000000..9f996263a86d
--- /dev/null
+++ b/arch/riscv/kernel/qos/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos.o
diff --git a/arch/riscv/kernel/qos/qos.c b/arch/riscv/kernel/qos/qos.c
new file mode 100644
index 000000000000..a3c2b910e2e0
--- /dev/null
+++ b/arch/riscv/kernel/qos/qos.c
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <asm/qos.h>
+
+/* cached value of srmcfg csr for each cpu */
+DEFINE_PER_CPU(u32, cpu_srmcfg);
+
+/* default srmcfg value for each cpu, set via resctrl cpu assignment */
+DEFINE_PER_CPU(u32, cpu_srmcfg_default);
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v3 02/11] RISC-V: Detect the Ssqosid extension
From: Drew Fustini @ 2026-04-15 1:53 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Drew Fustini
Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
devicetree, Paul Walmsley
In-Reply-To: <20260414-ssqosid-cbqri-rqsc-v7-0-v3-0-b3b2e7e9847a@kernel.org>
Ssqosid is the RISC-V Quality-of-Service (QoS) Identifiers specification
which defines the Supervisor Resource Management Configuration (srmcfg)
register.
Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
Co-developed-by: Kornel Dulęba <mindal@semihalf.com>
Signed-off-by: Kornel Dulęba <mindal@semihalf.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
arch/riscv/include/asm/hwcap.h | 1 +
arch/riscv/kernel/cpufeature.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 7ef8e5f55c8d..b83dae5cebb9 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -112,6 +112,7 @@
#define RISCV_ISA_EXT_ZCLSD 103
#define RISCV_ISA_EXT_ZICFILP 104
#define RISCV_ISA_EXT_ZICFISS 105
+#define RISCV_ISA_EXT_SSQOSID 106
#define RISCV_ISA_EXT_XLINUXENVCFG 127
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 1734f9a4c2fd..c0717a861a3c 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -582,6 +582,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
__RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA),
__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
__RISCV_ISA_EXT_SUPERSET(ssnpm, RISCV_ISA_EXT_SSNPM, riscv_xlinuxenvcfg_exts),
+ __RISCV_ISA_EXT_DATA(ssqosid, RISCV_ISA_EXT_SSQOSID),
__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
__RISCV_ISA_EXT_DATA(svade, RISCV_ISA_EXT_SVADE),
__RISCV_ISA_EXT_DATA_VALIDATE(svadu, RISCV_ISA_EXT_SVADU, riscv_ext_svadu_validate),
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v3 01/11] dt-bindings: riscv: Add Ssqosid extension description
From: Drew Fustini @ 2026-04-15 1:53 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Drew Fustini
Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
devicetree, Paul Walmsley
In-Reply-To: <20260414-ssqosid-cbqri-rqsc-v7-0-v3-0-b3b2e7e9847a@kernel.org>
Document the ratified Supervisor-mode Quality of Service ID (Ssqosid)
extension v1.0.
Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
Documentation/devicetree/bindings/riscv/extensions.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index c6ec9290fe07..1f3853a68760 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -232,6 +232,12 @@ properties:
ratified at commit d70011dde6c2 ("Update to ratified state")
of riscv-j-extension.
+ - const: ssqosid
+ description: |
+ The Ssqosid extension for Quality of Service ID is ratified
+ as v1.0 in commit 5059e0ca641c ("Merge pull request #7 from
+ ved-rivos/Ratified") of riscv-ssqosid.
+
- const: ssstateen
description: |
The standard Ssstateen extension for supervisor-mode view of the
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v3 00/11] RISC-V: QoS: add CBQRI resctrl interface
From: Drew Fustini @ 2026-04-15 1:53 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Drew Fustini
Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
devicetree, Paul Walmsley
This RFC series adds RISC-V Quality-of-Service support: the Ssqosid
extension [1] (srmcfg register), the CBQRI controller interface [2]
integrated with the kernel's resctrl subsystem [3], and ACPI RQSC [4]
table support for controller discovery. Device tree support is possible
but no platform drivers are included. All patches are available as a
branch [5].
There is a QEMU patch series [6] that implements Ssqosid and CBQRI. ACPI
RQSC support is implemented as a set of additional patches [7]. All of
the QEMU patches are available as a branch [8].
[1] https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
[2] https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
[3] https://docs.kernel.org/filesystems/resctrl.html
[4] https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/
[5] https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git/log/?h=b4/ssqosid-cbqri-rqsc
[6] https://lore.kernel.org/qemu-devel/20260105-riscv-ssqosid-cbqri-v4-0-9ad7671dde78@kernel.org/
[7] https://lore.kernel.org/qemu-devel/20260202-riscv-rqsc-v1-0-dcf448a3ed73@kernel.org/
[8] https://github.com/tt-fustini/qemu/tree/b4/riscv-rqsc
Series organization
-------------------
01: DT binding for Ssqosid extension
02-03: Ssqosid ISA support (detection, srmcfg CSR and switch_to)
04-07: CBQRI resctrl (hw interface, arch callbacks, domain
management, Kconfig/build wiring)
08-11: ACPI support (PPTT helper, actbl2.h RQSC structs [DO NOT
MERGE], RQSC parser, controller initialization)
RISC-V QoS
----------
QoS (Quality of Service) in this context is concerned with shared
resources on an SoC such as cache capacity and memory bandwidth.
The Ssqosid extension defines the srmcfg CSR which configures a hart
with two identifiers:
- Resource Control ID (RCID)
- Monitoring Counter ID (MCID)
These identifiers accompany each request issued by the hart to shared
resource controllers. This allows the capacity and bandwidth resources
used by a software workload (e.g. a process or a set of processes) to be
controlled and monitored.
CBQRI defines operations to configure resource usage limits, in the form
of capacity or bandwidth, for an RCID. CBQRI also defines operations to
configure counters to track resource utilization per MCID. Furthermore,
the Access Type (AT) field allows resource usage to be differentiated
between data and code.
x86 comparison
--------------
The existing QoS identifiers on x86 map well to RISC-V:
CLOSID (Class of Service ID) on x86 is RCID on RISC-V
RMID (Resource Monitoring ID) on x86 is MCID on RISC-V
In addition, CDP (code data prioritization) on x86 is similar to the
AT (access type) field in CBQRI which defines code and data types.
One aspect of CBQRI that simplifies the RISC-V resctrl interface is that
any CPU (technically a hart, or hardware thread, in RISC-V terminology)
can access the memory-mapped registers of any CBQRI controller in the
system. This means it does not matter which CPU runs the resctrl code.
Example SoC
-----------
This series was developed and tested using the QEMU virt platform
configured as a hypothetical SoC with a cache controller that implements
CBQRI capacity operations and a memory controller that implements CBQRI
bandwidth operations.
- L2 cache controllers
- Resource type: Capacity
- Number of capacity blocks (NCBLKS): 12
- In the context of a set-associative cache, the number of
capacity blocks can be thought of as the number of ways
- Number of access types: 2 (code and data)
- Usage monitoring not supported
- Capacity allocation operations: CONFIG_LIMIT, READ_LIMIT
- Last-level cache (LLC) controller
- Resource type: Capacity
- Number of capacity blocks (NCBLKS): 16
- Number of access types: 2 (code and data)
- Usage monitoring operations: CONFIG_EVENT, READ_COUNTER
- Event IDs supported: None, Occupancy
- Capacity allocation ops: CONFIG_LIMIT, READ_LIMIT, FLUSH_RCID
- Memory controllers
- Resource type: Bandwidth
- Number of bandwidth blocks (NBWBLKS): 1024
- Bandwidth blocks do not have a unit but instead represent a
portion of the total bandwidth resource. For NBWBLKS of 1024,
each block represents about 0.1% of the bandwidth resource.
- Maximum reserved bandwidth blocks (MRBWB): 819 (80% of NBWBLKS)
- Number of access types: 1 (no code/data differentiation)
- Usage monitoring operations: CONFIG_EVENT, READ_COUNTER
- Event IDs supported: None, Total read/write byte count, Total
read byte count, Total write byte count
- Bandwidth allocation operations: CONFIG_LIMIT, READ_LIMIT
The memory map for this example SoC:
Base addr Size
0x4820000 4KB Cluster 0 L2 cache controller
0x4821000 4KB Cluster 1 L2 cache controller
0x4828000 4KB Memory controller 0
0x4829000 4KB Memory controller 1
0x482a000 4KB Memory controller 2
0x482b000 4KB Shared LLC cache controller
This configuration is only meant to provide a "concrete" example, and it
represents just one of many possible ways that hardware can implement
the CBQRI spec.
The example SoC configuration is created with the following:
qemu-system-riscv64 \
-M virt,pflash0=pflash0,pflash1=pflash1,aia=aplic-imsic \
-smp cpus=8,sockets=1,clusters=2,cores=4,threads=1 \
-m 1G \
-nographic \
-kernel ${LINUX}/arch/riscv/boot/Image \
-append "root=/dev/vda rootwait" \
-blockdev node-name=pflash0,driver=file,read-only=on,filename=${EDK}/RISCV_VIRT_CODE.fd \
-blockdev node-name=pflash1,driver=file,filename=${EDK}/RISCV_VIRT_VARS.fd \
-drive if=none,file=${ROOTFS}/rootfs.ext2,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-device qemu-xhci \
-device usb-kbd \
-device virtio-net-pci,netdev=net0 \
-netdev user,id=net0 \
-device riscv.cbqri.capacity,max_mcids=256,max_rcids=64,ncblks=12,alloc_op_flush_rcid=false,mon_op_config_event=false,mon_op_read_counter=false,mon_evt_id_none=false,mon_evt_id_occupancy=false,mmio_base=0x04820000 \
-device riscv.cbqri.capacity,max_mcids=256,max_rcids=64,ncblks=12,alloc_op_flush_rcid=false,mon_op_config_event=false,mon_op_read_counter=false,mon_evt_id_none=false,mon_evt_id_occupancy=false,mmio_base=0x04821000 \
-device riscv.cbqri.capacity,max_mcids=256,max_rcids=64,ncblks=16,mmio_base=0x0482B000 \
-device riscv.cbqri.bandwidth,max_mcids=256,max_rcids=64,nbwblks=1024,mrbwb=819,mmio_base=0x04828000 \
-device riscv.cbqri.bandwidth,max_mcids=256,max_rcids=64,nbwblks=1024,mrbwb=819,mmio_base=0x04829000 \
-device riscv.cbqri.bandwidth,max_mcids=256,max_rcids=64,nbwblks=1024,mrbwb=819,mmio_base=0x0482a000
Open issues:
------------
- RQSC structs in actbl2.h must go through ACPICA upstream first. The
spec is in the final phase before ratification.
- No L2 and L3 cache occupancy monitoring
- This is not currently implemented and I have decided to leave
it for a followup series.
- No MBM (bandwidth monitoring)
- MBA schema works ok for the CBQRI-enabled memory controllers, but
resctrl does not currently have a solution for representing MBM for
bandwidth resources that are not associated with a L3 cache.
- For the old CBQRI proof-of-concept RFC, two separate domains were
created for each memory controller: one for MB (allocation) and one
for MBM (monitoring). The monitoring domains had to pretend that
these memory controllers were L3 caches which is not the case. I
have removed this as it was too complicated and not the right
solution.
Changelog
---------
Changes in v3:
Series restructuring:
- Restructure from 17 to 11 patches: introduce data structures
alongside their first users, consolidate build wiring into a
single "enable resctrl" commit
- Split the monolithic patch 08/17 into separate patches for HW
interface, arch callbacks, domain management, and Kconfig wiring
- Do not expose monitoring to resctrl; allocation only for now.
A separate followup series will add cache occupancy monitoring.
Bandwidth monitoring will have to wait for the larger issue of non-L3
bandwidth to be resolved first.
Bug fixes from v2 review:
- Fix cbqri_apply_bw_config() and resctrl_arch_get_config() using
capacity operation constants instead of bandwidth
- Fix missing err = -ENOMEM after ioremap() failure
- Fix ver_major not shifted after masking with GENMASK(7, 4)
- Fix ctrl->mcid_count = node->rcid in RQSC parser
Improvements from v2 review:
- Implement resctrl_arch_set_cpu_default_closid_rmid() (was no-op),
use per-cpu cpu_srmcfg_default for resctrl allocation rule 2
- Remove hw_dom->ctrl_val[] cache, read/write CBQRI registers directly
- Drop resctrl_arch_find_domain(), use resctrl_find_domain() directly
- Use sorted domain insertion via resctrl_find_domain()
- Set domain id from cache_id (capacity) or prox_dom (bandwidth)
- Define RISCV_RESCTRL_EMPTY_CLOSID instead of referencing x86 constant
- Find minimum mcid_count across controllers for max_rmid
- Convert SHIFT/MASK pairs to GENMASK() and FIELD_GET()/FIELD_PREP()
- Use acpi_pptt_get_cpumask_from_cache_id() instead of hardcoding
- Remove fixed-size f[6] array in RQSC; parse with ACPI_ADD_PTR and
flexible array for resource descriptors
Error handling and robustness:
- Implement resctrl_arch_reset_all_ctrls() to reset all CLOSID
allocations to defaults on unmount, including CDP code/data entries
- Capture resctrl_init() return and cleanup on failure
- Call resctrl_exit() on cpuhp_setup_state() failure
- Call resctrl_offline_ctrl_domain() before freeing in error path
- Check resctrl_find_domain() return to reject duplicate domain ids
- Validate nbwblks!=0 during probe; bounds-check RQSC res[0] access
- Skip controllers with bad cpumask instead of adding with empty mask
- Validate resource capabilities match across controllers at same
cache level
Bandwidth allocation:
- Derive max_bw from hardware MRBWB/NBWBLKS with DIV_ROUND_UP()
- Clamp rbwb to mrbwb so write/readback round-trips exactly
- Copy cpu_mask for bandwidth domains from proximity domain NUMA node
Hardware interface:
- Return final register from cbqri_wait_busy_flag() to eliminate
redundant MMIO reads after busy-wait
- Add per-controller spinlock for MMIO register sequence serialization
- Use readq_poll_timeout_atomic() instead of hand-rolled jiffies loop
- Move max_rmid update after successful controller probe
Cleanup:
- Add lockdep_assert_cpus_held() in resctrl_arch_update_domains()
and resctrl_arch_reset_all_ctrls()
- Mark acpi_parse_rqsc() __init
- Convert __switch_to_srmcfg() stub from macro to static inline to
make both checkpatch and clang happy
- Use pr_debug for per-controller details, pr_warn for non-fatal skips
- Remove unused arch stubs and dead code
- Use GENMASK_ULL for bits>=32, io-64-nonatomic-lo-hi.h for rv32
Link to v2: https://lore.kernel.org/r/20260128-ssqosid-cbqri-v2-0-dca586b091b9@kernel.org
Changes in v2:
- Add support for ACPI RQSC table which provides the details needed to
discover the CBQRI controllers and support resctrl
- Drop the "not for upstream" platform drivers and QEMU dts patches.
Those can be found in v1 and were only for the RFC series. The
branch for the v1 series is preserved as ssqosid-cbqri-rfc-v1
- Change cbqri_wait_busy_flag() from 100 ms to 1 ms to avoid
unnecessary latency.
- Change resctrl_arch_get_config() to return resctrl_get_default_ctrl()
instead of a negative errno value which is not valid for u32.
- Change cbqri_probe_controller() to return -EBUSY when
request_mem_region() fails
- Change resctrl_arch_get_config() to no longer increment when rbwb
modulo ctrl->bc.nbwblks is true
- Fix indentation in cbqri_set_cbm(), cbqri_set_rbwb() and
cbqri_get_rbwb().
- Link to v1: https://lore.kernel.org/r/20260119-ssqosid-cbqri-v1-0-aa2a75153832@kernel.org
---
Drew Fustini (11):
dt-bindings: riscv: Add Ssqosid extension description
RISC-V: Detect the Ssqosid extension
RISC-V: Add support for srmcfg CSR from Ssqosid extension
RISC-V: QoS: add CBQRI hardware interface
RISC-V: QoS: add resctrl arch callbacks for CBQRI controllers
RISC-V: QoS: add resctrl setup and domain management
RISC-V: QoS: enable resctrl support for Ssqosid
ACPI: PPTT: Add acpi_pptt_get_cache_size_from_id helper
DO NOT MERGE: include: acpi: actbl2: Add structs for RQSC table
ACPI: RISC-V: Parse RISC-V Quality of Service Controller (RQSC) table
ACPI: RISC-V: Add support for RISC-V Quality of Service Controller (RQSC)
.../devicetree/bindings/riscv/extensions.yaml | 6 +
MAINTAINERS | 11 +
arch/riscv/Kconfig | 20 +
arch/riscv/include/asm/acpi.h | 10 +
arch/riscv/include/asm/csr.h | 6 +
arch/riscv/include/asm/hwcap.h | 1 +
arch/riscv/include/asm/processor.h | 3 +
arch/riscv/include/asm/qos.h | 52 +
arch/riscv/include/asm/resctrl.h | 7 +
arch/riscv/include/asm/switch_to.h | 3 +
arch/riscv/kernel/Makefile | 2 +
arch/riscv/kernel/cpufeature.c | 1 +
arch/riscv/kernel/qos/Makefile | 2 +
arch/riscv/kernel/qos/internal.h | 81 ++
arch/riscv/kernel/qos/qos.c | 40 +
arch/riscv/kernel/qos/qos_resctrl.c | 1092 ++++++++++++++++++++
drivers/acpi/pptt.c | 63 ++
drivers/acpi/riscv/Makefile | 1 +
drivers/acpi/riscv/init.c | 23 +
drivers/acpi/riscv/rqsc.c | 136 +++
include/acpi/actbl2.h | 36 +
include/linux/acpi.h | 8 +
include/linux/riscv_qos.h | 109 ++
23 files changed, 1713 insertions(+)
---
base-commit: 7aaa8047eafd0bd628065b15757d9b48c5f9c07d
change-id: 20260329-ssqosid-cbqri-rqsc-v7-0-b0c788bab48a
Best regards,
--
Drew Fustini <fustini@kernel.org>
^ permalink raw reply
* RE: [PATCH v7 2/2] iio: dac: ad5706r: Add support for AD5706R DAC
From: Torreno, Alexis Czezar @ 2026-04-15 1:10 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Lars-Peter Clausen, Hennerich, Michael, David Lechner, Sa, Nuno,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, Andy Shevchenko
In-Reply-To: <20260414195400.60d39158@jic23-huawei>
> > +#define AD5706R_DAC_RESOLUTION 16
> > +#define AD5706R_DAC_MAX_CODE BIT(16)
>
> Trivial but I'd expect something called MAX_CODE to be GENMASK(15, 0) not
> BIT(16). E.g. inclusive limit.
Since it's dac code I guess this makes better sense, will edit.
>
> > +#define AD5706R_MULTIBYTE_REG_START 0x14
> > +#define AD5706R_MULTIBYTE_REG_END 0x71
> > +#define AD5706R_MAX_REG 0x77
> > +#define AD5706R_SINGLE_BYTE_LEN 1
> > +#define AD5706R_DOUBLE_BYTE_LEN 2
>
> See below. I'm not sure these two defines bring us anything.
>
> > +
> > +struct ad5706r_state {
> > + struct spi_device *spi;
> > + struct regmap *regmap;
> > +
> > + u8 tx_buf[4] __aligned(IIO_DMA_MINALIGN);
> > + u8 rx_buf[4];
> > +};
> > +
> > +static int ad5706r_reg_len(unsigned int reg) {
> > + if (reg >= AD5706R_MULTIBYTE_REG_START && reg <=
> AD5706R_MULTIBYTE_REG_END)
> > + return AD5706R_DOUBLE_BYTE_LEN;
>
> What do the defines for 2 == 2-bytes and 1 == 1-byte bring us over using
> numbers directly? E.g.
>
> if (reg >= AD5706R_MULTIBYTE_REG_START && reg <=
> AD5706R_MULTIBYTE_REG_END)
> return 2;
> return 1;
>
I suppose not much, it won't change in the future so a hard "1" or "2" can work.
Will remove the defines and just put the actual number
> > +
> > + return AD5706R_SINGLE_BYTE_LEN;
> > +}
> > +
> > +static int ad5706r_regmap_write(void *context, const void *data,
> > +size_t count) {
> > + struct ad5706r_state *st = context;
> > + unsigned int num_bytes, val;
> > + u16 reg;
> > +
> > + if (count != 4)
> > + return -EINVAL;
> > +
> > + reg = get_unaligned_be16(data);
> > + num_bytes = ad5706r_reg_len(reg);
> > +
> > + struct spi_transfer xfer = {
> > + .tx_buf = st->tx_buf,
> > + .len = num_bytes + 2,
> > + };
> > +
> > + val = get_unaligned_be32(data);
> > + put_unaligned_be32(val, &st->tx_buf[0]);
> > +
> > + /* For single byte, copy the data to the correct position */
> > + if (num_bytes == AD5706R_SINGLE_BYTE_LEN)
> > + st->tx_buf[2] = st->tx_buf[3];
>
> This does feel a bit odd vs using if / else if as you do in the read case. Also,
> same as above wrt to single bytes having a length of
> 1 meaning that just using a 1 might be easier to read.
Unlike in the read, I thought it would be simpler to copy the whole data of 4bytes,
then just correct the buffer during single_byte.
Should I make it similarly coded with the read()?
>
> > +
> > + return spi_sync_transfer(st->spi, &xfer, 1); }
>
> > +static int ad5706r_write_raw(struct iio_dev *indio_dev,
> > + struct iio_chan_spec const *chan,
> > + int val, int val2, long mask) {
> > + struct ad5706r_state *st = iio_priv(indio_dev);
> > + unsigned int reg;
> > +
> > + switch (mask) {
> > + case IIO_CHAN_INFO_RAW:
> > + if (!in_range(val, 0, AD5706R_DAC_MAX_CODE))
>
> I'm not seeing a strong reason to use in_range() here (hopefully I didn't
> suggest it in an earlier review ;) It make sense when we have a val >= base &&
> val < base + length. With base as 0 and MAX_CODE not 'obviously' from it's
> name being the length (it only is becauset he base is 0) this seems odd.
>
> if (val < 0 || val >= AD5706R_DAC_MAX_CODE) Though see
> above on MAX_CODE not being the maximum code...
>
I think around v3 Andy suggested the use of in_range, as the function itself helps
document what the line does. Is this a style preference?
Regards,
Alexis
^ permalink raw reply
* Re: [PATCH v3 2/4] phy: axiado: add Axiado eMMC PHY driver
From: Tzu-Hao Wei @ 2026-04-15 0:55 UTC (permalink / raw)
To: SriNavmani A, Prasad Bolisetty, Vinod Koul, Neil Armstrong,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-phy, devicetree, linux-arm-kernel, linux-kernel, openbmc
In-Reply-To: <20260317-axiado-ax3000-add-emmc-phy-driver-support-v3-2-fbf790f3f711@axiado.com>
On 3/18/2026 3:52 AM, Tzu-Hao Wei wrote:
> From: SriNavmani A <srinavmani@axiado.com>
>
> It provides the required configurations for Axiado eMMC PHY driver for
> HS200 mode.
>
> Signed-off-by: SriNavmani A <srinavmani@axiado.com>
> Co-developed-by: Prasad Bolisetty <pbolisetty@axiado.com>
> Signed-off-by: Prasad Bolisetty <pbolisetty@axiado.com>
> Signed-off-by: Tzu-Hao Wei <twei@axiado.com>
> ---
> drivers/phy/Kconfig | 1 +
> drivers/phy/Makefile | 1 +
> drivers/phy/axiado/Kconfig | 11 ++
> drivers/phy/axiado/Makefile | 1 +
> drivers/phy/axiado/phy-axiado-emmc.c | 217 +++++++++++++++++++++++++++++++++++
> 5 files changed, 231 insertions(+)
>
Hi Vinod,
Just a gentle ping on this patch series.
Since you reviewed the previous version, I wanted to check if you might have
a chance to take a look at this one when time permits.
Any feedback would be appreciated.
Best regards,
TH
^ permalink raw reply
* Re: [PATCH v8 0/2] i2c: Add Loongson-2K0300 I2C controller support
From: Andi Shyti @ 2026-04-14 22:31 UTC (permalink / raw)
To: Binbin Zhou
Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Wolfram Sang, Andy Shevchenko, linux-i2c,
Huacai Chen, Xuerui Wang, loongarch, devicetree
In-Reply-To: <cover.1776135865.git.zhoubinbin@loongson.cn>
Hi Binbin,
> Binbin Zhou (2):
> dt-bindings: i2c: loongson,ls2x: Add ls2k0300-i2c compatible
> i2c: ls2x-v2: Add driver for Loongson-2K0300 I2C controller
merged to i2c/i2c-host-v7.1
Thanks,
Andi
^ permalink raw reply
* Re: [PATCH v3] dt-bindings: i2c: cnxt,cx92755-i2c: Convert to DT schema
From: Andi Shyti @ 2026-04-14 22:22 UTC (permalink / raw)
To: Shi Hao; +Cc: krzk+dt, robh, conor+dt, linux-i2c, devicetree, linux-kernel
In-Reply-To: <20260411112451.35095-1-i.shihao.999@gmail.com>
Hi Shi,
On Sat, Apr 11, 2026 at 04:54:51PM +0530, Shi Hao wrote:
> Convert the Conexant Digicolor I2C bindings to DT schema.
>
> Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: Shi Hao <i.shihao.999@gmail.com>
merged to i2c/i2c-host-2.
Thanks,
Andi
^ permalink raw reply
* [PATCH v7 6/6] arm64: dts: rockchip: Add Orange Pi 5 Pro board support
From: Dennis Gilmore @ 2026-04-14 21:40 UTC (permalink / raw)
Cc: Alexey Charkov, Andrew Lunn, Andrzej Hajda, Chaoyi Chen,
Conor Dooley, David Airlie, Dennis Gilmore, devicetree, dri-devel,
FUKAUMI Naoki, Heiko Stuebner, Hsun Lai, Jernej Skrabec,
Jimmy Hon, John Clark, Jonas Karlman, Krzysztof Kozlowski,
Laurent Pinchart, linux-arm-kernel, linux-kernel, linux-rockchip,
Maarten Lankhorst, Maxime Ripard, Michael Opdenacker,
Michael Riesch, Mykola Kvach, Neil Armstrong, Peter Robinson,
Quentin Schulz, Robert Foss, Rob Herring, Simona Vetter,
Thomas Zimmermann
In-Reply-To: <20260414214104.1363987-1-dennis@ausil.us>
Add device tree for the Xunlong Orange Pi 5 Pro (RK3588S).
- eMMC module, you can optionally solder a SPI NOR in place and turn
off the eMMC
- PCIe-attached NIC (pcie2x1l1)
- PCIe NVMe slot (pcie2x1l2)
- AP6256 WiFi (BCM43456) via SDIO with mmc-pwrseq
- BCM4345C5 Bluetooth
- es8388 audio
- USB 2.0 and USB 3.0
- Two HDMI ports, the second is connected to the SoC's DP controller
driven through a Lontium LT8711UXD bridge.
Vendors schematics are available at:
https://drive.google.com/file/d/1qs1DratHuh7C6J6MEtQIwUsiSrg8qgTi/view
Signed-off-by: Dennis Gilmore <dennis@ausil.us>
---
arch/arm64/boot/dts/rockchip/Makefile | 1 +
.../dts/rockchip/rk3588s-orangepi-5-pro.dts | 442 ++++++++++++++++++
2 files changed, 443 insertions(+)
create mode 100644 arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5-pro.dts
diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index 4d384f153c13..c99dca2ae9e7 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -214,6 +214,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-nanopi-r6c.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-odroid-m2.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-orangepi-5.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-orangepi-5b.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-orangepi-5-pro.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-orangepi-cm5-base.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-radxa-cm5-io.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-roc-pc.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5-pro.dts b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5-pro.dts
new file mode 100644
index 000000000000..61462c66753d
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5-pro.dts
@@ -0,0 +1,442 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include "rk3588s-orangepi-5.dtsi"
+
+/ {
+ model = "Xunlong Orange Pi 5 Pro";
+ compatible = "xunlong,orangepi-5-pro", "rockchip,rk3588s";
+
+ aliases {
+ mmc0 = &sdhci;
+ mmc1 = &sdmmc;
+ mmc2 = &sdio;
+ };
+
+ hdmi1-con {
+ compatible = "hdmi-connector";
+ label = "HDMI1 OUT";
+ type = "a";
+
+ port {
+ hdmi1_con_in: endpoint {
+ remote-endpoint = <<8711uxd_out>;
+ };
+ };
+ };
+
+ lt8711uxd {
+ compatible = "lontium,lt8711uxd";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ lt8711uxd_in: endpoint {
+ remote-endpoint = <&dp0_out_con>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ lt8711uxd_out: endpoint {
+ remote-endpoint = <&hdmi1_con_in>;
+ };
+ };
+ };
+ };
+
+ analog-sound {
+ compatible = "simple-audio-card";
+ pinctrl-names = "default";
+ pinctrl-0 = <&hp_detect>;
+ simple-audio-card,format = "i2s";
+ simple-audio-card,hp-det-gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>;
+ simple-audio-card,mclk-fs = <256>;
+ simple-audio-card,name = "rockchip,es8388";
+ simple-audio-card,routing =
+ "Headphones", "LOUT1",
+ "Headphones", "ROUT1",
+ "LINPUT1", "Microphone Jack",
+ "RINPUT1", "Microphone Jack",
+ "LINPUT2", "Onboard Microphone",
+ "RINPUT2", "Onboard Microphone";
+ simple-audio-card,widgets =
+ "Microphone", "Microphone Jack",
+ "Microphone", "Onboard Microphone",
+ "Headphone", "Headphones";
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s2_2ch>;
+ };
+
+ simple-audio-card,codec {
+ sound-dai = <&es8388>;
+ system-clock-frequency = <12288000>;
+ };
+ };
+
+ pwm-leds {
+ compatible = "pwm-leds";
+
+ led-0 {
+ color = <LED_COLOR_ID_BLUE>;
+ function = LED_FUNCTION_STATUS;
+ linux,default-trigger = "heartbeat";
+ max-brightness = <255>;
+ pwms = <&pwm15 0 1000000 0>;
+ };
+
+ led-1 {
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_ACTIVITY;
+ linux,default-trigger = "heartbeat";
+ max-brightness = <255>;
+ pwms = <&pwm3 0 1000000 0>;
+ };
+ };
+
+ fan: pwm-fan {
+ compatible = "pwm-fan";
+ #cooling-cells = <2>;
+ cooling-levels = <0 50 100 150 200 255>;
+ fan-supply = <&vcc5v0_sys>;
+ pwms = <&pwm2 0 20000000 0>;
+ };
+
+ vcc3v3_dp: regulator-vcc3v3-dp {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dp_bridge_en>;
+ regulator-max-microvolt = <3300000>;
+ regulator-min-microvolt = <3300000>;
+ regulator-name = "vcc3v3_dp";
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_3v3_s3>;
+ };
+
+ vcc3v3_phy1: regulator-vcc3v3-phy1 {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc3v3_phy1_en>;
+ regulator-max-microvolt = <3300000>;
+ regulator-min-microvolt = <3300000>;
+ regulator-name = "vcc3v3_phy1";
+ startup-delay-us = <50000>;
+ vin-supply = <&vcc_3v3_s3>;
+ };
+
+ vcc5v0_otg: regulator-vcc5v0-otg {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpios = <&gpio0 RK_PC4 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc5v0_otg_en>;
+ regulator-max-microvolt = <5000000>;
+ regulator-min-microvolt = <5000000>;
+ regulator-name = "vcc5v0_otg";
+ vin-supply = <&vcc5v0_sys>;
+ };
+
+ sdio_pwrseq: sdio-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&hym8563>;
+ clock-names = "ext_clock";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_enable_h>;
+ post-power-on-delay-ms = <200>;
+ reset-gpios = <&gpio0 RK_PD0 GPIO_ACTIVE_LOW>;
+ };
+
+ typea_con: usb-a-connector {
+ compatible = "usb-a-connector";
+ data-role = "host";
+ label = "USB3 Type-A";
+ power-role = "source";
+ vbus-supply = <&vcc5v0_otg>;
+ };
+};
+
+&dp0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dp0m0_pins>;
+ status = "okay";
+};
+
+&dp0_in {
+ dp0_in_vp1: endpoint {
+ remote-endpoint = <&vp1_out_dp0>;
+ };
+};
+
+&dp0_out {
+ dp0_out_con: endpoint {
+ remote-endpoint = <<8711uxd_in>;
+ };
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1m4_xfer>;
+ status = "okay";
+};
+
+&i2c3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c3m0_xfer>;
+ status = "okay";
+
+ es8388: audio-codec@11 {
+ compatible = "everest,es8388", "everest,es8328";
+ reg = <0x11>;
+ #sound-dai-cells = <0>;
+ AVDD-supply = <&vcca_3v3_s0>;
+ DVDD-supply = <&vcca_1v8_s0>;
+ HPVDD-supply = <&vcca_3v3_s0>;
+ PVDD-supply = <&vcca_1v8_s0>;
+ assigned-clock-rates = <12288000>;
+ assigned-clocks = <&cru I2S2_2CH_MCLKOUT>;
+ clocks = <&cru I2S2_2CH_MCLKOUT>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s2m1_mclk>;
+ };
+};
+
+&i2c4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4m3_xfer>;
+ status = "okay";
+};
+
+&i2s2_2ch {
+ pinctrl-0 = <&i2s2m1_lrck &i2s2m1_sclk
+ &i2s2m1_sdi &i2s2m1_sdo>;
+ status = "okay";
+};
+
+&package_thermal {
+ polling-delay = <1000>;
+
+ cooling-maps {
+ map0 {
+ trip = <&package_fan0>;
+ cooling-device = <&fan THERMAL_NO_LIMIT 1>;
+ };
+
+ map1 {
+ trip = <&package_fan1>;
+ cooling-device = <&fan 2 THERMAL_NO_LIMIT>;
+ };
+ };
+
+ trips {
+ package_fan0: package-fan0 {
+ hysteresis = <2000>;
+ temperature = <55000>;
+ type = "active";
+ };
+
+ package_fan1: package-fan1 {
+ hysteresis = <2000>;
+ temperature = <65000>;
+ type = "active";
+ };
+ };
+};
+
+/* NVMe */
+&pcie2x1l1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie2x1l1_rst &pcie30x1m1_1_clkreqn &pcie30x1m1_1_waken>;
+ reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
+ supports-clkreq;
+ vpcie3v3-supply = <&vcc_3v3_s3>;
+ status = "okay";
+};
+
+/* NIC */
+&pcie2x1l2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie2x1l2_rst>;
+ reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>;
+ vpcie3v3-supply = <&vcc3v3_phy1>;
+ status = "okay";
+};
+
+&pinctrl {
+ bluetooth {
+ bt_wake_gpio: bt-wake-pin {
+ rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ bt_wake_host_irq: bt-wake-host-irq {
+ rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+ };
+
+ dp {
+ dp_bridge_en: dp-bridge-en {
+ rockchip,pins = <3 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ pcie {
+ pcie2x1l1_rst: pcie2x1l1-rst {
+ rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ pcie2x1l2_rst: pcie2x1l2-rst {
+ rockchip,pins = <3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ vcc3v3_phy1_en: vcc3v3-phy1-en {
+ rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ usb {
+ vcc5v0_otg_en: vcc5v0-otg-en {
+ rockchip,pins = <0 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ wlan {
+ wifi_enable_h: wifi-enable-h {
+ rockchip,pins = <0 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ wifi_host_wake_irq: wifi-host-wake-irq {
+ rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+ };
+};
+
+&pwm15 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm15m2_pins>;
+ status = "okay";
+};
+
+&pwm2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm2m1_pins>;
+ status = "okay";
+};
+
+&pwm3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm3m2_pins>;
+ status = "okay";
+};
+
+&rk806_single {
+ regulators {
+ vcca_1v8_s0: pldo-reg1 {
+ regulator-name = "vcca_1v8_s0";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vcc_1v8_s0: pldo-reg2 {
+ regulator-name = "vcc_1v8_s0";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+ };
+};
+
+&sdhci {
+ status = "okay";
+};
+
+&sdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cap-sdio-irq;
+ keep-power-in-suspend;
+ max-frequency = <150000000>;
+ mmc-pwrseq = <&sdio_pwrseq>;
+ no-mmc;
+ no-sd;
+ non-removable;
+ sd-uhs-sdr104;
+ status = "okay";
+
+ ap6256: wifi@1 {
+ compatible = "brcm,bcm43456-fmac", "brcm,bcm4329-fmac";
+ reg = <1>;
+ interrupt-names = "host-wake";
+ interrupt-parent = <&gpio0>;
+ interrupts = <RK_PA0 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_host_wake_irq>;
+ };
+};
+
+&uart9 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart9m2_xfer &uart9m2_ctsn &uart9m2_rtsn>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm4345c5";
+ clocks = <&hym8563>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
+ interrupt-names = "host-wakeup";
+ interrupt-parent = <&gpio0>;
+ interrupts = <RK_PC5 IRQ_TYPE_LEVEL_HIGH>;
+ max-speed = <1500000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&bt_wake_host_irq &bt_wake_gpio>;
+ shutdown-gpios = <&gpio0 RK_PD5 GPIO_ACTIVE_HIGH>;
+ vbat-supply = <&vcc_3v3_s3>;
+ vddio-supply = <&vcc_1v8_s3>;
+ };
+};
+
+&usb_host0_xhci {
+ dr_mode = "host";
+};
+
+&usbdp_phy0 {
+ /*
+ * USBDP PHY0 is wired to a USB3 Type-A host connector via lanes 2/3.
+ * Additionally lanes 0/1 and the aux channel are wired to the
+ * Lontium LT8711UXD DP-to-HDMI bridge feeding the HDMI1 connector.
+ */
+ rockchip,dp-lane-mux = <0 1>;
+};
+
+&vp1 {
+ vp1_out_dp0: endpoint@a {
+ reg = <ROCKCHIP_VOP2_EP_DP0>;
+ remote-endpoint = <&dp0_in_vp1>;
+ };
+};
--
2.53.0
^ permalink raw reply related
* [PATCH v7 5/6] arm64: dts: rockchip: refactor items from Orange Pi 5/b to prep for Pro
From: Dennis Gilmore @ 2026-04-14 21:40 UTC (permalink / raw)
Cc: Alexey Charkov, Andrew Lunn, Andrzej Hajda, Chaoyi Chen,
Conor Dooley, David Airlie, Dennis Gilmore, devicetree, dri-devel,
FUKAUMI Naoki, Heiko Stuebner, Hsun Lai, Jernej Skrabec,
Jimmy Hon, John Clark, Jonas Karlman, Krzysztof Kozlowski,
Laurent Pinchart, linux-arm-kernel, linux-kernel, linux-rockchip,
Maarten Lankhorst, Maxime Ripard, Michael Opdenacker,
Michael Riesch, Mykola Kvach, Neil Armstrong, Peter Robinson,
Quentin Schulz, Robert Foss, Rob Herring, Simona Vetter,
Thomas Zimmermann
In-Reply-To: <20260414214104.1363987-1-dennis@ausil.us>
The Orange Pi 5 Pro uses the same SoC and base as the Orange Pi 5 and
Orange Pi 5B but has had sound, USB, and leds wired up differently. The
5 and 5B boards use gmac for ethernet where the Pro has a PCIe attached
NIC.
Move the 5/5B-specific bits (analog-sound/es8388, FUSB302 Type-C,
gmac1, pwm-leds, i2s1_8ch routing, USB role-switch plumbing) out of
rk3588s-orangepi-5.dtsi into a new rk3588s-orangepi-5-5b.dtsi that is
included by both 5 and 5B.
The RK806 PLDO1 and PLDO2 outputs are wired differently between the
5/5B and the Pro (PLDO1/PLDO2 are swapped), so label the PMIC node
rk806_single in the base dtsi, drop pldo-reg1/pldo-reg2 from it, and
define them via a &rk806_single regulators augmentation in
rk3588s-orangepi-5-5b.dtsi. The Pro will supply its own mapping.
Signed-off-by: Dennis Gilmore <dennis@ausil.us>
---
.../dts/rockchip/rk3588s-orangepi-5-5b.dtsi | 222 +++++++++++++++++
.../boot/dts/rockchip/rk3588s-orangepi-5.dts | 6 +-
.../boot/dts/rockchip/rk3588s-orangepi-5.dtsi | 225 +-----------------
.../boot/dts/rockchip/rk3588s-orangepi-5b.dts | 2 +-
4 files changed, 240 insertions(+), 215 deletions(-)
create mode 100644 arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5-5b.dtsi
diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5-5b.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5-5b.dtsi
new file mode 100644
index 000000000000..9e987ffa6241
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5-5b.dtsi
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device tree definitions shared by the Orange Pi 5 and Orange Pi 5B
+ * but not the Orange Pi 5 Pro.
+ */
+
+#include <dt-bindings/usb/pd.h>
+#include "rk3588s-orangepi-5.dtsi"
+
+/ {
+ aliases {
+ ethernet0 = &gmac1;
+ };
+
+ analog-sound {
+ compatible = "simple-audio-card";
+ pinctrl-names = "default";
+ pinctrl-0 = <&hp_detect>;
+ simple-audio-card,name = "rockchip,es8388";
+ simple-audio-card,bitclock-master = <&masterdai>;
+ simple-audio-card,format = "i2s";
+ simple-audio-card,frame-master = <&masterdai>;
+ simple-audio-card,hp-det-gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>;
+ simple-audio-card,mclk-fs = <256>;
+ simple-audio-card,routing =
+ "Headphones", "LOUT1",
+ "Headphones", "ROUT1",
+ "LINPUT1", "Microphone Jack",
+ "RINPUT1", "Microphone Jack",
+ "LINPUT2", "Onboard Microphone",
+ "RINPUT2", "Onboard Microphone";
+ simple-audio-card,widgets =
+ "Microphone", "Microphone Jack",
+ "Microphone", "Onboard Microphone",
+ "Headphone", "Headphones";
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s1_8ch>;
+ };
+
+ masterdai: simple-audio-card,codec {
+ sound-dai = <&es8388>;
+ system-clock-frequency = <12288000>;
+ };
+ };
+
+ pwm-leds {
+ compatible = "pwm-leds";
+
+ led {
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_STATUS;
+ linux,default-trigger = "heartbeat";
+ max-brightness = <255>;
+ pwms = <&pwm0 0 25000 0>;
+ };
+ };
+};
+
+&gmac1 {
+ clock_in_out = "output";
+ phy-handle = <&rgmii_phy1>;
+ phy-mode = "rgmii-rxid";
+ pinctrl-0 = <&gmac1_miim
+ &gmac1_tx_bus2
+ &gmac1_rx_bus2
+ &gmac1_rgmii_clk
+ &gmac1_rgmii_bus>;
+ pinctrl-names = "default";
+ tx_delay = <0x42>;
+ status = "okay";
+};
+
+&i2c6 {
+ es8388: audio-codec@10 {
+ compatible = "everest,es8388", "everest,es8328";
+ reg = <0x10>;
+ clocks = <&cru I2S1_8CH_MCLKOUT>;
+ AVDD-supply = <&vcca_3v3_s0>;
+ DVDD-supply = <&vcca_1v8_s0>;
+ HPVDD-supply = <&vcca_3v3_s0>;
+ PVDD-supply = <&vcca_3v3_s0>;
+ assigned-clocks = <&cru I2S1_8CH_MCLKOUT>;
+ assigned-clock-rates = <12288000>;
+ #sound-dai-cells = <0>;
+ };
+
+ usbc0: usb-typec@22 {
+ compatible = "fcs,fusb302";
+ reg = <0x22>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <RK_PD3 IRQ_TYPE_LEVEL_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&usbc0_int>;
+ vbus-supply = <&vbus_typec>;
+ status = "okay";
+
+ usb_con: connector {
+ compatible = "usb-c-connector";
+ label = "USB-C";
+ data-role = "dual";
+ op-sink-microwatt = <1000000>;
+ power-role = "dual";
+ sink-pdos =
+ <PDO_FIXED(5000, 1000, PDO_FIXED_USB_COMM)>;
+ source-pdos =
+ <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+ try-power-role = "source";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ usbc0_hs: endpoint {
+ remote-endpoint = <&usb_host0_xhci_drd_sw>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ usbc0_ss: endpoint {
+ remote-endpoint = <&usbdp_phy0_typec_ss>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ usbc0_sbu: endpoint {
+ remote-endpoint = <&usbdp_phy0_typec_sbu>;
+ };
+ };
+ };
+ };
+ };
+};
+
+&i2s1_8ch {
+ rockchip,i2s-tx-route = <3 2 1 0>;
+ rockchip,i2s-rx-route = <1 3 2 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s1m0_sclk
+ &i2s1m0_mclk
+ &i2s1m0_lrck
+ &i2s1m0_sdi1
+ &i2s1m0_sdo3>;
+ status = "okay";
+};
+
+&pwm0 {
+ pinctrl-0 = <&pwm0m2_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
+&rk806_single {
+ regulators {
+ vcc_1v8_s0: pldo-reg1 {
+ regulator-name = "vcc_1v8_s0";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcca_1v8_s0: pldo-reg2 {
+ regulator-name = "vcca_1v8_s0";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+ };
+};
+
+
+&usb_host0_xhci {
+ dr_mode = "otg";
+ usb-role-switch;
+
+ port {
+ usb_host0_xhci_drd_sw: endpoint {
+ remote-endpoint = <&usbc0_hs>;
+ };
+ };
+};
+
+&usb_host2_xhci {
+ status = "okay";
+};
+
+&usbdp_phy0 {
+ mode-switch;
+ orientation-switch;
+ sbu1-dc-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
+ sbu2-dc-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>;
+
+ port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ usbdp_phy0_typec_ss: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&usbc0_ss>;
+ };
+
+ usbdp_phy0_typec_sbu: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&usbc0_sbu>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts
index 83b9b6645a1e..d76bdf1b5e90 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts
@@ -2,12 +2,16 @@
/dts-v1/;
-#include "rk3588s-orangepi-5.dtsi"
+#include "rk3588s-orangepi-5-5b.dtsi"
/ {
model = "Xunlong Orange Pi 5";
compatible = "xunlong,orangepi-5", "rockchip,rk3588s";
+ aliases {
+ mmc0 = &sdmmc;
+ };
+
vcc3v3_pcie20: regulator-vcc3v3-pcie20 {
compatible = "regulator-fixed";
enable-active-high;
diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi
index fd5c6a025cd1..2b605e5fc35a 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi
@@ -3,19 +3,13 @@
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/leds/common.h>
#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include <dt-bindings/soc/rockchip,vop2.h>
-#include <dt-bindings/usb/pd.h>
#include "rk3588s.dtsi"
/ {
- aliases {
- ethernet0 = &gmac1;
- mmc0 = &sdmmc;
- };
-
chosen {
stdout-path = "serial2:1500000n8";
};
@@ -34,38 +28,6 @@ button-recovery {
};
};
- analog-sound {
- compatible = "simple-audio-card";
- pinctrl-names = "default";
- pinctrl-0 = <&hp_detect>;
- simple-audio-card,name = "rockchip,es8388";
- simple-audio-card,bitclock-master = <&masterdai>;
- simple-audio-card,format = "i2s";
- simple-audio-card,frame-master = <&masterdai>;
- simple-audio-card,hp-det-gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>;
- simple-audio-card,mclk-fs = <256>;
- simple-audio-card,routing =
- "Headphones", "LOUT1",
- "Headphones", "ROUT1",
- "LINPUT1", "Microphone Jack",
- "RINPUT1", "Microphone Jack",
- "LINPUT2", "Onboard Microphone",
- "RINPUT2", "Onboard Microphone";
- simple-audio-card,widgets =
- "Microphone", "Microphone Jack",
- "Microphone", "Onboard Microphone",
- "Headphone", "Headphones";
-
- simple-audio-card,cpu {
- sound-dai = <&i2s1_8ch>;
- };
-
- masterdai: simple-audio-card,codec {
- sound-dai = <&es8388>;
- system-clock-frequency = <12288000>;
- };
- };
-
hdmi0-con {
compatible = "hdmi-connector";
type = "a";
@@ -77,18 +39,6 @@ hdmi0_con_in: endpoint {
};
};
- pwm-leds {
- compatible = "pwm-leds";
-
- led {
- color = <LED_COLOR_ID_GREEN>;
- function = LED_FUNCTION_STATUS;
- linux,default-trigger = "heartbeat";
- max-brightness = <255>;
- pwms = <&pwm0 0 25000 0>;
- };
- };
-
vbus_typec: regulator-vbus-typec {
compatible = "regulator-fixed";
enable-active-high;
@@ -101,15 +51,6 @@ vbus_typec: regulator-vbus-typec {
vin-supply = <&vcc5v0_sys>;
};
- vcc5v0_sys: regulator-vcc5v0-sys {
- compatible = "regulator-fixed";
- regulator-name = "vcc5v0_sys";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- };
-
vcc_3v3_sd_s0: regulator-vcc-3v3-sd-s0 {
compatible = "regulator-fixed";
gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_LOW>;
@@ -119,6 +60,15 @@ vcc_3v3_sd_s0: regulator-vcc-3v3-sd-s0 {
regulator-max-microvolt = <3300000>;
vin-supply = <&vcc_3v3_s3>;
};
+
+ vcc5v0_sys: regulator-vcc5v0-sys {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_sys";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
};
&combphy0_ps {
@@ -161,20 +111,6 @@ &cpu_l3 {
cpu-supply = <&vdd_cpu_lit_s0>;
};
-&gmac1 {
- clock_in_out = "output";
- phy-handle = <&rgmii_phy1>;
- phy-mode = "rgmii-rxid";
- pinctrl-0 = <&gmac1_miim
- &gmac1_tx_bus2
- &gmac1_rx_bus2
- &gmac1_rgmii_clk
- &gmac1_rgmii_bus>;
- pinctrl-names = "default";
- tx_delay = <0x42>;
- status = "okay";
-};
-
&gpu {
mali-supply = <&vdd_gpu_s0>;
status = "okay";
@@ -270,69 +206,6 @@ &i2c6 {
pinctrl-0 = <&i2c6m3_xfer>;
status = "okay";
- es8388: audio-codec@10 {
- compatible = "everest,es8388", "everest,es8328";
- reg = <0x10>;
- clocks = <&cru I2S1_8CH_MCLKOUT>;
- AVDD-supply = <&vcca_3v3_s0>;
- DVDD-supply = <&vcca_1v8_s0>;
- HPVDD-supply = <&vcca_3v3_s0>;
- PVDD-supply = <&vcca_3v3_s0>;
- assigned-clocks = <&cru I2S1_8CH_MCLKOUT>;
- assigned-clock-rates = <12288000>;
- #sound-dai-cells = <0>;
- };
-
- usbc0: usb-typec@22 {
- compatible = "fcs,fusb302";
- reg = <0x22>;
- interrupt-parent = <&gpio0>;
- interrupts = <RK_PD3 IRQ_TYPE_LEVEL_LOW>;
- pinctrl-names = "default";
- pinctrl-0 = <&usbc0_int>;
- vbus-supply = <&vbus_typec>;
- status = "okay";
-
- usb_con: connector {
- compatible = "usb-c-connector";
- label = "USB-C";
- data-role = "dual";
- op-sink-microwatt = <1000000>;
- power-role = "dual";
- sink-pdos =
- <PDO_FIXED(5000, 1000, PDO_FIXED_USB_COMM)>;
- source-pdos =
- <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
- try-power-role = "source";
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- usbc0_hs: endpoint {
- remote-endpoint = <&usb_host0_xhci_drd_sw>;
- };
- };
-
- port@1 {
- reg = <1>;
- usbc0_ss: endpoint {
- remote-endpoint = <&usbdp_phy0_typec_ss>;
- };
- };
-
- port@2 {
- reg = <2>;
- usbc0_sbu: endpoint {
- remote-endpoint = <&usbdp_phy0_typec_sbu>;
- };
- };
- };
- };
- };
-
hym8563: rtc@51 {
compatible = "haoyu,hym8563";
reg = <0x51>;
@@ -346,18 +219,6 @@ hym8563: rtc@51 {
};
};
-&i2s1_8ch {
- rockchip,i2s-tx-route = <3 2 1 0>;
- rockchip,i2s-rx-route = <1 3 2 0>;
- pinctrl-names = "default";
- pinctrl-0 = <&i2s1m0_sclk
- &i2s1m0_mclk
- &i2s1m0_lrck
- &i2s1m0_sdi1
- &i2s1m0_sdo3>;
- status = "okay";
-};
-
&i2s5_8ch {
status = "okay";
};
@@ -404,12 +265,6 @@ typec5v_pwren: typec5v-pwren {
};
};
-&pwm0 {
- pinctrl-0 = <&pwm0m2_pins>;
- pinctrl-names = "default";
- status = "okay";
-};
-
&rknn_core_0 {
npu-supply = <&vdd_npu_s0>;
sram-supply = <&vdd_npu_s0>;
@@ -491,7 +346,7 @@ &spi2 {
pinctrl-names = "default";
pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
- pmic@0 {
+ rk806_single: pmic@0 {
compatible = "rockchip,rk806";
reg = <0x0>;
interrupt-parent = <&gpio0>;
@@ -666,31 +521,6 @@ regulator-state-mem {
};
};
- vcc_1v8_s0: pldo-reg1 {
- regulator-name = "vcc_1v8_s0";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
-
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- vcca_1v8_s0: pldo-reg2 {
- regulator-name = "vcca_1v8_s0";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
-
- regulator-state-mem {
- regulator-off-in-suspend;
- regulator-suspend-microvolt = <1800000>;
- };
- };
-
vdda_1v2_s0: pldo-reg3 {
regulator-name = "vdda_1v2_s0";
regulator-always-on;
@@ -841,26 +671,7 @@ &uart2 {
};
&usbdp_phy0 {
- mode-switch;
- orientation-switch;
- sbu1-dc-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
- sbu2-dc-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>;
status = "okay";
-
- port {
- #address-cells = <1>;
- #size-cells = <0>;
-
- usbdp_phy0_typec_ss: endpoint@0 {
- reg = <0>;
- remote-endpoint = <&usbc0_ss>;
- };
-
- usbdp_phy0_typec_sbu: endpoint@1 {
- reg = <1>;
- remote-endpoint = <&usbc0_sbu>;
- };
- };
};
&usb_host0_ehci {
@@ -872,15 +683,7 @@ &usb_host0_ohci {
};
&usb_host0_xhci {
- dr_mode = "otg";
- usb-role-switch;
status = "okay";
-
- port {
- usb_host0_xhci_drd_sw: endpoint {
- remote-endpoint = <&usbc0_hs>;
- };
- };
};
&usb_host1_ehci {
@@ -891,7 +694,7 @@ &usb_host1_ohci {
status = "okay";
};
-&usb_host2_xhci {
+&vop {
status = "okay";
};
@@ -899,10 +702,6 @@ &vop_mmu {
status = "okay";
};
-&vop {
- status = "okay";
-};
-
&vp0 {
vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 {
reg = <ROCKCHIP_VOP2_EP_HDMI0>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5b.dts
index d21ec320d295..8af174777809 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5b.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5b.dts
@@ -2,7 +2,7 @@
/dts-v1/;
-#include "rk3588s-orangepi-5.dtsi"
+#include "rk3588s-orangepi-5-5b.dtsi"
/ {
model = "Xunlong Orange Pi 5B";
--
2.53.0
^ permalink raw reply related
* [PATCH v7 4/6] arm64: dts: rockchip: rk3588s-orangepi-5: rename PLDO regulator labels to match schematic
From: Dennis Gilmore @ 2026-04-14 21:40 UTC (permalink / raw)
Cc: Alexey Charkov, Andrew Lunn, Andrzej Hajda, Chaoyi Chen,
Conor Dooley, David Airlie, Dennis Gilmore, devicetree, dri-devel,
FUKAUMI Naoki, Heiko Stuebner, Hsun Lai, Jernej Skrabec,
Jimmy Hon, John Clark, Jonas Karlman, Krzysztof Kozlowski,
Laurent Pinchart, linux-arm-kernel, linux-kernel, linux-rockchip,
Maarten Lankhorst, Maxime Ripard, Michael Opdenacker,
Michael Riesch, Mykola Kvach, Neil Armstrong, Peter Robinson,
Quentin Schulz, Robert Foss, Rob Herring, Simona Vetter,
Thomas Zimmermann
In-Reply-To: <20260414214104.1363987-1-dennis@ausil.us>
The Orange Pi 5, 5B and 5 Pro schematics label the RK806 PLDO outputs
using the pattern VCC_*_S0 / VCCA_*_S0 / VDDA_*_S0. Rename the base
dtsi regulator labels (and the es8388 supply references) to match:
pldo-reg1: avcc_1v8_s0 -> vcc_1v8_s0
pldo-reg2: vcc_1v8_s0 -> vcca_1v8_s0
pldo-reg3: avdd_1v2_s0 -> vdda_1v2_s0
pldo-reg4: vcc_3v3_s0 -> vcca_3v3_s0
Also update the saradc vref-supply reference to track the pldo-reg1
rename. No functional change.
Signed-off-by: Dennis Gilmore <dennis@ausil.us>
---
.../boot/dts/rockchip/rk3588s-orangepi-5.dtsi | 26 +++++++++----------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi
index dafad29f9854..fd5c6a025cd1 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi
@@ -274,10 +274,10 @@ es8388: audio-codec@10 {
compatible = "everest,es8388", "everest,es8328";
reg = <0x10>;
clocks = <&cru I2S1_8CH_MCLKOUT>;
- AVDD-supply = <&vcc_3v3_s0>;
- DVDD-supply = <&vcc_1v8_s0>;
- HPVDD-supply = <&vcc_3v3_s0>;
- PVDD-supply = <&vcc_3v3_s0>;
+ AVDD-supply = <&vcca_3v3_s0>;
+ DVDD-supply = <&vcca_1v8_s0>;
+ HPVDD-supply = <&vcca_3v3_s0>;
+ PVDD-supply = <&vcca_3v3_s0>;
assigned-clocks = <&cru I2S1_8CH_MCLKOUT>;
assigned-clock-rates = <12288000>;
#sound-dai-cells = <0>;
@@ -441,7 +441,7 @@ &rknn_mmu_2 {
};
&saradc {
- vref-supply = <&avcc_1v8_s0>;
+ vref-supply = <&vcc_1v8_s0>;
status = "okay";
};
@@ -666,8 +666,8 @@ regulator-state-mem {
};
};
- avcc_1v8_s0: pldo-reg1 {
- regulator-name = "avcc_1v8_s0";
+ vcc_1v8_s0: pldo-reg1 {
+ regulator-name = "vcc_1v8_s0";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <1800000>;
@@ -678,8 +678,8 @@ regulator-state-mem {
};
};
- vcc_1v8_s0: pldo-reg2 {
- regulator-name = "vcc_1v8_s0";
+ vcca_1v8_s0: pldo-reg2 {
+ regulator-name = "vcca_1v8_s0";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <1800000>;
@@ -691,8 +691,8 @@ regulator-state-mem {
};
};
- avdd_1v2_s0: pldo-reg3 {
- regulator-name = "avdd_1v2_s0";
+ vdda_1v2_s0: pldo-reg3 {
+ regulator-name = "vdda_1v2_s0";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <1200000>;
@@ -703,8 +703,8 @@ regulator-state-mem {
};
};
- vcc_3v3_s0: pldo-reg4 {
- regulator-name = "vcc_3v3_s0";
+ vcca_3v3_s0: pldo-reg4 {
+ regulator-name = "vcca_3v3_s0";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <3300000>;
--
2.53.0
^ permalink raw reply related
* [PATCH v7 3/6] drm/bridge: simple: Add the Lontium LT8711UXD DP-to-HDMI bridge
From: Dennis Gilmore @ 2026-04-14 21:40 UTC (permalink / raw)
Cc: Alexey Charkov, Andrew Lunn, Andrzej Hajda, Chaoyi Chen,
Conor Dooley, David Airlie, Dennis Gilmore, devicetree, dri-devel,
FUKAUMI Naoki, Heiko Stuebner, Hsun Lai, Jernej Skrabec,
Jimmy Hon, John Clark, Jonas Karlman, Krzysztof Kozlowski,
Laurent Pinchart, linux-arm-kernel, linux-kernel, linux-rockchip,
Maarten Lankhorst, Maxime Ripard, Michael Opdenacker,
Michael Riesch, Mykola Kvach, Neil Armstrong, Peter Robinson,
Quentin Schulz, Robert Foss, Rob Herring, Simona Vetter,
Thomas Zimmermann
In-Reply-To: <20260414214104.1363987-1-dennis@ausil.us>
The Lontium LT8711UXD is a high performance two lane Type-C/DP1.4
to HDMI2.0 converter, designed to connect a USB Type-C source or
a DP1.4 source to an HDMI2.0 sink.
Signed-off-by: Dennis Gilmore <dennis@ausil.us>
---
drivers/gpu/drm/bridge/simple-bridge.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c
index 8aa31ca3c72d..42c1f3d5ba0c 100644
--- a/drivers/gpu/drm/bridge/simple-bridge.c
+++ b/drivers/gpu/drm/bridge/simple-bridge.c
@@ -270,6 +270,11 @@ static const struct of_device_id simple_bridge_match[] = {
.data = &(const struct simple_bridge_info) {
.connector_type = DRM_MODE_CONNECTOR_HDMIA,
},
+ }, {
+ .compatible = "lontium,lt8711uxd",
+ .data = &(const struct simple_bridge_info) {
+ .connector_type = DRM_MODE_CONNECTOR_HDMIA,
+ },
}, {
.compatible = "parade,ps185hdm",
.data = &(const struct simple_bridge_info) {
--
2.53.0
^ permalink raw reply related
* [PATCH v7 2/6] dt-bindings: display: bridge: simple: document the Lontium LT8711UXD DP-to-HDMI bridge
From: Dennis Gilmore @ 2026-04-14 21:40 UTC (permalink / raw)
Cc: Alexey Charkov, Andrew Lunn, Andrzej Hajda, Chaoyi Chen,
Conor Dooley, David Airlie, Dennis Gilmore, devicetree, dri-devel,
FUKAUMI Naoki, Heiko Stuebner, Hsun Lai, Jernej Skrabec,
Jimmy Hon, John Clark, Jonas Karlman, Krzysztof Kozlowski,
Laurent Pinchart, linux-arm-kernel, linux-kernel, linux-rockchip,
Maarten Lankhorst, Maxime Ripard, Michael Opdenacker,
Michael Riesch, Mykola Kvach, Neil Armstrong, Peter Robinson,
Quentin Schulz, Robert Foss, Rob Herring, Simona Vetter,
Thomas Zimmermann
In-Reply-To: <20260414214104.1363987-1-dennis@ausil.us>
The Lontium LT8711UXD is a high performance two lane Type-C/DP1.4
to HDMI2.0 converter, designed to connect a USB Type-C source or
a DP1.4 source to an HDMI2.0 sink.
Signed-off-by: Dennis Gilmore <dennis@ausil.us>
---
.../devicetree/bindings/display/bridge/simple-bridge.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml
index e6808419f625..752c736c8f85 100644
--- a/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml
@@ -30,6 +30,7 @@ properties:
- algoltek,ag6311
- asl-tek,cs5263
- dumb-vga-dac
+ - lontium,lt8711uxd
- parade,ps185hdm
- radxa,ra620
- realtek,rtd2171
--
2.53.0
^ permalink raw reply related
* [PATCH v7 1/6] dt-bindings: arm: rockchip: Add Orange Pi 5 Pro
From: Dennis Gilmore @ 2026-04-14 21:40 UTC (permalink / raw)
Cc: Alexey Charkov, Andrew Lunn, Andrzej Hajda, Chaoyi Chen,
Conor Dooley, David Airlie, Dennis Gilmore, devicetree, dri-devel,
FUKAUMI Naoki, Heiko Stuebner, Hsun Lai, Jernej Skrabec,
Jimmy Hon, John Clark, Jonas Karlman, Krzysztof Kozlowski,
Laurent Pinchart, linux-arm-kernel, linux-kernel, linux-rockchip,
Maarten Lankhorst, Maxime Ripard, Michael Opdenacker,
Michael Riesch, Mykola Kvach, Neil Armstrong, Peter Robinson,
Quentin Schulz, Robert Foss, Rob Herring, Simona Vetter,
Thomas Zimmermann, Krzysztof Kozlowski
In-Reply-To: <20260414214104.1363987-1-dennis@ausil.us>
Add compatible string for the Orange Pi 5 Pro.
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Dennis Gilmore <dennis@ausil.us>
---
Documentation/devicetree/bindings/arm/rockchip.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
index ae77ded9fe47..3c6b83a84463 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -1320,6 +1320,7 @@ properties:
items:
- enum:
- xunlong,orangepi-5
+ - xunlong,orangepi-5-pro
- xunlong,orangepi-5b
- const: rockchip,rk3588s
--
2.53.0
^ permalink raw reply related
* [PATCH v7 0/6] Add support for Orange Pi 5 Pro
From: Dennis Gilmore @ 2026-04-14 21:40 UTC (permalink / raw)
Cc: Alexey Charkov, Andrew Lunn, Andrzej Hajda, Chaoyi Chen,
Conor Dooley, David Airlie, Dennis Gilmore, devicetree, dri-devel,
FUKAUMI Naoki, Heiko Stuebner, Hsun Lai, Jernej Skrabec,
Jimmy Hon, John Clark, Jonas Karlman, Krzysztof Kozlowski,
Laurent Pinchart, linux-arm-kernel, linux-kernel, linux-rockchip,
Maarten Lankhorst, Maxime Ripard, Michael Opdenacker,
Michael Riesch, Mykola Kvach, Neil Armstrong, Peter Robinson,
Quentin Schulz, Robert Foss, Rob Herring, Simona Vetter,
Thomas Zimmermann
This series adds initial support for Orange Pi 5 Pro. The PCIe attached
network driver(dwmac-motorcomm) was just added.
The series was tested against Linux 7.0-rc7
Please take a look.
Thank you,
Dennis Gilmore
Changes in v7:
- Fix up whitespace issues identified by checkpatch.pl --strict in
rk3588s-orangepi-5-5b.dtsi
- checkpatch gave a warning for WARNING: phy-mode "rgmii-rxid" without
comment, as this was moved over I left it untouched
- Added lontium,lt8711uxd to the compatible enum in the simple-bridge
binding
- Added lontium,lt8711uxd match entry with DRM_MODE_CONNECTOR_HDMIA to
the simple-bridge driver
- New patch to rename the regulator labels for the es8388 supplies to
match the schematics as they all use vcca_*
- RK806 PLDO1 and PLDO2 outputs are swapped between the 5/5B and pro.
move their definition to the shared 5/5B dtsi and 5 Pro dts
- Fixed ES8388 PVDD-supply — vcca_3v3_s0 → vcca_1v8_s0, 5 Pro is
different to 5 and 5b.
- analog-sound: use CPU-as-clock-master on the Pro. The ES8388 is wired to
i2s2_2ch (the only I2S block physically routed to the codec pins on this
board), which uses the legacy rockchip_i2s driver. That driver's
slave-mode trigger path hangs for 200 µs polling I2S_CLR and bails with
-ETIMEDOUT ("lrclk update failed"). The TDM-capable i2s0/i2s1/i2s5
blocks served by rockchip_i2s_tdm don't have this issue, which is why
other mainline ES8388 boards get away with bitclock-master = masterdai.
Drop bitclock-master/frame-master and the masterdai label to let the I2S
block generate BCLK/LRCK itself
- Added pinctrl entries for all GPIO pins (dp_bridge_en, vcc3v3_phy1_en,
wifi_enable_h, pcie2x1l1_rst, pcie2x1l2_rst)
- DP bridge rework — replaced dp-connector node with proper chain:
- lt8711uxd bridge node (compatible lontium,lt8711uxd, with port@0/port@1
endpoints). Bridge power is gated by the vcc3v3_dp regulator, whose
enable GPIO (GPIO3_PC2) is driven via the dp_bridge_en pinctrl group;
no enable-gpios/vdd-supply on the bridge node itself.
- hdmi1-con connector node (compatible hdmi-connector, type a)
- dp0_out endpoint now points to bridge input instead of old connector
- drop accidentally included, unrelated changes to
drivers/gpu/drm/bridge/synopsys/dw-dp.c and
Documentation/devicetree/bindings/display/rockchip/rockchip,dw-dp.yaml
- link to v6 https://lore.kernel.org/linux-devicetree/20260411024743.195385-1-dennis@ausil.us/
Changes in v6:
- Move the shared configs for the Orange Pi 5 and Orange Pi 5b from each
devices dts to a shared rk3588s-orangepi-5-5b.dtsi to avoid duplication
- Remove empty ports subnodeis from typea_con
- Move i2s2m1_mclk pinctrl from &i2s2 to the es8388 codec node
- Add dp-con, dp0_out, dp0_in, and vp1 nodes, plus the vcc3v3_dp regulator
in order to get the second HDMI port working via its transparent
LT8711UXD DP to HDMI bridge
- link to v5 https://lore.kernel.org/linux-devicetree/20260401010707.2584962-1-dennis@ausil.us/
Changes in v5:
- define a connector node for Type-A port, and list the regulator as its VBUS supply explicitly.
- Requires https://lore.kernel.org/all/20260217-typea-vbus-v1-1-657b4e55a4c2@flipper.net/
- link to v4 https://lore.kernel.org/linux-devicetree/20260310031002.3921234-1-dennis@ausil.us/
Changes in v4:
- rename vcc3v3_pcie20 copied from rk3588s-orangepi-5.dts to vcc3v3_phy1 to match the schematic
- use vcc_3v3_s3 as the supply not vcc5v0_sys for PCIe
- remove the definition for vcc3v3_pcie_m2 as it does not really exist
as a regulator
- link to v3 https://lore.kernel.org/linux-devicetree/20260306024634.239614-1-dennis@ausil.us/
Changes in v3:
- moved leds from gpio-leds to pwm-leds
- remove disable-wp from sdio
- rename vcc3v3_pcie_eth regulator to vcc3v3_pcie_m2 to reflect the
purppose
- actually clean up the delete lines and comments missed in v2
- link to v2 https://lore.kernel.org/linux-devicetree/20260304025521.210377-1-dennis@ausil.us/
Changes in v2:
- moved items not shared by orangepi 5/5b/5 Pro from dtsi to 5 and 5b
dts files
- removed all the comments and deleted properties from 5 Pro dts
- Link to v1 https://lore.kernel.org/linux-devicetree/20260228205418.2944620-1-dennis@ausil.us/
Dennis Gilmore (6):
dt-bindings: arm: rockchip: Add Orange Pi 5 Pro
dt-bindings: display: bridge: simple: document the Lontium LT8711UXD
DP-to-HDMI bridge
drm/bridge: simple: Add the Lontium LT8711UXD DP-to-HDMI bridge
arm64: dts: rockchip: rk3588s-orangepi-5: rename PLDO regulator labels
to match schematic
arm64: dts: rockchip: refactor items from Orange Pi 5/b to prep for
Pro
arm64: dts: rockchip: Add Orange Pi 5 Pro board support
.../devicetree/bindings/arm/rockchip.yaml | 1 +
.../display/bridge/simple-bridge.yaml | 1 +
arch/arm64/boot/dts/rockchip/Makefile | 1 +
.../dts/rockchip/rk3588s-orangepi-5-5b.dtsi | 222 +++++++++
.../dts/rockchip/rk3588s-orangepi-5-pro.dts | 442 ++++++++++++++++++
.../boot/dts/rockchip/rk3588s-orangepi-5.dts | 6 +-
.../boot/dts/rockchip/rk3588s-orangepi-5.dtsi | 235 +---------
.../boot/dts/rockchip/rk3588s-orangepi-5b.dts | 2 +-
drivers/gpu/drm/bridge/simple-bridge.c | 5 +
9 files changed, 695 insertions(+), 220 deletions(-)
create mode 100644 arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5-5b.dtsi
create mode 100644 arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5-pro.dts
--
2.53.0
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox