* [PATCH v4 26/27] media: rockchip: rga: add rga3 support
From: Sven Püschel @ 2026-03-25 14:50 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, Sven Püschel,
Nicolas Dufresne
In-Reply-To: <20260325-spu-rga3-v4-0-e90ec1c61354@pengutronix.de>
Add support for the RGA3 unit contained in the RK3588.
Only a basic feature set consisting of scaling and color conversion is
implemented. Currently unimplemented features include:
- Advanced formats like 10bit YUV, FBCE mode and Tile8x8 mode
- Background color (V4L2_CID_BG_COLOR)
- Configurable alpha value (V4L2_CID_ALPHA_COMPONENT)
- Image flipping (V4L2_CID_HFLIP and V4L2_CID_VFLIP)
- Image rotation (V4L2_CID_ROTATE)
- Image cropping/composing (VIDIOC_S_SELECTION)
- Only very basic output cropping for 1088 -> 1080 cases is implemented
The register address defines were copied from the
vendor Rockchip kernel sources and slightly adjusted to not start at 0
again for the cmd registers.
During testing it has been noted that the scaling of the hardware is
slightly incorrect. A test conversion of 128x128 RGBA to 256x256 RGBA
causes a slightly larger scaling. The scaling is suddle, as it seems
that the image is scaled to a 2px larger version and then cropped to
it's final size. Trying to use the RGA2 scaling factor calculation
didn't work. As the calculation matches the vendor kernel driver, no
further research has been utilized to check if there may be some kind of
better scaling factor calculation.
Furthermore comparing the RGA3 conversion with the GStreamer
videoconvertscale element, the chroma-site is different. A quick testing
didn't reveal a chroma-site that creates the same image with the
GStreamer Element. Also when converting from YUV to RGB the RGB values
differ by 1 or 2. This doesn't seem to be a colorspace conversion issue
but rather a slightly different precision on the calculation.
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
drivers/media/platform/rockchip/rga/Makefile | 2 +-
drivers/media/platform/rockchip/rga/rga.c | 4 +
drivers/media/platform/rockchip/rga/rga.h | 1 +
drivers/media/platform/rockchip/rga/rga3-hw.c | 507 ++++++++++++++++++++++++++
drivers/media/platform/rockchip/rga/rga3-hw.h | 192 ++++++++++
5 files changed, 705 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/rockchip/rga/Makefile b/drivers/media/platform/rockchip/rga/Makefile
index 1bbecdc3d8df2..7326a548f3dc7 100644
--- a/drivers/media/platform/rockchip/rga/Makefile
+++ b/drivers/media/platform/rockchip/rga/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-rockchip-rga-objs := rga.o rga-hw.o rga-buf.o
+rockchip-rga-objs := rga.o rga-hw.o rga3-hw.o rga-buf.o
obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index fd92ecf408e0c..5007f2a025b1d 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -910,6 +910,10 @@ static const struct of_device_id rockchip_rga_match[] = {
.compatible = "rockchip,rk3399-rga",
.data = &rga2_hw,
},
+ {
+ .compatible = "rockchip,rk3588-rga3",
+ .data = &rga3_hw,
+ },
{},
};
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 849b96392b780..bb225549db86e 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -166,5 +166,6 @@ static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
}
extern const struct rga_hw rga2_hw;
+extern const struct rga_hw rga3_hw;
#endif
diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.c b/drivers/media/platform/rockchip/rga/rga3-hw.c
new file mode 100644
index 0000000000000..213650edab962
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga3-hw.c
@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025-2026 Pengutronix e.K.
+ * Author: Sven Püschel <s.pueschel@pengutronix.de>
+ */
+
+#include <linux/pm_runtime.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/printk.h>
+
+#include <media/v4l2-common.h>
+
+#include "rga3-hw.h"
+#include "rga.h"
+
+static unsigned int rga3_get_scaling(unsigned int src, unsigned int dst)
+{
+ /*
+ * RGA3 scaling factor calculation as described in chapter 5.4.7 Resize
+ * of the TRM Part 2. The resulting scaling factor is a 16-bit value
+ * and therefore normalized with 2^16.
+ *
+ * While the TRM also mentions (dst-1)/(src-1) for the up-scaling case,
+ * it didn't work as the value always exceeds 16 bit. Flipping the
+ * factors results in a correct up-scaling. This is possible as the
+ * RGA3 has the RGA3_WIN_SCALE_XXX_UP bit to determine if it does
+ * an up or downscale.
+ *
+ * The scaling factor can potentially cause a slightly larger scaling
+ * (e.g. 1/2px larger scale and then cropped to the destination size).
+ * This can be seen when scaling 128x128px RGBA to 256x256px RGBA.
+ * The RGA2 scaling factor calculation (without the various +/-1
+ * doesn't work for the RGA3. It's assumed that this is an hardware
+ * accuracy limitation, as the vendor kernel driver uses the same
+ * scaling factor calculation.
+ *
+ * With a scaling factor of 1.0 the calculation technically also
+ * overflows 16 bit. This isn't relevant, as in this case the
+ * RGA3_WIN_SCALE_XXX_BYPASS bit completely skips the scaling operation.
+ */
+ if (dst > src) {
+ if (((src - 1) << 16) % (dst - 1) == 0)
+ return ((src - 1) << 16) / (dst - 1) - 1;
+ else
+ return ((src - 1) << 16) / (dst - 1);
+ } else {
+ return ((dst - 1) << 16) / (src - 1) + 1;
+ }
+}
+
+/*
+ * Check if the given format can be captured, as the RGA3 doesn't support all
+ * input formats also on it's output.
+ */
+static bool rga3_can_capture(const struct rga3_fmt *fmt)
+{
+ return fmt->hw_format <= RGA3_COLOR_FMT_LAST_OUTPUT;
+}
+
+/*
+ * Map the transformations to the RGA3 command buffer.
+ * Currently this is just the scaling settings and a fixed alpha value.
+ */
+static void rga3_cmd_set_trans_info(struct rga_ctx *ctx)
+{
+ u32 *cmd = ctx->cmdbuf_virt;
+ unsigned int src_h, src_w, dst_h, dst_w;
+ unsigned int reg;
+ u16 hor_scl_fac, ver_scl_fac;
+ const struct rga3_fmt *in = ctx->in.fmt;
+
+ /* Support basic input cropping to support 1088px inputs */
+ src_h = ctx->in.crop.height;
+ src_w = ctx->in.crop.width;
+ dst_h = ctx->out.pix.height;
+ dst_w = ctx->out.pix.width;
+
+ reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_SCALE_HOR_UP, dst_w > src_w)
+ | FIELD_PREP(RGA3_WIN_SCALE_HOR_BYPASS, dst_w == src_w)
+ | FIELD_PREP(RGA3_WIN_SCALE_VER_UP, dst_h > src_h)
+ | FIELD_PREP(RGA3_WIN_SCALE_VER_BYPASS, dst_h == src_h);
+
+ hor_scl_fac = rga3_get_scaling(src_w, dst_w);
+ ver_scl_fac = rga3_get_scaling(src_h, dst_h);
+ reg = RGA3_WIN0_SCL_FAC - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_SCALE_HOR_FAC, hor_scl_fac)
+ | FIELD_PREP(RGA3_SCALE_VER_FAC, ver_scl_fac);
+
+ if (v4l2_format_info(in->fourcc)->has_alpha) {
+ /* copy alpha from input */
+ reg = RGA3_OVLP_TOP_ALPHA - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
+ | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
+ reg = RGA3_OVLP_BOT_ALPHA - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
+ | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
+ } else {
+ /* just use a 255 alpha value */
+ reg = RGA3_OVLP_TOP_CTRL - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
+ | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
+ reg = RGA3_OVLP_BOT_CTRL - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
+ | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
+ }
+}
+
+static void rga3_cmd_set_win0_addr(struct rga_ctx *ctx,
+ const struct rga_addrs *addrs)
+{
+ u32 *cmd = ctx->cmdbuf_virt;
+ unsigned int reg;
+
+ reg = RGA3_WIN0_Y_BASE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = addrs->y_addr;
+ reg = RGA3_WIN0_U_BASE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = addrs->u_addr;
+}
+
+static void rga3_cmd_set_wr_addr(struct rga_ctx *ctx,
+ const struct rga_addrs *addrs)
+{
+ u32 *cmd = ctx->cmdbuf_virt;
+ unsigned int reg;
+
+ reg = RGA3_WR_Y_BASE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = addrs->y_addr;
+ reg = RGA3_WR_U_BASE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = addrs->u_addr;
+}
+
+/* Map the input pixel format to win0 of the comamnd buffer. */
+static void rga3_cmd_set_win0_format(struct rga_ctx *ctx)
+{
+ u32 *cmd = ctx->cmdbuf_virt;
+ const struct rga3_fmt *in = ctx->in.fmt;
+ const struct rga3_fmt *out = ctx->out.fmt;
+ const struct v4l2_format_info *in_fmt, *out_fmt;
+ unsigned int act_h, act_w, src_h, src_w;
+ bool r2y, y2r;
+ u8 rd_format;
+ const struct v4l2_pix_format_mplane *csc_pix;
+ u8 csc_mode;
+ unsigned int reg;
+
+ act_h = ctx->in.pix.height;
+ act_w = ctx->in.pix.width;
+ /* Support basic input cropping to support 1088px inputs */
+ src_h = ctx->in.crop.height;
+ src_w = ctx->in.crop.width;
+
+ in_fmt = v4l2_format_info(in->fourcc);
+ out_fmt = v4l2_format_info(out->fourcc);
+ r2y = v4l2_is_format_rgb(in_fmt) && v4l2_is_format_yuv(out_fmt);
+ y2r = v4l2_is_format_yuv(in_fmt) && v4l2_is_format_rgb(out_fmt);
+
+ /* The Hardware only supports formats with 1/2 planes */
+ if (in_fmt->comp_planes == 2)
+ rd_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
+ else
+ rd_format = RGA3_RDWR_FORMAT_INTERLEAVED;
+
+ /* set pixel format and CSC */
+ csc_pix = r2y ? &ctx->out.pix : &ctx->in.pix;
+ switch (csc_pix->ycbcr_enc) {
+ case V4L2_YCBCR_ENC_BT2020:
+ csc_mode = RGA3_WIN_CSC_MODE_BT2020_L;
+ break;
+ case V4L2_YCBCR_ENC_709:
+ csc_mode = RGA3_WIN_CSC_MODE_BT709_L;
+ break;
+ default: /* should be fixed to BT601 in adjust_and_map_format */
+ if (csc_pix->quantization == V4L2_QUANTIZATION_LIM_RANGE)
+ csc_mode = RGA3_WIN_CSC_MODE_BT601_L;
+ else
+ csc_mode = RGA3_WIN_CSC_MODE_BT601_F;
+ break;
+ }
+
+ reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_ENABLE, 1)
+ | FIELD_PREP(RGA3_WIN_PIC_FORMAT, in->hw_format)
+ | FIELD_PREP(RGA3_WIN_YC_SWAP, in->yc_swap)
+ | FIELD_PREP(RGA3_WIN_RBUV_SWAP, in->rbuv_swap)
+ | FIELD_PREP(RGA3_WIN_RD_FORMAT, rd_format)
+ | FIELD_PREP(RGA3_WIN_R2Y, r2y)
+ | FIELD_PREP(RGA3_WIN_Y2R, y2r)
+ | FIELD_PREP(RGA3_WIN_CSC_MODE, csc_mode);
+
+ /* set stride */
+ reg = RGA3_WIN0_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+ /* stride needs to be in words */
+ cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
+ reg = RGA3_WIN0_UV_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+ /* The Hardware only supports formats with 1/2 planes */
+ if (ctx->in.pix.num_planes == 2)
+ cmd[reg >> 2] = ctx->in.pix.plane_fmt[1].bytesperline >> 2;
+ else
+ cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
+
+ /* set size */
+ reg = RGA3_WIN0_ACT_SIZE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, act_w)
+ | FIELD_PREP(RGA3_HEIGHT, act_h);
+ reg = RGA3_WIN0_SRC_SIZE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, src_w)
+ | FIELD_PREP(RGA3_HEIGHT, src_h);
+}
+
+/* Map the output pixel format to the command buffer */
+static void rga3_cmd_set_wr_format(struct rga_ctx *ctx)
+{
+ u32 *cmd = ctx->cmdbuf_virt;
+ const struct rga3_fmt *out = ctx->out.fmt;
+ const struct v4l2_format_info *out_fmt;
+ unsigned int dst_h, dst_w;
+ u8 wr_format;
+ unsigned int reg;
+
+ dst_h = ctx->out.pix.height;
+ dst_w = ctx->out.pix.width;
+
+ out_fmt = v4l2_format_info(out->fourcc);
+
+ /* The Hardware only supports formats with 1/2 planes */
+ if (out_fmt->comp_planes == 2)
+ wr_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
+ else
+ wr_format = RGA3_RDWR_FORMAT_INTERLEAVED;
+
+ /* set pixel format */
+ reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_WR_PIC_FORMAT, out->hw_format)
+ | FIELD_PREP(RGA3_WR_YC_SWAP, out->yc_swap)
+ | FIELD_PREP(RGA3_WR_RBUV_SWAP, out->rbuv_swap)
+ | FIELD_PREP(RGA3_WR_FORMAT, wr_format)
+ /* Use the max value to avoid limiting the write speed */
+ | FIELD_PREP(RGA3_WR_SW_OUTSTANDING_MAX, 63);
+
+ /* set stride */
+ reg = RGA3_WR_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+ /* stride needs to be in words */
+ cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
+ reg = RGA3_WR_PL_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+ /* The Hardware only supports formats with 1/2 planes */
+ if (ctx->out.pix.num_planes == 2)
+ cmd[reg >> 2] = ctx->out.pix.plane_fmt[1].bytesperline >> 2;
+ else
+ cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
+
+ /* Set size.
+ * As two inputs are not supported, we don't use win1.
+ * Therefore only set the size for win0.
+ */
+ reg = RGA3_WIN0_DST_SIZE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, dst_w)
+ | FIELD_PREP(RGA3_HEIGHT, dst_h);
+}
+
+static void rga3_hw_setup_cmdbuf(struct rga_ctx *ctx)
+{
+ memset(ctx->cmdbuf_virt, 0, RGA3_CMDBUF_SIZE * 4);
+
+ rga3_cmd_set_win0_format(ctx);
+ rga3_cmd_set_trans_info(ctx);
+ rga3_cmd_set_wr_format(ctx);
+}
+
+static void rga3_hw_start(struct rockchip_rga *rga,
+ struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
+{
+ struct rga_ctx *ctx = rga->curr;
+
+ rga3_cmd_set_win0_addr(ctx, &src->dma_addrs);
+ rga3_cmd_set_wr_addr(ctx, &dst->dma_addrs);
+
+ rga_write(rga, RGA3_CMD_ADDR, ctx->cmdbuf_phy);
+
+ /* sync CMD buf for RGA */
+ dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+
+ /* set to master mode and start the conversion */
+ rga_write(rga, RGA3_SYS_CTRL,
+ FIELD_PREP(RGA3_CMD_MODE, RGA3_CMD_MODE_MASTER));
+ rga_write(rga, RGA3_INT_EN, FIELD_PREP(RGA3_INT_FRM_DONE, 1));
+ rga_write(rga, RGA3_CMD_CTRL,
+ FIELD_PREP(RGA3_CMD_LINE_START_PULSE, 1));
+}
+
+static bool rga3_handle_irq(struct rockchip_rga *rga)
+{
+ u32 intr;
+
+ intr = rga_read(rga, RGA3_INT_RAW);
+ /* clear all interrupts */
+ rga_write(rga, RGA3_INT_CLR, intr);
+
+ return FIELD_GET(RGA3_INT_FRM_DONE, intr);
+}
+
+static void rga3_get_version(struct rockchip_rga *rga)
+{
+ u32 version = rga_read(rga, RGA3_VERSION_NUM);
+
+ rga->version.major = FIELD_GET(RGA3_VERSION_NUM_MAJOR, version);
+ rga->version.minor = FIELD_GET(RGA3_VERSION_NUM_MINOR, version);
+}
+
+static struct rga3_fmt rga3_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .hw_format = RGA3_COLOR_FMT_BGR888,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .hw_format = RGA3_COLOR_FMT_BGR888,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_ABGR32,
+ .hw_format = RGA3_COLOR_FMT_BGRA8888,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGBA32,
+ .hw_format = RGA3_COLOR_FMT_BGRA8888,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_XBGR32,
+ .hw_format = RGA3_COLOR_FMT_BGRA8888,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGBX32,
+ .hw_format = RGA3_COLOR_FMT_BGRA8888,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .hw_format = RGA3_COLOR_FMT_BGR565,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .hw_format = RGA3_COLOR_FMT_YUV420,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .hw_format = RGA3_COLOR_FMT_YUV420,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .hw_format = RGA3_COLOR_FMT_YUV420,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .hw_format = RGA3_COLOR_FMT_YUV420,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV16M,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV61M,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ .yc_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ .yc_swap = 1,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ .rbuv_swap = 1,
+ },
+ /* Input only formats last to keep rga3_enum_format simple */
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB32,
+ .hw_format = RGA3_COLOR_FMT_ABGR8888,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGRA32,
+ .hw_format = RGA3_COLOR_FMT_ABGR8888,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_XRGB32,
+ .hw_format = RGA3_COLOR_FMT_ABGR8888,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGRX32,
+ .hw_format = RGA3_COLOR_FMT_ABGR8888,
+ },
+};
+
+static int rga3_enum_format(struct v4l2_fmtdesc *f)
+{
+ struct rga3_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(rga3_formats))
+ return -EINVAL;
+
+ fmt = &rga3_formats[f->index];
+ if (V4L2_TYPE_IS_CAPTURE(f->type) && !rga3_can_capture(fmt))
+ return -EINVAL;
+
+ f->pixelformat = fmt->fourcc;
+ return 0;
+}
+
+static void *rga3_adjust_and_map_format(struct rga_ctx *ctx,
+ struct v4l2_pix_format_mplane *format,
+ bool is_output)
+{
+ unsigned int i;
+ const struct v4l2_format_info *format_info;
+ const struct v4l2_pix_format_mplane *other_format;
+ const struct v4l2_format_info *other_format_info;
+
+ if (!format)
+ return &rga3_formats[0];
+
+ format_info = v4l2_format_info(format->pixelformat);
+ other_format = is_output ? &ctx->in.pix : &ctx->out.pix;
+ other_format_info = v4l2_format_info(other_format->pixelformat);
+
+ if ((v4l2_is_format_rgb(format_info) &&
+ v4l2_is_format_yuv(other_format_info)) ||
+ (v4l2_is_format_yuv(format_info) &&
+ v4l2_is_format_rgb(other_format_info))) {
+ /*
+ * The RGA3 only supports BT601, BT709 and BT2020 RGB<->YUV conversions
+ * Additionally BT709 and BT2020 only support limited range YUV.
+ */
+ switch (format->ycbcr_enc) {
+ case V4L2_YCBCR_ENC_601:
+ /* supports full and limited range */
+ break;
+ case V4L2_YCBCR_ENC_709:
+ case V4L2_YCBCR_ENC_BT2020:
+ format->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+ break;
+ default:
+ format->ycbcr_enc = V4L2_YCBCR_ENC_601;
+ format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ break;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(rga3_formats); i++) {
+ if (!is_output && !rga3_can_capture(&rga3_formats[i]))
+ continue;
+
+ if (rga3_formats[i].fourcc == format->pixelformat)
+ return &rga3_formats[i];
+ }
+
+ format->pixelformat = rga3_formats[0].fourcc;
+ return &rga3_formats[0];
+}
+
+const struct rga_hw rga3_hw = {
+ .card_type = "rga3",
+ .has_internal_iommu = false,
+ .cmdbuf_size = RGA3_CMDBUF_SIZE,
+ .min_width = RGA3_MIN_WIDTH,
+ .min_height = RGA3_MIN_HEIGHT,
+ /* use output size, as it's a bit smaller than the input size */
+ .max_width = RGA3_MAX_OUTPUT_WIDTH,
+ .max_height = RGA3_MAX_OUTPUT_HEIGHT,
+ .max_scaling_factor = RGA3_MAX_SCALING_FACTOR,
+ .stride_alignment = 16,
+ .features = 0,
+
+ .setup_cmdbuf = rga3_hw_setup_cmdbuf,
+ .start = rga3_hw_start,
+ .handle_irq = rga3_handle_irq,
+ .get_version = rga3_get_version,
+ .enum_format = rga3_enum_format,
+ .adjust_and_map_format = rga3_adjust_and_map_format,
+};
diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.h b/drivers/media/platform/rockchip/rga/rga3-hw.h
new file mode 100644
index 0000000000000..cc87051492194
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga3-hw.h
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) Pengutronix e.K.
+ * Author: Sven Püschel <s.pueschel@pengutronix.de>
+ */
+#ifndef __RGA3_HW_H__
+#define __RGA3_HW_H__
+
+#include <linux/bits.h>
+#include <linux/types.h>
+
+#define RGA3_CMDBUF_SIZE 0x2e
+
+#define RGA3_MIN_WIDTH 128
+#define RGA3_MIN_HEIGHT 128
+#define RGA3_MAX_INPUT_WIDTH (8192 - 16)
+#define RGA3_MAX_INPUT_HEIGHT (8192 - 16)
+#define RGA3_MAX_OUTPUT_WIDTH (8192 - 64)
+#define RGA3_MAX_OUTPUT_HEIGHT (8192 - 64)
+#define RGA3_MAX_SCALING_FACTOR 8
+#define RGA3_RESET_TIMEOUT 1000
+
+/* Registers address */
+/* sys reg */
+#define RGA3_SYS_CTRL 0x000
+#define RGA3_CMD_CTRL 0x004
+#define RGA3_CMD_ADDR 0x008
+#define RGA3_MI_GROUP_CTRL 0x00c
+#define RGA3_ARQOS_CTRL 0x010
+#define RGA3_VERSION_NUM 0x018
+#define RGA3_VERSION_TIM 0x01c
+#define RGA3_INT_EN 0x020
+#define RGA3_INT_RAW 0x024
+#define RGA3_INT_MSK 0x028
+#define RGA3_INT_CLR 0x02c
+#define RGA3_RO_SRST 0x030
+#define RGA3_STATUS0 0x034
+#define RGA3_SCAN_CNT 0x038
+#define RGA3_CMD_STATE 0x040
+
+/* cmd reg */
+#define RGA3_WIN0_RD_CTRL 0x100
+#define RGA3_FIRST_CMD_REG RGA3_WIN0_RD_CTRL
+#define RGA3_WIN0_Y_BASE 0x110
+#define RGA3_WIN0_U_BASE 0x114
+#define RGA3_WIN0_V_BASE 0x118
+#define RGA3_WIN0_VIR_STRIDE 0x11c
+#define RGA3_WIN0_FBC_OFF 0x120
+#define RGA3_WIN0_SRC_SIZE 0x124
+#define RGA3_WIN0_ACT_OFF 0x128
+#define RGA3_WIN0_ACT_SIZE 0x12c
+#define RGA3_WIN0_DST_SIZE 0x130
+#define RGA3_WIN0_SCL_FAC 0x134
+#define RGA3_WIN0_UV_VIR_STRIDE 0x138
+#define RGA3_WIN1_RD_CTRL 0x140
+#define RGA3_WIN1_Y_BASE 0x150
+#define RGA3_WIN1_U_BASE 0x154
+#define RGA3_WIN1_V_BASE 0x158
+#define RGA3_WIN1_VIR_STRIDE 0x15c
+#define RGA3_WIN1_FBC_OFF 0x160
+#define RGA3_WIN1_SRC_SIZE 0x164
+#define RGA3_WIN1_ACT_OFF 0x168
+#define RGA3_WIN1_ACT_SIZE 0x16c
+#define RGA3_WIN1_DST_SIZE 0x170
+#define RGA3_WIN1_SCL_FAC 0x174
+#define RGA3_WIN1_UV_VIR_STRIDE 0x178
+#define RGA3_OVLP_CTRL 0x180
+#define RGA3_OVLP_OFF 0x184
+#define RGA3_OVLP_TOP_KEY_MIN 0x188
+#define RGA3_OVLP_TOP_KEY_MAX 0x18c
+#define RGA3_OVLP_TOP_CTRL 0x190
+#define RGA3_OVLP_BOT_CTRL 0x194
+#define RGA3_OVLP_TOP_ALPHA 0x198
+#define RGA3_OVLP_BOT_ALPHA 0x19c
+#define RGA3_WR_CTRL 0x1a0
+#define RGA3_WR_FBCE_CTRL 0x1a4
+#define RGA3_WR_VIR_STRIDE 0x1a8
+#define RGA3_WR_PL_VIR_STRIDE 0x1ac
+#define RGA3_WR_Y_BASE 0x1b0
+#define RGA3_WR_U_BASE 0x1b4
+#define RGA3_WR_V_BASE 0x1b8
+
+/* Registers value */
+#define RGA3_COLOR_FMT_YUV420 0x0
+#define RGA3_COLOR_FMT_YUV422 0x1
+#define RGA3_COLOR_FMT_YUV420_10B 0x2
+#define RGA3_COLOR_FMT_YUV422_10B 0x3
+/*
+ * Use memory ordering names
+ * instead of the datasheet naming RGB formats in big endian order
+ */
+#define RGA3_COLOR_FMT_BGR565 0x4
+#define RGA3_COLOR_FMT_BGR888 0x5
+#define RGA3_COLOR_FMT_FIRST_HAS_ALPHA RGA3_COLOR_FMT_BGRA8888
+#define RGA3_COLOR_FMT_BGRA8888 0x6
+#define RGA3_COLOR_FMT_LAST_OUTPUT RGA3_COLOR_FMT_BGRA8888
+/* the following are only supported as inputs */
+#define RGA3_COLOR_FMT_ABGR8888 0x7
+/*
+ * the following seem to be unnecessary,
+ * as they can be achieved with RB swaps
+ */
+#define RGA3_COLOR_FMT_RGBA8888 0x8
+#define RGA3_COLOR_FMT_ARGB8888 0x9
+
+#define RGA3_RDWR_FORMAT_SEMI_PLANAR 0x1
+#define RGA3_RDWR_FORMAT_INTERLEAVED 0x2
+
+#define RGA3_CMD_MODE_MASTER 0x1
+
+#define RGA3_WIN_CSC_MODE_BT601_L 0x0
+#define RGA3_WIN_CSC_MODE_BT709_L 0x1
+#define RGA3_WIN_CSC_MODE_BT601_F 0x2
+#define RGA3_WIN_CSC_MODE_BT2020_L 0x3
+
+/* RGA masks */
+/* SYS_CTRL */
+#define RGA3_CCLK_SRESET BIT(4)
+#define RGA3_ACLK_SRESET BIT(3)
+#define RGA3_CMD_MODE BIT(1)
+
+/* CMD_CTRL */
+#define RGA3_CMD_LINE_START_PULSE BIT(0)
+
+/* VERSION_NUM */
+#define RGA3_VERSION_NUM_MAJOR GENMASK(31, 28)
+#define RGA3_VERSION_NUM_MINOR GENMASK(27, 20)
+
+/* INT_* */
+#define RGA3_INT_FRM_DONE BIT(0)
+#define RGA3_INT_DMA_READ_BUS_ERR BIT(2)
+#define RGA3_INT_WIN0_FBC_DEC_ERR BIT(5)
+#define RGA3_INT_WIN0_HOR_ERR BIT(6)
+#define RGA3_INT_WIN0_VER_ERR BIT(7)
+#define RGA3_INT_WR_VER_ERR BIT(13)
+#define RGA3_INT_WR_HOR_ERR BIT(14)
+#define RGA3_INT_WR_BUS_ERR BIT(15)
+#define RGA3_INT_WIN0_IN_FIFO_WR_ERR BIT(16)
+#define RGA3_INT_WIN0_IN_FIFO_RD_ERR BIT(17)
+#define RGA3_INT_WIN0_HOR_FIFO_WR_ERR BIT(18)
+#define RGA3_INT_WIN0_HOR_FIFO_RD_ERR BIT(19)
+#define RGA3_INT_WIN0_VER_FIFO_WR_ERR BIT(20)
+#define RGA3_INT_WIN0_VER_FIFO_RD_ERR BIT(21)
+
+/* RO_SRST */
+#define RGA3_RO_SRST_DONE GENMASK(5, 0)
+
+/* *_SIZE */
+#define RGA3_HEIGHT GENMASK(28, 16)
+#define RGA3_WIDTH GENMASK(12, 0)
+
+/* SCL_FAC */
+#define RGA3_SCALE_VER_FAC GENMASK(31, 16)
+#define RGA3_SCALE_HOR_FAC GENMASK(15, 0)
+
+/* WINx_CTRL */
+#define RGA3_WIN_CSC_MODE GENMASK(27, 26)
+#define RGA3_WIN_R2Y BIT(25)
+#define RGA3_WIN_Y2R BIT(24)
+#define RGA3_WIN_SCALE_VER_UP BIT(23)
+#define RGA3_WIN_SCALE_VER_BYPASS BIT(22)
+#define RGA3_WIN_SCALE_HOR_UP BIT(21)
+#define RGA3_WIN_SCALE_HOR_BYPASS BIT(20)
+#define RGA3_WIN_YC_SWAP BIT(13)
+#define RGA3_WIN_RBUV_SWAP BIT(12)
+#define RGA3_WIN_RD_FORMAT GENMASK(9, 8)
+#define RGA3_WIN_PIC_FORMAT GENMASK(7, 4)
+#define RGA3_WIN_ENABLE BIT(0)
+
+/* COLOR_CTRL */
+#define RGA3_OVLP_GLOBAL_ALPHA GENMASK(23, 16)
+#define RGA3_OVLP_COLOR_MODE BIT(0)
+
+/* ALPHA_CTRL */
+#define RGA3_ALPHA_SELECT_MODE BIT(4)
+#define RGA3_ALPHA_BLEND_MODE GENMASK(3, 2)
+
+/* WR_CTRL */
+#define RGA3_WR_YC_SWAP BIT(20)
+#define RGA3_WR_SW_OUTSTANDING_MAX GENMASK(18, 13)
+#define RGA3_WR_RBUV_SWAP BIT(12)
+#define RGA3_WR_FORMAT GENMASK(9, 8)
+#define RGA3_WR_PIC_FORMAT GENMASK(7, 4)
+
+struct rga3_fmt {
+ u32 fourcc;
+ u8 hw_format;
+ bool rbuv_swap;
+ bool yc_swap;
+};
+
+#endif
--
2.53.0
^ permalink raw reply related
* [PATCH v4 23/27] media: rockchip: rga: move rga_fmt to rga-hw.h
From: Sven Püschel @ 2026-03-25 14:50 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, Sven Püschel,
Nicolas Dufresne
In-Reply-To: <20260325-spu-rga3-v4-0-e90ec1c61354@pengutronix.de>
Move rga_fmt to rga-hw in preparation of the RGA3 addition, as the struct
contains many RGA2 specific values. They are used to write the correct
register values quickly based on the chosen format. Therefore the
pointer to the rga_fmt struct is kept but changed to an opaque void
pointer outside of the rga-hw.h.
To enumerate and set the correct formats, two helper functions need to
be exposed in the rga_hw struct:
enum_format just get's the vidioc_enum_fmt format and it's return value
is also returned from vidioc_enum_fmt. This is a simple pass-through,
as the implementation is very simple.
adjust_and_map_format is a simple abstraction around the previous
rga_find_format. But unlike rga_find_format, it always returns a valid
format. Therefore the passed format value is also a pointer to update
it in case the values are not supported by the hardware.
Due to the RGA3 supporting different formats on the capture and output
side, an additional parameter is_capture has been added to support
this use-case. The additional ctx parameter is also added to allow the
RGA3 to limit the colorimetry only if an RGB<->YCrCb transformation
happens.
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
drivers/media/platform/rockchip/rga/rga-buf.c | 2 +-
drivers/media/platform/rockchip/rga/rga-hw.c | 49 +++++++++++++++++++++------
drivers/media/platform/rockchip/rga/rga-hw.h | 8 +++++
drivers/media/platform/rockchip/rga/rga.c | 39 +++++++--------------
drivers/media/platform/rockchip/rga/rga.h | 14 +++-----
5 files changed, 66 insertions(+), 46 deletions(-)
diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index c0cc885ba58a8..8632b18cd3fc6 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -162,7 +162,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
}
/* Fill the remaining planes */
- info = v4l2_format_info(f->fmt->fourcc);
+ info = v4l2_format_info(f->pix.pixelformat);
for (i = info->mem_planes; i < info->comp_planes; i++)
dma_addrs[i] = dma_addrs[0] + get_plane_offset(f, info, i);
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 5d993cf69963d..e76d1994b8684 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -171,6 +171,8 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
union rga_dst_vir_info dst_vir_info;
union rga_dst_act_info dst_act_info;
u32 in_stride, out_stride;
+ struct rga_fmt *in_fmt = ctx->in.fmt;
+ struct rga_fmt *out_fmt = ctx->out.fmt;
src_h = ctx->in.crop.height;
src_w = ctx->in.crop.width;
@@ -186,18 +188,18 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
- src_info.data.format = ctx->in.fmt->hw_format;
- src_info.data.swap = ctx->in.fmt->color_swap;
- dst_info.data.format = ctx->out.fmt->hw_format;
- dst_info.data.swap = ctx->out.fmt->color_swap;
+ src_info.data.format = in_fmt->hw_format;
+ src_info.data.swap = in_fmt->color_swap;
+ dst_info.data.format = out_fmt->hw_format;
+ dst_info.data.swap = out_fmt->color_swap;
/*
* CSC mode must only be set when the colorspace families differ between
* input and output. It must remain unset (zeroed) if both are the same.
*/
- if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) &&
- RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) {
+ if (RGA_COLOR_FMT_IS_YUV(in_fmt->hw_format) &&
+ RGA_COLOR_FMT_IS_RGB(out_fmt->hw_format)) {
switch (ctx->in.pix.colorspace) {
case V4L2_COLORSPACE_REC709:
src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
@@ -208,8 +210,8 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
}
}
- if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) &&
- RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) {
+ if (RGA_COLOR_FMT_IS_RGB(in_fmt->hw_format) &&
+ RGA_COLOR_FMT_IS_YUV(out_fmt->hw_format)) {
switch (ctx->out.pix.colorspace) {
case V4L2_COLORSPACE_REC709:
dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
@@ -563,11 +565,36 @@ static struct rga_fmt formats[] = {
},
};
+static void *rga_adjust_and_map_format(struct rga_ctx *ctx,
+ struct v4l2_pix_format_mplane *format,
+ bool is_output)
+{
+ unsigned int i;
+
+ if (!format)
+ return &formats[0];
+
+ for (i = 0; i < ARRAY_SIZE(formats); i++) {
+ if (formats[i].fourcc == format->pixelformat)
+ return &formats[i];
+ }
+
+ format->pixelformat = formats[0].fourcc;
+ return &formats[0];
+}
+
+static int rga_enum_format(struct v4l2_fmtdesc *f)
+{
+ if (f->index >= ARRAY_SIZE(formats))
+ return -EINVAL;
+
+ f->pixelformat = formats[f->index].fourcc;
+ return 0;
+}
+
const struct rga_hw rga2_hw = {
.card_type = "rga2",
.has_internal_iommu = true,
- .formats = formats,
- .num_formats = ARRAY_SIZE(formats),
.cmdbuf_size = RGA_CMDBUF_SIZE,
.min_width = MIN_WIDTH,
.max_width = MAX_WIDTH,
@@ -580,4 +607,6 @@ const struct rga_hw rga2_hw = {
.start = rga_hw_start,
.handle_irq = rga_handle_irq,
.get_version = rga_get_version,
+ .adjust_and_map_format = rga_adjust_and_map_format,
+ .enum_format = rga_enum_format,
};
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
index fffcab0131225..039a3e868733e 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.h
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -6,6 +6,8 @@
#ifndef __RGA_HW_H__
#define __RGA_HW_H__
+#include <linux/types.h>
+
#define RGA_CMDBUF_SIZE 0x20
/* Hardware limits */
@@ -431,4 +433,10 @@ union rga_pat_con {
} data;
};
+struct rga_fmt {
+ u32 fourcc;
+ u8 color_swap;
+ u8 hw_format;
+};
+
#endif
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 6433fdaa5b339..364c1dac3f81c 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -185,17 +185,6 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
return 0;
}
-static struct rga_fmt *rga_fmt_find(struct rockchip_rga *rga, u32 pixelformat)
-{
- unsigned int i;
-
- for (i = 0; i < rga->hw->num_formats; i++) {
- if (rga->hw->formats[i].fourcc == pixelformat)
- return &rga->hw->formats[i];
- }
- return NULL;
-}
-
struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
{
if (V4L2_TYPE_IS_OUTPUT(type))
@@ -217,7 +206,6 @@ static int rga_open(struct file *file)
.crop.top = 0,
.crop.width = def_width,
.crop.height = def_height,
- .fmt = &rga->hw->formats[0],
};
ctx = kzalloc_obj(*ctx);
@@ -238,9 +226,12 @@ static int rga_open(struct file *file)
ctx->in = def_frame;
ctx->out = def_frame;
- v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.fmt->fourcc,
+ ctx->in.fmt = rga->hw->adjust_and_map_format(ctx, &ctx->in.pix, true);
+ v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.pix.pixelformat,
def_width, def_height, rga->hw->stride_alignment);
- v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.fmt->fourcc,
+ ctx->out.fmt =
+ rga->hw->adjust_and_map_format(ctx, &ctx->out.pix, false);
+ v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.pix.pixelformat,
def_width, def_height, rga->hw->stride_alignment);
if (mutex_lock_interruptible(&rga->mutex)) {
@@ -322,13 +313,11 @@ vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f)
{
struct rockchip_rga *rga = video_drvdata(file);
- struct rga_fmt *fmt;
-
- if (f->index >= rga->hw->num_formats)
- return -EINVAL;
+ int ret;
- fmt = &rga->hw->formats[f->index];
- f->pixelformat = fmt->fourcc;
+ ret = rga->hw->enum_format(f);
+ if (ret != 0)
+ return ret;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
@@ -363,7 +352,6 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
struct rga_ctx *ctx = file_to_rga_ctx(file);
const struct rga_hw *hw = ctx->rga->hw;
- struct rga_fmt *fmt;
struct v4l2_frmsize_stepwise frmsize = {
.min_width = hw->min_width,
.max_width = hw->max_width,
@@ -394,9 +382,7 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
pix_fmt->xfer_func = frm->pix.xfer_func;
}
- fmt = rga_fmt_find(ctx->rga, pix_fmt->pixelformat);
- if (!fmt)
- fmt = &hw->formats[0];
+ hw->adjust_and_map_format(ctx, pix_fmt, V4L2_TYPE_IS_OUTPUT(f->type));
v4l2_apply_frmsize_constraints(&pix_fmt->width, &pix_fmt->height, &frmsize);
v4l2_fill_pixfmt_mp_aligned(pix_fmt, pix_fmt->pixelformat,
@@ -456,7 +442,8 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
frm = rga_get_frame(ctx, f->type);
if (IS_ERR(frm))
return PTR_ERR(frm);
- frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
+ frm->fmt = rga->hw->adjust_and_map_format(ctx, pix_fmt,
+ V4L2_TYPE_IS_OUTPUT(f->type));
/*
* Copy colorimetry from output to capture as required by the
@@ -480,7 +467,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
v4l2_dbg(debug, 1, &rga->v4l2_dev,
"[%s] fmt - %p4cc %dx%d (stride %d)\n",
V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
- &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
+ &pix_fmt->pixelformat, pix_fmt->width, pix_fmt->height,
pix_fmt->plane_fmt[0].bytesperline);
for (i = 0; i < pix_fmt->num_planes; i++) {
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index d203b7dae2b03..d98e57c6d7b57 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -17,18 +17,12 @@
#define DEFAULT_WIDTH 100
#define DEFAULT_HEIGHT 100
-struct rga_fmt {
- u32 fourcc;
- u8 color_swap;
- u8 hw_format;
-};
-
struct rga_frame {
/* Crop */
struct v4l2_rect crop;
/* Image format */
- struct rga_fmt *fmt;
+ void *fmt;
struct v4l2_pix_format_mplane pix;
};
@@ -142,8 +136,6 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
struct rga_hw {
const char *card_type;
bool has_internal_iommu;
- struct rga_fmt *formats;
- u32 num_formats;
size_t cmdbuf_size;
u32 min_width, min_height;
u32 max_width, max_height;
@@ -155,6 +147,10 @@ struct rga_hw {
struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
bool (*handle_irq)(struct rockchip_rga *rga);
void (*get_version)(struct rockchip_rga *rga);
+ void *(*adjust_and_map_format)(struct rga_ctx *ctx,
+ struct v4l2_pix_format_mplane *format,
+ bool is_output);
+ int (*enum_format)(struct v4l2_fmtdesc *f);
};
static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
--
2.53.0
^ permalink raw reply related
* Re: [PATCH 3/3] arm64: dts: freescale: imx95-toradex-smarc: Use gpio-hog for WIFI_UART_EN
From: Frank Li @ 2026-03-25 14:54 UTC (permalink / raw)
To: Franz Schnyder
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Franz Schnyder,
devicetree, imx, linux-arm-kernel, linux-kernel,
Francesco Dolcini
In-Reply-To: <20260325115513.707914-1-fra.schnyder@gmail.com>
On Wed, Mar 25, 2026 at 12:55:11PM +0100, Franz Schnyder wrote:
> From: Franz Schnyder <franz.schnyder@toradex.com>
>
> On the Toradex SMARC iMX95, the WiFi UART signals are shared with the
> JTAG. The WIFI_UART_EN signal is used to select between these
> two functions.
>
> Configure the signal as gpio-hog and drive it high to select the UART
> function by default. Add a label to override the hog in derived
> device trees.
gpio hog have problem about probe order, are you sure gpio device probe
before pcie?
I have not seen any place refer to wifi_uart_en.
Frank
>
> Signed-off-by: Franz Schnyder <franz.schnyder@toradex.com>
> ---
> arch/arm64/boot/dts/freescale/imx95-toradex-smarc.dtsi | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/freescale/imx95-toradex-smarc.dtsi b/arch/arm64/boot/dts/freescale/imx95-toradex-smarc.dtsi
> index a90edefc5197..29e3f5bf867b 100644
> --- a/arch/arm64/boot/dts/freescale/imx95-toradex-smarc.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx95-toradex-smarc.dtsi
> @@ -451,6 +451,13 @@ som_gpio_expander_1: gpio@21 {
> "",
> "",
> "SMARC_SDIO_WP";
> +
> + wifi_uart_en: wifi-uart-en-hog {
> + gpio-hog;
> + gpios = <12 GPIO_ACTIVE_HIGH>;
> + line-name = "WIFI_UART_EN";
> + output-high;
> + };
> };
>
> embedded-controller@28 {
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH v2 01/11] arm64: Skip update of an idreg field affected by an override
From: Suzuki K Poulose @ 2026-03-25 14:54 UTC (permalink / raw)
To: Catalin Marinas, Marc Zyngier
Cc: linux-arm-kernel, kvmarm, Fuad Tabba, Will Deacon, Mark Rutland,
Joey Gouly, Oliver Upton, Zenghui Yu
In-Reply-To: <abwXl35xQ2ze1XwJ@arm.com>
On 19/03/2026 15:34, Catalin Marinas wrote:
> On Mon, Mar 02, 2026 at 11:56:42AM +0000, Marc Zyngier wrote:
>> When computing the new value od an idreg that contains a field
>> affected by an override, do not update that particular field.
>>
>> The value computed at init-time must be kept as-is, as that's
>> what the user has asked for, for better or worse.
>>
>> Signed-off-by: Marc Zyngier <maz@kernel.org>
>> ---
>> arch/arm64/kernel/cpufeature.c | 7 +++++++
>> 1 file changed, 7 insertions(+)
>>
>> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
>> index c31f8e17732a3..28fc77443ccd3 100644
>> --- a/arch/arm64/kernel/cpufeature.c
>> +++ b/arch/arm64/kernel/cpufeature.c
>> @@ -1224,6 +1224,13 @@ static void update_cpu_ftr_reg(struct arm64_ftr_reg *reg, u64 new)
>> s64 ftr_cur = arm64_ftr_value(ftrp, reg->sys_val);
>> s64 ftr_new = arm64_ftr_value(ftrp, new);
>>
>> + /*
>> + * Don't alter the initial value that has been forced
>> + * by an override.
>> + */
>> + if ((reg->override->mask & arm64_ftr_mask(ftrp)) == arm64_ftr_mask(ftrp))
>> + continue;
>
> I got lost in the in the cpufeature framework, so I may be missing
> something.
>
> Let's say the primary CPU has a feature field with value 2 and we want
> to override it to value 1. For e.g. a LOWER_SAFE feature, boot_cpu_data
> will stored the overridden value of 1.
>
> A secondary CPU comes online with the same feature missing, so value 0.
> With the above change, we no longer update the system-wide feature
> value, leave it as 1. Later on, for a system feature we may turn it on
> even though the secondary CPU does not support it.
>
> In summary, this makes the overridden field sticky for secondary CPUs
> even if they don't support it.
That is true. I think we should let the secondary CPUs alter the values,
with initial CPU feature value with the override value set, the system
could then choose the safest among the override and the others.
>
> Unrelated to your patch, I think we can similarly fail to reject
> secondary CPUs in check_early_cpu_features() -> verify_local_cpu_caps()
> because of __read_sysreg_by_encoding() which uses the override value
> unconditionally. From this perspective, we are now consistent with your
> patch above.
This is true as well and the override takes the priority and with the
wrong level of override value the system could be made to think that
some features are available even when it is unsafe to do so.
We should sanitise the values read by __read_sysreg_by_encoding() with
the "overrides". I can cook something up.
>
> In all cases we taint the kernel for FTR_STRICT features but that may go
> unnoticed or if we had FTR_NONSTRICT (does it even matter in this
> case?).
>
> Maybe that's the intended use and blame the user for passing the wrong
> override. We are still slightly inconsistent depending on what the boot
This is correct. We should at least WARN for impossible overrides on the
secondaries. (We only do that for boot CPUs today). The other issue with
this is WEAK_LOCAL cpu features where we use the capability wherever
available. May be we could reduce the severity of the warning to
pr_warn_once().
Suzuki
> CPU supports where we still decide whether accept or reject an override.
> We don't do this for secondaries.
>
> Anyway, I'm not opposing to this patch if that's what's intended. I'm
> sure I'll forget everything about this framework in a couple of weeks.
>
^ permalink raw reply
* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
From: Maxime Ripard @ 2026-03-25 14:56 UTC (permalink / raw)
To: Ville Syrjälä
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
In-Reply-To: <acPA60Ci3n_t__xF@intel.com>
[-- Attachment #1: Type: text/plain, Size: 5249 bytes --]
On Wed, Mar 25, 2026 at 01:03:07PM +0200, Ville Syrjälä wrote:
> On Wed, Mar 25, 2026 at 09:24:27AM +0100, Maxime Ripard wrote:
> > On Tue, Mar 24, 2026 at 09:53:35PM +0200, Ville Syrjälä wrote:
> > > On Tue, Mar 24, 2026 at 08:10:11PM +0100, Nicolas Frattaroli wrote:
> > > > On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> > > > > On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > > > > > +enum drm_connector_color_format {
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > > > + * helpers should pick a suitable color format. All implementations of a
> > > > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > > > + * semantics.
> > > > > > + *
> > > > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > > > + * YCbCr 4:2:0.
> > > > > > + *
> > > > > > + * For display protocols other than HDMI, the recursive bridge chain
> > > > > > + * format selection picks the first chain of bridge formats that works,
> > > > > > + * as has already been the case before the introduction of the "color
> > > > > > + * format" property. Non-HDMI bridges should therefore either sort their
> > > > > > + * bus output formats by preference, or agree on a unified auto format
> > > > > > + * selection logic that's implemented in a common state helper (like
> > > > > > + * how HDMI does it).
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > > > > > + * not subsampled)
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > > > > > + * with horizontal subsampling)
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > > > > > + * with horizontal and vertical subsampling)
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> > > > >
> > > > > Seems like this should document what the quantization range
> > > > > should be for each format.
> > > > >
> > > >
> > > > I don't think so? If you want per-component bit depth values,
> > > > DRM_FORMAT_* defines would be the appropriate values to use. This
> > > > enum is more abstract than that, and is there to communicate
> > > > YUV vs. RGB and chroma subsampling, with bit depth being handled
> > > > by other properties.
> > > >
> > > > If you mean the factor used for subsampling, then that'd only be
> > > > relevant if YCBCR410 was supported where one chroma plane isn't
> > > > halved but quartered in resolution. I suspect 4:1:0 will never
> > > > be added; no digital display protocol standard supports it to my
> > > > knowledge, and hopefully none ever will.
> > >
> > > No, I mean the quantization range (16-235 vs. 0-255 etc).
> > >
> > > The i915 behaviour is that YCbCr is always limited range,
> > > RGB can either be full or limited range depending on the
> > > "Broadcast RGB" property and other related factors.
> >
> > So far the HDMI state has both the format and quantization range as
> > different fields. I'm not sure we need to document the range in the
> > format field, maybe only mention it's not part of the format but has a
> > field of its own?
>
> I think we only have it for RGB (on some drivers only?). For YCbCr
> I think the assumption is limited range everywhere.
>
> But I'm not really concerned about documenting struct members.
> What I'm talking about is the *uapi* docs. Surely userspace
> will want to know what the new property actually does so the
> uapi needs to be documented properly. And down the line some
> new driver might also implement the wrong behaviour if there
> is no clear specification.
Ack
> So I'm thinking (or perhaps hoping) the rule might be something like:
> - YCbCr limited range
> - RGB full range if "Broadcast RGB" property is not present
Isn't it much more complicated than that for HDMI though? My
recollection was that any VIC but VIC1 would be limited range, and
anything else full range?
> - RGB full or limited range based on the "Broadcast RGB" property
> if it's present
>
> I think the "Broadcast RGB" property itself might also be lacking
> proper uapi docs, so that may need to be remedied as well.
I took care of documenting it when merging the HDMI helpers:
https://docs.kernel.org/gpu/drm-kms.html#hdmi-specific-connector-properties
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply
* Re: [PATCH v6 1/5] mm: rmap: support batched checks of the references for large folios
From: David Hildenbrand (Arm) @ 2026-03-25 14:58 UTC (permalink / raw)
To: Lorenzo Stoakes (Oracle)
Cc: Baolin Wang, Barry Song, akpm, catalin.marinas, will,
lorenzo.stoakes, ryan.roberts, Liam.Howlett, vbabka, rppt, surenb,
mhocko, riel, harry.yoo, jannh, willy, dev.jain, linux-mm,
linux-arm-kernel, linux-kernel
In-Reply-To: <e5cb474a-a84d-4edc-8289-d68378feee7d@lucifer.local>
On 3/25/26 15:36, Lorenzo Stoakes (Oracle) wrote:
> On Mon, Mar 16, 2026 at 03:15:18PM +0100, David Hildenbrand (Arm) wrote:
>> On 3/16/26 07:25, Baolin Wang wrote:
>>>
>>>
>>>
>>> Sure. However, after investigating RISC‑V and x86, I found that
>>> ptep_clear_flush_young() does not flush the TLB on these architectures:
>>>
>>> int ptep_clear_flush_young(struct vm_area_struct *vma,
>>> unsigned long address, pte_t *ptep)
>>> {
>>> /*
>>> * On x86 CPUs, clearing the accessed bit without a TLB flush
>>> * doesn't cause data corruption. [ It could cause incorrect
>>> * page aging and the (mistaken) reclaim of hot pages, but the
>>> * chance of that should be relatively low. ]
>>> *
>>> * So as a performance optimization don't flush the TLB when
>>> * clearing the accessed bit, it will eventually be flushed by
>>> * a context switch or a VM operation anyway. [ In the rare
>>> * event of it not getting flushed for a long time the delay
>>> * shouldn't really matter because there's no real memory
>>> * pressure for swapout to react to. ]
>>> */
>>> return ptep_test_and_clear_young(vma, address, ptep);
>>> }
>>
>> You'd probably want an arch helper then, that tells you whether
>> a flush_tlb_range() after ptep_test_and_clear_young() is required.
>>
>> Or some special flush_tlb_range() helper.
>>
>> I agree that it requires more work.
>
> Sorry unclear here - does the series need more work or does a follow up patch
> need more work?
Follow up!
--
Cheers,
David
^ permalink raw reply
* Re: [PATCH v3] PCI: dw-rockchip: Enable async probe by default
From: Robin Murphy @ 2026-03-25 15:01 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Danilo Krummrich, Manivannan Sadhasivam, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Heiko Stuebner, Niklas Cassel, Shawn Lin,
Hans Zhang, Nicolas Frattaroli, Wilfred Mallawa, linux-pci,
linux-arm-kernel, linux-rockchip, linux-kernel, Anand Moon,
Grimmauld, Greg Kroah-Hartman, Rafael J. Wysocki, driver-core,
Lukas Wunner
In-Reply-To: <acNgUoWWMCi1oLU4@google.com>
On 25/03/2026 4:13 am, Dmitry Torokhov wrote:
> On Thu, Mar 12, 2026 at 12:48:36PM +0000, Robin Murphy wrote:
>> On 2026-03-11 9:09 pm, Danilo Krummrich wrote:
>>> On Wed Mar 11, 2026 at 1:28 PM CET, Manivannan Sadhasivam wrote:
>>>> On Wed, Mar 11, 2026 at 12:46:03PM +0100, Danilo Krummrich wrote:
>>>>> On Wed Mar 11, 2026 at 6:24 AM CET, Manivannan Sadhasivam wrote:
>>>>>> I have a contrary view here. If just a single driver or lib doesn't handle async
>>>>>> probe, it cannot just force other drivers to not take the advantage of async
>>>>>> probe. As I said above, enabling async probe easily saves a few hunderd ms or
>>>>>> even more if there are more than one Root Port or Root Complex in an SoC.
>>>>>
>>>>> Then the driver or lib has to be fixed / improved first or the driver core has
>>>>> to be enabled to deal with a case where PROBE_FORCE_SYNCHRONOUS is requested
>>>>> from an async path, etc.
>>>>>
>>>>> In any case, applying the patch and breaking things (knowingly?) doesn't seem
>>>>> like the correct approach.
>>>>>
>>>>>> I strongly agree with you here that the underlying issue should be fixed. But
>>>>>> the real impact to end users is not this splat, but not having the boot time
>>>>>> optimization that this patch brings in. As an end user, one would want their
>>>>>> systems to boot quickly and they wouldn't bother much about a harmless warning
>>>>>> splat appearing in the dmesg log.
>>>>>
>>>>> You mean quickly booting into a "harmless" potential deadlock condition the
>>>>> warning splat tries to make people aware of? :)
>>>>>
>>>>
>>>> Hmm, I overlooked the built-as-module part where the deadlock could be possible
>>>> as indicated by the comment about the WARN_ON_ONCE().
>>>>
>>>> But what is the path forward here? Do you want the phylib to fix the
>>>> request_module() call or fix the driver core instead?
>>>
>>> Here are a few thoughts.
>>>
>>> In general, I think the best would be to get rid of the (affected)
>>> PROBE_FORCE_SYNCHRONOUS cases.
>>>
>>> Now, I guess this can be pretty hard for a PCI controller driver, as you can't
>>> really predict what ends up being probed from you async context, i.e. it could
>>> even be some other bus controller and things could even propagate further.
>>>
>>> Not sure how big of a deal it is in practice though, there are not a lot of
>>> PROBE_FORCE_SYNCHRONOUS drivers (left), but note that specifying neither
>>> PROBE_FORCE_SYNCHRONOUS nor PROBE_PREFER_ASYNCHRONOUS currently results in
>>> synchronous by default.
>>>
>>> (Also, quite some other PCI controller drivers do set PROBE_PREFER_ASYNCHRONOUS
>>> and apparently got lucky with it.)
>>>
>>> From a driver-core perspective I think we're rather limited on what we can do;
>>> we are already in async context at this point and can't magically go back to
>>> initcall context.
>>>
>>> So, the only thing I can think of is to kick off work on a workqueue, which in
>>> the end would be the same as the deferred probe handling.
>>
>> Hmm, in fact, isn't the deferred probe mechanism itself actually quite
>> appropriate? A suitable calling context isn't the most obvious "resource
>> provider" to wait for, but ultimately it's still a case of "we don't
>> have everything we need right now, but it's worth trying again soon".
>> I may have missed some subtleties, but my instinct is that it could
>> perhaps be as simple as something like this (completely untested).
>>
>> Cheers,
>> Robin.
>>
>> ----->8-----
>>
>> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
>> index bea8da5f8a3a..3c4a0207ae3f 100644
>> --- a/drivers/base/dd.c
>> +++ b/drivers/base/dd.c
>> @@ -954,6 +954,16 @@ static int __device_attach_driver(struct device_driver *drv, void *_data)
>> if (data->check_async && async_allowed != data->want_async)
>> return 0;
>> + /*
>> + * Bus drivers may probe asynchronously, but be adding a child device
>> + * whose driver still wants a synchronous probe. In this case, just
>> + * defer it, to be triggered by the parent driver probe succeeding.
>> + */
>> + if (!async_allowed && current_is_async()) {
>> + driver_deferred_probe_add(dev);
>> + return 0;
>> + }
>
> That means that you are kicking the majority devices (for now) into
> deferral path. I do not think this is optimal.
And probing drivers under conditions where they may go wrong or deadlock
is better? I've not yet had a chance to actually test this myself to see
the effect on timings, but whatever it might be, I can't imagine any
*other* method of re-serialising child driver probes could be
significantly better (or if it could be, that might represent some
improvement we could make to the deferred probe mechanism in general
anyway).
I have finally got a bit of time this afternoon to pick this up again,
so I'll have a play and try to finish the write-up capturing all the
reasoning so far (it's a long one...)
> Does phy really need to request modules synchronously (and on its own)?
> Why can't it rely on udev to load the modules and signal when phy
> devices are ready?
Getting hung up on what phylib does in this one particular case is
rather missing the point. There is a reason that we're still not forcing
async_probe on for everything by default. Many drivers will still not
have been tested and validated to handle it correctly, and while the
majority of latent issues will likely just be concurrency bugs which can
be fixed with better locking or whatever, even then we should be
encouraging developers to actively test and look for such bugs to make
their drivers "async probe clean", rather than knowingly enabling bugs
to surface in the wild as weird and subtle breakage on end-user systems.
However, I imagine there will always remain some small minority of
PROBE_FORCE_SYNCHRONOUS drivers - either for niche legitimate technical
reasons, or just legacy drivers where updating them would take more
effort than it's worth - so the driver core surely needs the ability to
not do the wrong thing itself. That doesn't even need to be "optimal",
it just needs to be functionally correct.
Thanks,
Robin.
>
> Seems like a deficiency on PHY subsystem that is stuck in times long
> past.
>
> Thanks.
>
^ permalink raw reply
* Re: [PATCH v2 2/6] arm64: dts: freescale: Add Verdin iMX95 support
From: Frank Li @ 2026-03-25 15:01 UTC (permalink / raw)
To: Francesco Dolcini
Cc: Ernest Van Hoecke, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Ernest Van Hoecke, Emanuele Ghidoli, Francesco Dolcini,
devicetree, linux-kernel, imx, linux-arm-kernel
In-Reply-To: <20260325112724.GA7964@francesco-nb>
On Wed, Mar 25, 2026 at 12:27:24PM +0100, Francesco Dolcini wrote:
> On Tue, Mar 24, 2026 at 12:14:35PM -0400, Frank Li wrote:
> > On Fri, Mar 13, 2026 at 09:57:43AM +0100, Ernest Van Hoecke wrote:
> > > From: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
> > >
> > > Add support for the Toradex Verdin iMX95 and its development carrier
> > > board.
> > >
> > > The module consists of an NXP i.MX95 family SoC, up to 16GB LPDDR4x RAM,
> > > up to 128GB of storage, a USB 3.2 OTG and USB 2.0 Host, a Gigabit
> > > Ethernet PHY, an I2C EEPROM and Temperature Sensor, an RX8130 RTC, an
> > > I3C bus, one Quad lane CSI interface, one Quad lane DSI or CSI
> > > interface, one LVDS interface (one or two channels), and some optional
> > > addons: TPM 2.0, and a WiFi/BT module.
> > >
> > > Link: https://www.toradex.com/computer-on-modules/verdin-arm-family/nxp-imx95
> > > Link: https://www.toradex.com/products/carrier-board/verdin-development-board-kit
> > > Co-developed-by: Emanuele Ghidoli <emanuele.ghidoli@toradex.com>
> > > Signed-off-by: Emanuele Ghidoli <emanuele.ghidoli@toradex.com>
> > > Co-developed-by: Francesco Dolcini <francesco.dolcini@toradex.com>
> > > Signed-off-by: Francesco Dolcini <francesco.dolcini@toradex.com>
> > > Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
> > > ---
> > > v2: Reordered nodes alphanumerically by node name
> > > v1: https://lore.kernel.org/all/20260305-verdin-imx95-upstream-frank-li-base-v1-2-823fad02def9@toradex.com/
> > > ---
> > > +
> > > +/* Verdin UART_1, connector X50 through RS485 transceiver */
> > > +&lpuart7 {
> > > + rs485-rts-active-low;
> > > + rs485-rx-during-tx;
> > > + linux,rs485-enabled-at-boot-time;
> > > +
> >
> > Nit: needn't empty line between status and other property, suggest run
> > https://github.com/lznuaa/dt-format to speed up process.
>
> Please review Documentation/devicetree/bindings/dts-coding-style.rst.
>
> Quoting from there
> > "status" (if applicable), preceded by a blank line if there is content before the property
>
> I would be careful on taking every detail of such a style guide literally,
> but your comment here is not correct and it's not helping anyone.
Thank you point out, there are not extra empty line in existing dts.
git grep -r -a3 "status =" arch/arm64/boot/dts/
I think it should update dts-coding-style.rst to match most existing one.
Frank
>
> Francesco
>
^ permalink raw reply
* Re: [PATCH v6 1/5] mm: rmap: support batched checks of the references for large folios
From: Lorenzo Stoakes (Oracle) @ 2026-03-25 15:06 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Baolin Wang, Barry Song, akpm, catalin.marinas, will,
lorenzo.stoakes, ryan.roberts, Liam.Howlett, vbabka, rppt, surenb,
mhocko, riel, harry.yoo, jannh, willy, dev.jain, linux-mm,
linux-arm-kernel, linux-kernel
In-Reply-To: <e3e374cc-ddf2-4112-b063-6cb1839ea566@kernel.org>
On Wed, Mar 25, 2026 at 03:58:36PM +0100, David Hildenbrand (Arm) wrote:
> On 3/25/26 15:36, Lorenzo Stoakes (Oracle) wrote:
> > On Mon, Mar 16, 2026 at 03:15:18PM +0100, David Hildenbrand (Arm) wrote:
> >> On 3/16/26 07:25, Baolin Wang wrote:
> >>>
> >>>
> >>>
> >>> Sure. However, after investigating RISC‑V and x86, I found that
> >>> ptep_clear_flush_young() does not flush the TLB on these architectures:
> >>>
> >>> int ptep_clear_flush_young(struct vm_area_struct *vma,
> >>> unsigned long address, pte_t *ptep)
> >>> {
> >>> /*
> >>> * On x86 CPUs, clearing the accessed bit without a TLB flush
> >>> * doesn't cause data corruption. [ It could cause incorrect
> >>> * page aging and the (mistaken) reclaim of hot pages, but the
> >>> * chance of that should be relatively low. ]
> >>> *
> >>> * So as a performance optimization don't flush the TLB when
> >>> * clearing the accessed bit, it will eventually be flushed by
> >>> * a context switch or a VM operation anyway. [ In the rare
> >>> * event of it not getting flushed for a long time the delay
> >>> * shouldn't really matter because there's no real memory
> >>> * pressure for swapout to react to. ]
> >>> */
> >>> return ptep_test_and_clear_young(vma, address, ptep);
> >>> }
> >>
> >> You'd probably want an arch helper then, that tells you whether
> >> a flush_tlb_range() after ptep_test_and_clear_young() is required.
> >>
> >> Or some special flush_tlb_range() helper.
> >>
> >> I agree that it requires more work.
> >
> > Sorry unclear here - does the series need more work or does a follow up patch
> > need more work?
>
> Follow up!
Ok good as in mm-stable now. Sadly means I don't get to review it but there we
go.
>
> --
> Cheers,
>
> David
Thanks, Lorenzo
^ permalink raw reply
* Re: [PATCH v3 3/7] pinctrl: pinctrl-generic: add __pinctrl_generic_pins_function_dt_node_to_map()
From: Frank Li @ 2026-03-25 15:09 UTC (permalink / raw)
To: Conor Dooley
Cc: Linus Walleij, Peter Rosin, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rafał Miłecki, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, linux-kernel, linux-gpio,
devicetree, imx, linux-arm-kernel, Haibo Chen
In-Reply-To: <20260325-riding-browbeat-293b47f43d82@spud>
On Wed, Mar 25, 2026 at 10:33:05AM +0000, Conor Dooley wrote:
> On Tue, Mar 24, 2026 at 04:16:10PM -0400, Frank Li wrote:
> > On Fri, Mar 20, 2026 at 09:54:45AM -0400, Frank Li wrote:
> > > On Fri, Mar 20, 2026 at 02:27:21PM +0100, Linus Walleij wrote:
> > > > On Thu, Mar 19, 2026 at 12:04 AM Frank Li <Frank.li@nxp.com> wrote:
> > > > > On Mon, Mar 16, 2026 at 10:37:28AM +0100, Linus Walleij wrote:
> > > >
> > > > > > That said: in this case you're just adding a parameter, just add
> > > > > > the parameter and change all of the in-tree users to pass false
> > > > > > or whatever you need, these is just one (1) in-tree user anyway.
> > > > >
> > > > > pinctrl_generic_pins_function_dt_node_to_map() directly feed to
> > > > > .dt_node_to_map() callback, add parameter will impact too much.
> > > >
> > > > Why do you say that. It already has many parameters, one more
> > > > or less doesn't matter. It's not like this call is performance-critical.
> > > > Just change the users.
> > >
> > > In only user drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c,
> > > .dt_node_to_map = pinctrl_generic_pins_function_dt_node_to_map;
> > >
> > > pinctrl_generic_pins_function_dt_node_to_map() need match .dt_node_to_map()'s
> > > declear.
> > >
> > > So it can't direct add two parameters in pinctrl_generic_pins_function_dt_node_to_map()
> > > Need simple wrap function, which other in pinctrl-mpfs-mssio.c or in
> > > pinconf.h.
> > >
> > > If add two parameter in .dt_node_to_map(), need change all functions, which
> > > .dt_node_to_map = xxx_to_map(). and OF core part.
> >
> > Linus Walleij:
> > Is my explain clear enough? I am preparing respin it?
> >
> > is okay use wrap function
> > pinctrl_generic_pins_function_dt_node_to_map_ext()?
>
> I don't understand this patch. The function is called
> pinctrl_generic_pins_function_dt_node_to_map(). You have no pins.
> You're adding a parameter to make a function with *pins* in its name not
> use pins. The new function doesn't use pins but has pins in the name.
> At the very least function names should not be misleading.
>
> I was going to suggest pulling out the relevant portions and creating
> some helpers that could be used by multiple different-but-similar
> functions, but I don't actually even think that there's much in common.
> Most damningly I think, you don't actually read either the functions or
> pins properties at all and neither are permitted by your binding.
> So turns out you use neither pins or functions...
>
> You don't actually have any of these properties which runs counter to the
> goal of the function, which is parsing. With this in mind, it feels to me
> like you're trying way too hard to make use of a generic function when the
> right thing to do is probably just have an entirely custom function.
> Maybe that's a custom implementation in your driver, or a new function
> here, but I think writing that will highlight just how little of the
> code would be shared between the existing function and what your
> use-case needs: no pin configuration stuff, no reading of the devicetree
> other than the node names and no dealing with the label pointing to the
> "wrong" place.
>
> I recently bought a spacemit k1 board to go and write a sister function
> to pinctrl_generic_pins_function_dt_node_to_map() that deals with pins
> and groups (because that's a pretty common pattern).
> I would be calling that pinctrl_generic_pinmux_dt_node_to_map(),
> because it that's the property it deals with. I have honestly got no
> idea what to call one for this situation since you don't have any of the
> properties in pinmux-node.yaml. Maybe that's a sign.
At v2, I implemented customize dt_node_to_map(), Linus Walleij think it is
too similar with pinctrl_generic_pins_function_dt_node_to_map(), so ask me
to enhanance and reuse pinctrl_generic_pins_function_dt_node_to_map().
Frank
>
> Cheers,
> Conor.
^ permalink raw reply
* Re: [PATCH RESEND v8 3/6] mfd: max77759: add register bitmasks and modify irq configs for charger
From: Lee Jones @ 2026-03-25 15:10 UTC (permalink / raw)
To: Amit Sunil Dhamne via B4 Relay
Cc: Sebastian Reichel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
André Draszik, Greg Kroah-Hartman, Badhri Jagan Sridharan,
Heikki Krogerus, Peter Griffin, Tudor Ambarus, Alim Akhtar,
Mark Brown, Matti Vaittinen, Andrew Morton, linux-kernel,
linux-pm, devicetree, linux-usb, linux-arm-kernel,
linux-samsung-soc, RD Babiera, Kyle Tso, Amit Sunil Dhamne
In-Reply-To: <20260314-max77759-charger-v8-3-226ca5f8c7d2@google.com>
On Sat, 14 Mar 2026, Amit Sunil Dhamne via B4 Relay wrote:
> From: Amit Sunil Dhamne <amitsd@google.com>
>
> Add register bitmasks for charger function.
>
> In addition split the charger IRQs further such that each bit represents
> an IRQ downstream of charger regmap irq chip. In addition populate the
> ack_base to offload irq ack to the regmap irq chip framework.
>
> Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
> Reviewed-by: André Draszik <andre.draszik@linaro.org>
> ---
> drivers/mfd/max77759.c | 91 ++++++++++++++++++++--
> include/linux/mfd/max77759.h | 176 ++++++++++++++++++++++++++++++++++++-------
> 2 files changed, 230 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/mfd/max77759.c b/drivers/mfd/max77759.c
> index a7efe233ec8c..288746f675b8 100644
> --- a/drivers/mfd/max77759.c
> +++ b/drivers/mfd/max77759.c
> @@ -201,8 +201,24 @@ static const struct regmap_config max77759_regmap_config_charger = {
> * - SYSUVLO_INT
> * - FSHIP_NOT_RD
> * - CHGR_INT: charger
> - * - CHG_INT
> - * - CHG_INT2
> + * - INT1
> + * - AICL
> + * - CHGIN
> + * - WCIN
> + * - CHG
> + * - BAT
> + * - INLIM
> + * - THM2
> + * - BYP
> + * - INT2
> + * - INSEL
> + * - SYS_UVLO1
> + * - SYS_UVLO2
> + * - BAT_OILO
> + * - CHG_STA_CC
> + * - CHG_STA_CV
> + * - CHG_STA_TO
> + * - CHG_STA_DONE
> */
> enum {
> MAX77759_INT_MAXQ,
> @@ -256,8 +286,38 @@ static const struct regmap_irq max77759_topsys_irqs[] = {
> };
>
> static const struct regmap_irq max77759_chgr_irqs[] = {
> - REGMAP_IRQ_REG(MAX77759_CHARGER_INT_1, 0, GENMASK(7, 0)),
> - REGMAP_IRQ_REG(MAX77759_CHARGER_INT_2, 1, GENMASK(7, 0)),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT1_AICL, 0,
> + MAX77759_CHGR_REG_CHG_INT_AICL),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT1_CHGIN, 0,
> + MAX77759_CHGR_REG_CHG_INT_CHGIN),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT1_WCIN, 0,
> + MAX77759_CHGR_REG_CHG_INT_WCIN),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT1_CHG, 0,
> + MAX77759_CHGR_REG_CHG_INT_CHG),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT1_BAT, 0,
> + MAX77759_CHGR_REG_CHG_INT_BAT),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT1_INLIM, 0,
> + MAX77759_CHGR_REG_CHG_INT_INLIM),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT1_THM2, 0,
> + MAX77759_CHGR_REG_CHG_INT_THM2),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT1_BYP, 0,
> + MAX77759_CHGR_REG_CHG_INT_BYP),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT2_INSEL, 1,
> + MAX77759_CHGR_REG_CHG_INT2_INSEL),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT2_SYS_UVLO1, 1,
> + MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO1),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT2_SYS_UVLO2, 1,
> + MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO2),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT2_BAT_OILO, 1,
> + MAX77759_CHGR_REG_CHG_INT2_BAT_OILO),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_CC, 1,
> + MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CC),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_CV, 1,
> + MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CV),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_TO, 1,
> + MAX77759_CHGR_REG_CHG_INT2_CHG_STA_TO),
> + REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_DONE, 1,
> + MAX77759_CHGR_REG_CHG_INT2_CHG_STA_DONE),
> };
>
> static const struct regmap_irq_chip max77759_pmic_irq_chip = {
> @@ -302,6 +362,7 @@ static const struct regmap_irq_chip max77759_chrg_irq_chip = {
Minor nit: The new code in this patch consistently uses "chgr" as the prefix
for charger-related names. To improve consistency, how about we rename this
struct to `max77759_chgr_irq_chip`?
> .domain_suffix = "CHGR",
> .status_base = MAX77759_CHGR_REG_CHG_INT,
> .mask_base = MAX77759_CHGR_REG_CHG_INT_MASK,
> + .ack_base = MAX77759_CHGR_REG_CHG_INT,
> .num_regs = 2,
> .irqs = max77759_chgr_irqs,
> .num_irqs = ARRAY_SIZE(max77759_chgr_irqs),
> @@ -325,8 +386,22 @@ static const struct resource max77759_gpio_resources[] = {
> };
>
> static const struct resource max77759_charger_resources[] = {
> - DEFINE_RES_IRQ_NAMED(MAX77759_CHARGER_INT_1, "INT1"),
> - DEFINE_RES_IRQ_NAMED(MAX77759_CHARGER_INT_2, "INT2"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_AICL, "AICL"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_CHGIN, "CHGIN"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_WCIN, "WCIN"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_CHG, "CHG"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_BAT, "BAT"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_INLIM, "INLIM"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_THM2, "THM2"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_BYP, "BYP"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_INSEL, "INSEL"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_SYS_UVLO1, "SYS_UVLO1"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_SYS_UVLO2, "SYS_UVLO2"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_BAT_OILO, "BAT_OILO"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_CC, "CHG_STA_CC"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_CV, "CHG_STA_CV"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_TO, "CHG_STA_TO"),
> + DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_DONE, "CHG_STA_DONE"),
> };
>
> static const struct mfd_cell max77759_cells[] = {
> diff --git a/include/linux/mfd/max77759.h b/include/linux/mfd/max77759.h
> index c6face34e385..fd5aea21ab2e 100644
> --- a/include/linux/mfd/max77759.h
> +++ b/include/linux/mfd/max77759.h
> @@ -59,35 +59,65 @@
> #define MAX77759_MAXQ_REG_AP_DATAIN0 0xb1
> #define MAX77759_MAXQ_REG_UIC_SWRST 0xe0
>
> -#define MAX77759_CHGR_REG_CHG_INT 0xb0
> -#define MAX77759_CHGR_REG_CHG_INT2 0xb1
> -#define MAX77759_CHGR_REG_CHG_INT_MASK 0xb2
> -#define MAX77759_CHGR_REG_CHG_INT2_MASK 0xb3
> -#define MAX77759_CHGR_REG_CHG_INT_OK 0xb4
> -#define MAX77759_CHGR_REG_CHG_DETAILS_00 0xb5
> -#define MAX77759_CHGR_REG_CHG_DETAILS_01 0xb6
> -#define MAX77759_CHGR_REG_CHG_DETAILS_02 0xb7
> -#define MAX77759_CHGR_REG_CHG_DETAILS_03 0xb8
> -#define MAX77759_CHGR_REG_CHG_CNFG_00 0xb9
> -#define MAX77759_CHGR_REG_CHG_CNFG_01 0xba
> -#define MAX77759_CHGR_REG_CHG_CNFG_02 0xbb
> -#define MAX77759_CHGR_REG_CHG_CNFG_03 0xbc
> -#define MAX77759_CHGR_REG_CHG_CNFG_04 0xbd
> -#define MAX77759_CHGR_REG_CHG_CNFG_05 0xbe
> -#define MAX77759_CHGR_REG_CHG_CNFG_06 0xbf
> -#define MAX77759_CHGR_REG_CHG_CNFG_07 0xc0
> -#define MAX77759_CHGR_REG_CHG_CNFG_08 0xc1
> -#define MAX77759_CHGR_REG_CHG_CNFG_09 0xc2
> -#define MAX77759_CHGR_REG_CHG_CNFG_10 0xc3
> -#define MAX77759_CHGR_REG_CHG_CNFG_11 0xc4
> -#define MAX77759_CHGR_REG_CHG_CNFG_12 0xc5
> -#define MAX77759_CHGR_REG_CHG_CNFG_13 0xc6
> -#define MAX77759_CHGR_REG_CHG_CNFG_14 0xc7
> -#define MAX77759_CHGR_REG_CHG_CNFG_15 0xc8
> -#define MAX77759_CHGR_REG_CHG_CNFG_16 0xc9
> -#define MAX77759_CHGR_REG_CHG_CNFG_17 0xca
> -#define MAX77759_CHGR_REG_CHG_CNFG_18 0xcb
> -#define MAX77759_CHGR_REG_CHG_CNFG_19 0xcc
> +#define MAX77759_CHGR_REG_CHG_INT 0xb0
> +#define MAX77759_CHGR_REG_CHG_INT_AICL BIT(7)
> +#define MAX77759_CHGR_REG_CHG_INT_CHGIN BIT(6)
> +#define MAX77759_CHGR_REG_CHG_INT_WCIN BIT(5)
> +#define MAX77759_CHGR_REG_CHG_INT_CHG BIT(4)
> +#define MAX77759_CHGR_REG_CHG_INT_BAT BIT(3)
> +#define MAX77759_CHGR_REG_CHG_INT_INLIM BIT(2)
> +#define MAX77759_CHGR_REG_CHG_INT_THM2 BIT(1)
> +#define MAX77759_CHGR_REG_CHG_INT_BYP BIT(0)
> +#define MAX77759_CHGR_REG_CHG_INT2 0xb1
> +#define MAX77759_CHGR_REG_CHG_INT2_INSEL BIT(7)
> +#define MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO1 BIT(6)
> +#define MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO2 BIT(5)
> +#define MAX77759_CHGR_REG_CHG_INT2_BAT_OILO BIT(4)
> +#define MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CC BIT(3)
> +#define MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CV BIT(2)
> +#define MAX77759_CHGR_REG_CHG_INT2_CHG_STA_TO BIT(1)
> +#define MAX77759_CHGR_REG_CHG_INT2_CHG_STA_DONE BIT(0)
> +#define MAX77759_CHGR_REG_CHG_INT_MASK 0xb2
> +#define MAX77759_CHGR_REG_CHG_INT2_MASK 0xb3
> +#define MAX77759_CHGR_REG_CHG_INT_OK 0xb4
> +#define MAX77759_CHGR_REG_CHG_DETAILS_00 0xb5
> +#define MAX77759_CHGR_REG_CHG_DETAILS_00_CHGIN_DTLS GENMASK(6, 5)
> +#define MAX77759_CHGR_REG_CHG_DETAILS_01 0xb6
> +#define MAX77759_CHGR_REG_CHG_DETAILS_01_BAT_DTLS GENMASK(6, 4)
> +#define MAX77759_CHGR_REG_CHG_DETAILS_01_CHG_DTLS GENMASK(3, 0)
> +#define MAX77759_CHGR_REG_CHG_DETAILS_02 0xb7
> +#define MAX77759_CHGR_REG_CHG_DETAILS_02_CHGIN_STS BIT(5)
> +#define MAX77759_CHGR_REG_CHG_DETAILS_03 0xb8
> +#define MAX77759_CHGR_REG_CHG_CNFG_00 0xb9
> +#define MAX77759_CHGR_REG_CHG_CNFG_00_MODE GENMASK(3, 0)
> +#define MAX77759_CHGR_REG_CHG_CNFG_01 0xba
> +#define MAX77759_CHGR_REG_CHG_CNFG_02 0xbb
> +#define MAX77759_CHGR_REG_CHG_CNFG_02_CHGCC GENMASK(5, 0)
> +#define MAX77759_CHGR_REG_CHG_CNFG_03 0xbc
> +#define MAX77759_CHGR_REG_CHG_CNFG_04 0xbd
> +#define MAX77759_CHGR_REG_CHG_CNFG_04_CHG_CV_PRM GENMASK(5, 0)
> +#define MAX77759_CHGR_REG_CHG_CNFG_05 0xbe
> +#define MAX77759_CHGR_REG_CHG_CNFG_06 0xbf
> +#define MAX77759_CHGR_REG_CHG_CNFG_06_CHGPROT GENMASK(3, 2)
> +#define MAX77759_CHGR_REG_CHG_CNFG_07 0xc0
> +#define MAX77759_CHGR_REG_CHG_CNFG_08 0xc1
> +#define MAX77759_CHGR_REG_CHG_CNFG_09 0xc2
> +#define MAX77759_CHGR_REG_CHG_CNFG_09_CHGIN_ILIM GENMASK(6, 0)
> +#define MAX77759_CHGR_REG_CHG_CNFG_10 0xc3
> +#define MAX77759_CHGR_REG_CHG_CNFG_11 0xc4
> +#define MAX77759_CHGR_REG_CHG_CNFG_12 0xc5
> +/* Wireless Charging input channel select */
> +#define MAX77759_CHGR_REG_CHG_CNFG_12_WCINSEL BIT(6)
> +/* CHGIN/USB input channel select */
> +#define MAX77759_CHGR_REG_CHG_CNFG_12_CHGINSEL BIT(5)
> +#define MAX77759_CHGR_REG_CHG_CNFG_13 0xc6
> +#define MAX77759_CHGR_REG_CHG_CNFG_14 0xc7
> +#define MAX77759_CHGR_REG_CHG_CNFG_15 0xc8
> +#define MAX77759_CHGR_REG_CHG_CNFG_16 0xc9
> +#define MAX77759_CHGR_REG_CHG_CNFG_17 0xca
> +#define MAX77759_CHGR_REG_CHG_CNFG_18 0xcb
> +#define MAX77759_CHGR_REG_CHG_CNFG_18_WDTEN BIT(0)
> +#define MAX77759_CHGR_REG_CHG_CNFG_19 0xcc
>
> /* MaxQ opcodes for max77759_maxq_command() */
> #define MAX77759_MAXQ_OPCODE_MAXLENGTH (MAX77759_MAXQ_REG_AP_DATAOUT32 - \
> @@ -101,6 +131,94 @@
> #define MAX77759_MAXQ_OPCODE_USER_SPACE_READ 0x81
> #define MAX77759_MAXQ_OPCODE_USER_SPACE_WRITE 0x82
>
> +/*
> + * Charger Input Status
> + * @MAX77759_CHGR_CHGIN_DTLS_VBUS_UNDERVOLTAGE:
> + * Charger input voltage (Vchgin) < Under Voltage Threshold (Vuvlo)
> + * @MAX77759_CHGR_CHGIN_DTLS_VBUS_MARGINAL_VOLTAGE: Vchgin > Vuvlo and
> + * Vchgin < (Battery Voltage (Vbatt) + system voltage (Vsys))
> + * @MAX77759_CHGR_CHGIN_DTLS_VBUS_OVERVOLTAGE:
> + * Vchgin > Over Voltage threshold (Vovlo)
> + * @MAX77759_CHGR_CHGIN_DTLS_VBUS_VALID:
> + * Vchgin > Vuvlo, Vchgin < Vovlo and Vchgin > (Vsys + Vbatt)
> + */
> +enum max77759_chgr_chgin_dtls_status {
> + MAX77759_CHGR_CHGIN_DTLS_VBUS_UNDERVOLTAGE,
> + MAX77759_CHGR_CHGIN_DTLS_VBUS_MARGINAL_VOLTAGE,
> + MAX77759_CHGR_CHGIN_DTLS_VBUS_OVERVOLTAGE,
> + MAX77759_CHGR_CHGIN_DTLS_VBUS_VALID,
> +};
> +
> +/*
> + * Battery Details
> + * @MAX77759_CHGR_BAT_DTLS_NO_BATT_CHG_SUSP:
> + * No battery and the charger suspended
> + * @MAX77759_CHGR_BAT_DTLS_DEAD_BATTERY: Vbatt < Vtrickle
> + * @MAX77759_CHGR_BAT_DTLS_BAT_CHG_TIMER_FAULT:
> + * Charging suspended due to timer fault
> + * @MAX77759_CHGR_BAT_DTLS_BAT_OKAY:
> + * Battery okay and Vbatt > Min Sys Voltage (Vsysmin)
> + * @MAX77759_CHGR_BAT_DTLS_BAT_UNDERVOLTAGE:
> + * Battery is okay. Vtrickle < Vbatt < Vsysmin
> + * @MAX77759_CHGR_BAT_DTLS_BAT_OVERVOLTAGE:
> + * Battery voltage > Overvoltage threshold
> + * @MAX77759_CHGR_BAT_DTLS_BAT_OVERCURRENT:
> + * Battery current exceeds overcurrent threshold
> + * @MAX77759_CHGR_BAT_DTLS_BAT_ONLY_MODE:
> + * Battery only mode and battery level not available
> + */
> +enum max77759_chgr_bat_dtls_states {
> + MAX77759_CHGR_BAT_DTLS_NO_BATT_CHG_SUSP,
> + MAX77759_CHGR_BAT_DTLS_DEAD_BATTERY,
> + MAX77759_CHGR_BAT_DTLS_BAT_CHG_TIMER_FAULT,
> + MAX77759_CHGR_BAT_DTLS_BAT_OKAY,
> + MAX77759_CHGR_BAT_DTLS_BAT_UNDERVOLTAGE,
> + MAX77759_CHGR_BAT_DTLS_BAT_OVERVOLTAGE,
> + MAX77759_CHGR_BAT_DTLS_BAT_OVERCURRENT,
> + MAX77759_CHGR_BAT_DTLS_BAT_ONLY_MODE,
> +};
> +
> +/*
> + * Charger Details
> + * @MAX77759_CHGR_CHG_DTLS_PREQUAL: Charger in prequalification mode
> + * @MAX77759_CHGR_CHG_DTLS_CC: Charger in fast charge const curr mode
> + * @MAX77759_CHGR_CHG_DTLS_CV: Charger in fast charge const voltage mode
> + * @MAX77759_CHGR_CHG_DTLS_TO: Charger is in top off mode
> + * @MAX77759_CHGR_CHG_DTLS_DONE: Charger is done
> + * @MAX77759_CHGR_CHG_DTLS_RSVD_1: Reserved
> + * @MAX77759_CHGR_CHG_DTLS_TIMER_FAULT: Charger is in timer fault mode
> + * @MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM:
> + * Charger is suspended as bettery removal detected
Typo here, s/bettery/battery/.
> + * @MAX77759_CHGR_CHG_DTLS_OFF:
> + * Charger is off. Input invalid or charger disabled
> + * @MAX77759_CHGR_CHG_DTLS_RSVD_2: Reserved
> + * @MAX77759_CHGR_CHG_DTLS_RSVD_3: Reserved
> + * @MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER:
> + * Charger is off as watchdog timer expired
> + * @MAX77759_CHGR_CHG_DTLS_SUSP_JEITA: Charger is in JEITA control mode
> + */
> +enum max77759_chgr_chg_dtls_states {
Just a small style suggestion, could you please align the descriptions in this
kerneldoc block? It improves readability. Using a consistent number of spaces
or tabs after the colon helps.
Feel free to use up to 100-chars if it improves readability.
> + MAX77759_CHGR_CHG_DTLS_PREQUAL,
> + MAX77759_CHGR_CHG_DTLS_CC,
> + MAX77759_CHGR_CHG_DTLS_CV,
> + MAX77759_CHGR_CHG_DTLS_TO,
> + MAX77759_CHGR_CHG_DTLS_DONE,
> + MAX77759_CHGR_CHG_DTLS_RSVD_1,
> + MAX77759_CHGR_CHG_DTLS_TIMER_FAULT,
> + MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM,
> + MAX77759_CHGR_CHG_DTLS_OFF,
> + MAX77759_CHGR_CHG_DTLS_RSVD_2,
> + MAX77759_CHGR_CHG_DTLS_RSVD_3,
> + MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER,
> + MAX77759_CHGR_CHG_DTLS_SUSP_JEITA,
> +};
> +
> +enum max77759_chgr_mode {
> + MAX77759_CHGR_MODE_OFF,
> + MAX77759_CHGR_MODE_CHG_BUCK_ON = 0x5,
> + MAX77759_CHGR_MODE_OTG_BOOST_ON = 0xA,
> +};
> +
> /**
> * struct max77759 - core max77759 internal data structure
> *
--
Lee Jones [李琼斯]
^ permalink raw reply
* Re: [PATCH bpf-next v10 1/5] bpf: Move constants blinding out of arch-specific JITs
From: Alexei Starovoitov @ 2026-03-25 15:12 UTC (permalink / raw)
To: Xu Kuohai
Cc: bot+bpf-ci, bpf, LKML, linux-arm-kernel, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau, Eduard,
Yonghong Song, Puranjay Mohan, Anton Protopopov,
Alexis Lothoré (eBPF Foundation), Shahab Vahedi,
Russell King, Tiezhu Yang, Hengqi Chen, Johan Almbladh,
Paul Burton, Hari Bathini, Christophe Leroy, Naveen N. Rao,
Luke Nelson, Xi Wang, Björn Töpel, Pu Lehui,
Ilya Leoshkevich, Heiko Carstens, Vasily Gorbik, David S. Miller,
Wang YanQing, Martin KaFai Lau, Chris Mason, Ihor Solodrai
In-Reply-To: <5b24cd1d-a8cf-4c9c-a0c8-c79c10ea80e4@huaweicloud.com>
On Wed, Mar 25, 2026 at 12:47 AM Xu Kuohai <xukuohai@huaweicloud.com> wrote:
>
> On 3/24/2026 8:46 PM, bot+bpf-ci@kernel.org wrote:
> >> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> >> index 67eb12b637a5..8f52f4b6c3af 100644
> >> --- a/kernel/bpf/core.c
> >> +++ b/kernel/bpf/core.c
> >
> > [ ... ]
> >
> >> @@ -1507,13 +1507,16 @@ static void adjust_insn_arrays(struct bpf_prog *prog, u32 off, u32 len)
> >> #endif
> >> }
> >>
> >> -struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
> >> +struct bpf_prog *bpf_jit_blind_constants(struct bpf_verifier_env *env, struct bpf_prog *prog)
> >> {
> >
> > [ ... ]
> >
> >> - tmp = bpf_patch_insn_single(clone, i, insn_buff, rewritten);
> >> - if (IS_ERR(tmp)) {
> >> + if (env)
> >> + tmp = bpf_patch_insn_data(env, subprog_start + i, insn_buff, rewritten);
> >> + else
> >> + tmp = bpf_patch_insn_single(clone, i, insn_buff, rewritten);
> >
> > When env is non-NULL, bpf_patch_insn_data() adjusts env->insn_aux_data
> > via adjust_insn_aux_data() and env->subprog_info via
> > adjust_subprog_starts(). This shifts subprogram start positions to
> > account for the expanded instructions.
> >
>
> Right, but only the subsequent subprogs are shifted, the current subprog
> is not. Since we are patching the main prog when env is non-NULL, and
> subprog_start is always 0 for a main prog, subprog_start is not needed
> here and can be removed.
sashiko found other bugs too:
https://sashiko.dev/#/patchset/20260324122052.342751-1-xukuohai%40huaweicloud.com
Pls fix them all.
^ permalink raw reply
* Re: [PATCH v3] PCI: dw-rockchip: Enable async probe by default
From: Danilo Krummrich @ 2026-03-25 15:13 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Robin Murphy, Manivannan Sadhasivam, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Heiko Stuebner, Niklas Cassel, Shawn Lin,
Hans Zhang, Nicolas Frattaroli, Wilfred Mallawa, linux-pci,
linux-arm-kernel, linux-rockchip, linux-kernel, Anand Moon,
Grimmauld, Greg Kroah-Hartman, Rafael J. Wysocki, driver-core,
Lukas Wunner
In-Reply-To: <acNgUoWWMCi1oLU4@google.com>
On Wed Mar 25, 2026 at 5:13 AM CET, Dmitry Torokhov wrote:
> That means that you are kicking the majority devices (for now) into
> deferral path. I do not think this is optimal.
That's not necessary, we'd only need to kick those into the deferral path that
have PROBE_FORCE_SYNCHRONOUS, no?
^ permalink raw reply
* Re: [PATCH] arm64: dts: imx8mp: Add DT overlays for DH i.MX8M Plus DHCOM SoM and boards
From: Frank Li @ 2026-03-25 15:16 UTC (permalink / raw)
To: Marek Vasut
Cc: linux-arm-kernel, Christoph Niedermaier, Conor Dooley,
Fabio Estevam, Krzysztof Kozlowski, Pengutronix Kernel Team,
Rob Herring, Sascha Hauer, devicetree, imx, kernel, linux-kernel
In-Reply-To: <e580bc1d-96ce-43c5-880f-bb8ee31fda28@nabladev.com>
On Tue, Mar 24, 2026 at 10:43:25PM +0100, Marek Vasut wrote:
> On 3/24/26 9:00 PM, Frank Li wrote:
> > On Tue, Mar 24, 2026 at 06:39:10PM +0100, Marek Vasut wrote:
> > > On 3/24/26 5:01 PM, Frank Li wrote:
> > > > On Fri, Mar 13, 2026 at 12:24:04AM +0100, Marek Vasut wrote:
> > > > ...
> > > >
> > > > > diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-overlay-panel-ch101olhlwh.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-overlay-panel-ch101olhlwh.dtsi
> > > > > new file mode 100644
> > > > > index 0000000000000..534737363c9f0
> > > > > --- /dev/null
> > > > > +++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-overlay-panel-ch101olhlwh.dtsi
> > > > > @@ -0,0 +1,42 @@
> > > > > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > > > > +/*
> > > > > + * Copyright (C) 2022 Marek Vasut
> > > >
> > > > 2026?
> > >
> > > That was the original copyright year when this was implemented, but I can
> > > update it to 2022-2026 ?
> >
> > Okay, you upstream this year.
>
> Right, V2 does extend the copyrights until this year.
>
> > > > > + */
> > > > > +
> > > > > +&display_bl {
> > > > > + pwms = <&pwm1 0 5000000 0>;
> > > > > +};
> > > > > +
> > > > > +&DH_OVERLAY_PANEL_I2C_BUS {
> > > >
> > > > why upcase for label, generally it should be lower case
> > >
> > > Because this label is really a macro , please read on.
> > >
> > > > > + #address-cells = <1>;
> > > > > + #size-cells = <0>;
> > > > > +
> > > > > + touchscreen@41 {
> > > > > + compatible = "ilitek,ili251x";
> > > > > + pinctrl-0 = <DH_OVERLAY_PANEL_I2C_TOUCHSCREEN_PINCTRL>;
> > > > > + pinctrl-names = "default";
> > > > > + reg = <0x41>;
> > > >
> > > > reg should second property, please dt-format for new dts files.
> > > > check others
> > > What is "dt-format" ? Linux kernel source tree, even current next, does not
> > > mention such a tool . I did run schema check and checkpatch on these
> > > patches. obv.
> >
> > I send out at many place, https://github.com/lznuaa/dt-format
> > I write small tools to detect and fix node and property order problem,
> > it may be buggy.
> >
> > These node order problem is easy to detected and fix by tools to save
> > review cycle and focus on the important stuff.
> Maybe "make dtbs_check" target could include this tool , to make people
> aware of it ?
Good suggest, but it is not mature and not everyone agree all code style
yet. practice and run at imx project firstly. It is not perfected, but
helpful.
Frank
^ permalink raw reply
* Re: [PATCH v1] media: rkisp1: Add support for CAC
From: Jacopo Mondi @ 2026-03-25 15:21 UTC (permalink / raw)
To: Barnabás Pőcze
Cc: Dafna Hirschfeld, Laurent Pinchart, Mauro Carvalho Chehab,
Heiko Stuebner, linux-media, linux-rockchip, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260323140216.1486161-1-barnabas.pocze@ideasonboard.com>
Hi Barnabás
On Mon, Mar 23, 2026 at 03:02:16PM +0100, Barnabás Pőcze wrote:
> The CAC block implements chromatic aberration correction. Expose it to
> userspace using the extensible parameters format. This was tested on the
> i.MX8MP platform, but based on available documentation it is also present
> in the RK3399 variant (V10). Thus presumably also in later versions,
> so no feature flag is introduced.
>
> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Only minors..
> ---
> .../platform/rockchip/rkisp1/rkisp1-params.c | 69 ++++++++++++
> .../platform/rockchip/rkisp1/rkisp1-regs.h | 21 +++-
> include/uapi/linux/rkisp1-config.h | 106 +++++++++++++++++-
> 3 files changed, 193 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
> index 6442436a5e428..b889af9dcee45 100644
> --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
> +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
> @@ -64,6 +64,7 @@ union rkisp1_ext_params_config {
> struct rkisp1_ext_params_compand_bls_config compand_bls;
> struct rkisp1_ext_params_compand_curve_config compand_curve;
> struct rkisp1_ext_params_wdr_config wdr;
> + struct rkisp1_ext_params_cac_config cac;
> };
>
> enum rkisp1_params_formats {
> @@ -1413,6 +1414,48 @@ static void rkisp1_wdr_config(struct rkisp1_params *params,
> RKISP1_CIF_ISP_WDR_TONE_CURVE_YM_MASK);
> }
>
> +static void
> +rkisp1_cac_config(struct rkisp1_params *params,
> + const struct rkisp1_cif_isp_cac_config *arg)
Fits in one line without going over 80 cols
> +{
> + u32 regval;
> +
> + /*
> + * The enable bit is in the same register (RKISP1_CIF_ISP_CAC_CTRL),
> + * so only set the clipping mode, and do not modify the other bits.
> + */
> + regval = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_CAC_CTRL);
> + regval &= ~(RKISP1_CIF_ISP_CAC_CTRL_H_CLIP_MODE |
> + RKISP1_CIF_ISP_CAC_CTRL_V_CLIP_MODE);
> + regval |= FIELD_PREP(RKISP1_CIF_ISP_CAC_CTRL_H_CLIP_MODE, arg->h_clip_mode) |
> + FIELD_PREP(RKISP1_CIF_ISP_CAC_CTRL_V_CLIP_MODE, arg->v_clip_mode);
> + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CAC_CTRL, regval);
> +
> + regval = FIELD_PREP(RKISP1_CIF_ISP_CAC_COUNT_START_H_MASK, arg->h_count_start) |
> + FIELD_PREP(RKISP1_CIF_ISP_CAC_COUNT_START_V_MASK, arg->v_count_start);
> + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CAC_COUNT_START, regval);
> +
> + regval = FIELD_PREP(RKISP1_CIF_ISP_CAC_A_RED_MASK, arg->red[0]) |
> + FIELD_PREP(RKISP1_CIF_ISP_CAC_A_BLUE_MASK, arg->blue[0]);
> + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CAC_A, regval);
> +
> + regval = FIELD_PREP(RKISP1_CIF_ISP_CAC_B_RED_MASK, arg->red[1]) |
> + FIELD_PREP(RKISP1_CIF_ISP_CAC_B_BLUE_MASK, arg->blue[1]);
> + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CAC_B, regval);
> +
> + regval = FIELD_PREP(RKISP1_CIF_ISP_CAC_C_RED_MASK, arg->red[2]) |
> + FIELD_PREP(RKISP1_CIF_ISP_CAC_C_BLUE_MASK, arg->blue[2]);
> + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CAC_C, regval);
> +
> + regval = FIELD_PREP(RKISP1_CIF_ISP_CAC_X_NORM_NF_MASK, arg->x_nf) |
> + FIELD_PREP(RKISP1_CIF_ISP_CAC_X_NORM_NS_MASK, arg->x_ns);
> + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CAC_X_NORM, regval);
> +
> + regval = FIELD_PREP(RKISP1_CIF_ISP_CAC_Y_NORM_NF_MASK, arg->y_nf) |
> + FIELD_PREP(RKISP1_CIF_ISP_CAC_Y_NORM_NS_MASK, arg->y_ns);
> + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CAC_Y_NORM, regval);
> +}
> +
> static void
> rkisp1_isp_isr_other_config(struct rkisp1_params *params,
> const struct rkisp1_params_cfg *new_params)
> @@ -2089,6 +2132,25 @@ static void rkisp1_ext_params_wdr(struct rkisp1_params *params,
> RKISP1_CIF_ISP_WDR_CTRL_ENABLE);
> }
>
> +static void rkisp1_ext_params_cac(struct rkisp1_params *params,
> + const union rkisp1_ext_params_config *block)
> +{
> + const struct rkisp1_ext_params_cac_config *cac = &block->cac;
> +
> + if (cac->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) {
> + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CAC_CTRL,
> + RKISP1_CIF_ISP_CAC_CTRL_ENABLE);
> + return;
> + }
> +
> + rkisp1_cac_config(params, &cac->config);
> +
> + if ((cac->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_ENABLE) &&
> + !(params->enabled_blocks & BIT(cac->header.type)))
> + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CAC_CTRL,
> + RKISP1_CIF_ISP_CAC_CTRL_ENABLE);
> +}
> +
> typedef void (*rkisp1_block_handler)(struct rkisp1_params *params,
> const union rkisp1_ext_params_config *config);
>
> @@ -2185,6 +2247,10 @@ static const struct rkisp1_ext_params_handler {
> .handler = rkisp1_ext_params_wdr,
> .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS,
> },
> + [RKISP1_EXT_PARAMS_BLOCK_TYPE_CAC] = {
> + .handler = rkisp1_ext_params_cac,
> + .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS,
> + },
> };
>
> #define RKISP1_PARAMS_BLOCK_INFO(block, data) \
> @@ -2215,6 +2281,7 @@ rkisp1_ext_params_block_types_info[] = {
> RKISP1_PARAMS_BLOCK_INFO(COMPAND_EXPAND, compand_curve),
> RKISP1_PARAMS_BLOCK_INFO(COMPAND_COMPRESS, compand_curve),
> RKISP1_PARAMS_BLOCK_INFO(WDR, wdr),
> + RKISP1_PARAMS_BLOCK_INFO(CAC, cac),
> };
>
> static_assert(ARRAY_SIZE(rkisp1_ext_params_handlers) ==
> @@ -2474,6 +2541,8 @@ void rkisp1_params_disable(struct rkisp1_params *params)
> rkisp1_ie_enable(params, false);
> rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPF_MODE,
> RKISP1_CIF_ISP_DPF_MODE_EN);
> + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CAC_CTRL,
> + RKISP1_CIF_ISP_CAC_CTRL_ENABLE);
> }
>
> static const struct rkisp1_params_ops rkisp1_v10_params_ops = {
> diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
> index fbeb186cde0d5..8e25537459bbd 100644
> --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
> +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
> @@ -724,6 +724,23 @@
> #define RKISP1_CIF_ISP_WDR_DMIN_STRENGTH_MASK GENMASK(20, 16)
> #define RKISP1_CIF_ISP_WDR_DMIN_STRENGTH_MAX 16U
>
> +/* CAC */
> +#define RKISP1_CIF_ISP_CAC_CTRL_ENABLE BIT(0)
> +#define RKISP1_CIF_ISP_CAC_CTRL_V_CLIP_MODE GENMASK(2, 1)
> +#define RKISP1_CIF_ISP_CAC_CTRL_H_CLIP_MODE GENMASK(3, 3)
> +#define RKISP1_CIF_ISP_CAC_COUNT_START_H_MASK GENMASK(12, 0)
> +#define RKISP1_CIF_ISP_CAC_COUNT_START_V_MASK GENMASK(28, 16)
> +#define RKISP1_CIF_ISP_CAC_A_RED_MASK GENMASK(8, 0)
> +#define RKISP1_CIF_ISP_CAC_A_BLUE_MASK GENMASK(24, 16)
> +#define RKISP1_CIF_ISP_CAC_B_RED_MASK GENMASK(8, 0)
> +#define RKISP1_CIF_ISP_CAC_B_BLUE_MASK GENMASK(24, 16)
> +#define RKISP1_CIF_ISP_CAC_C_RED_MASK GENMASK(8, 0)
> +#define RKISP1_CIF_ISP_CAC_C_BLUE_MASK GENMASK(24, 16)
All these masks for coefficients 0, 1 and 2 are identical. Maybe
#define RKISP1_CIF_ISP_CAC_RED_MASK GENMASK(8, 0)
#define RKISP1_CIF_ISP_CAC_BLUE_MASK GENMASK(24, 16)
is enough
> +#define RKISP1_CIF_ISP_CAC_X_NORM_NF_MASK GENMASK(4, 0)
> +#define RKISP1_CIF_ISP_CAC_X_NORM_NS_MASK GENMASK(19, 16)
> +#define RKISP1_CIF_ISP_CAC_Y_NORM_NF_MASK GENMASK(4, 0)
> +#define RKISP1_CIF_ISP_CAC_Y_NORM_NS_MASK GENMASK(19, 16)
> +
> /* =================================================================== */
> /* CIF Registers */
> /* =================================================================== */
> @@ -1196,8 +1213,8 @@
> #define RKISP1_CIF_ISP_CAC_A (RKISP1_CIF_ISP_CAC_BASE + 0x00000008)
> #define RKISP1_CIF_ISP_CAC_B (RKISP1_CIF_ISP_CAC_BASE + 0x0000000c)
> #define RKISP1_CIF_ISP_CAC_C (RKISP1_CIF_ISP_CAC_BASE + 0x00000010)
> -#define RKISP1_CIF_ISP_X_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000014)
> -#define RKISP1_CIF_ISP_Y_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000018)
> +#define RKISP1_CIF_ISP_CAC_X_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000014)
> +#define RKISP1_CIF_ISP_CAC_Y_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000018)
>
> #define RKISP1_CIF_ISP_EXP_BASE 0x00002600
> #define RKISP1_CIF_ISP_EXP_CTRL (RKISP1_CIF_ISP_EXP_BASE + 0x00000000)
> diff --git a/include/uapi/linux/rkisp1-config.h b/include/uapi/linux/rkisp1-config.h
> index b2d2a71f7baff..d8acccaddd0e9 100644
> --- a/include/uapi/linux/rkisp1-config.h
> +++ b/include/uapi/linux/rkisp1-config.h
> @@ -967,6 +967,92 @@ struct rkisp1_cif_isp_wdr_config {
> __u8 use_iref;
> };
>
> +/*
> + * enum rkisp1_cif_isp_cac_h_clip_mode - horizontal clipping mode
> + *
> + * @RKISP1_CIF_ISP_CAC_H_CLIP_MODE_4PX: +/- 4 pixels
> + * @RKISP1_CIF_ISP_CAC_H_CLIP_MODE_4_5PX: +/- 4/5 pixels depending on bayer position
> + */
> +enum rkisp1_cif_isp_cac_h_clip_mode {
> + RKISP1_CIF_ISP_CAC_H_CLIP_MODE_4PX = 0,
> + RKISP1_CIF_ISP_CAC_H_CLIP_MODE_4_5PX = 1,
> +};
> +
> +/**
> + * enum rkisp1_cif_isp_cac_v_clip_mode - vertical clipping mode
> + *
> + * @RKISP1_CIF_ISP_CAC_V_CLIP_MODE_2PX: +/- 2 pixels
> + * @RKISP1_CIF_ISP_CAC_V_CLIP_MODE_3PX: +/- 3 pixels
> + * @RKISP1_CIF_ISP_CAC_V_CLIP_MODE_3_4PX: +/- 3/4 pixels depending on bayer position
> + */
> +enum rkisp1_cif_isp_cac_v_clip_mode {
> + RKISP1_CIF_ISP_CAC_V_CLIP_MODE_2PX = 0,
> + RKISP1_CIF_ISP_CAC_V_CLIP_MODE_3PX = 1,
> + RKISP1_CIF_ISP_CAC_V_CLIP_MODE_3_4PX = 2,
> +};
> +
> +/**
> + * struct rkisp1_cif_isp_cac_config - chromatic aberration correction configuration
> + *
> + * The correction is carried out by shifting the red and blue pixels relative
> + * to the green ones, depending on the distance from the optical center:
Yes, the distance to the center is one parameter, but the shifting
amount depends on other things. I would drop the last part of the
sentence and move the description of the two below fields after the
text
> + *
> + * @h_count_start: horizontal coordinate of the optical center (13-bit unsigned integer; [1,8191])
> + * @v_count_start: vertical coordinate of the optical center (13-bit unsigned integer; [1,8191])
so these could go just before @x_nf
> + *
> + * For each pixel, the x/y distances from the optical center are calculated and
I forgot: did we establish that the correction is applied to the
euclidean distance or to x and y separately ?
> + * then transformed into the [0,255] range based on the following formula:
s/transformed/normalized ?
> + *
> + * (((d << 4) >> s) * f) >> 5
> + *
> + * where `d` is the distance, `s` and `f` are the normalization parameters:
Can you use 'ns' and 'nf' to match the below ?
> + *
> + * @x_nf: horizontal normalization scale parameter (5-bit unsigned integer; [0,31])
> + * @x_ns: horizontal normalization shift parameter (4-bit unsigned integer; [0,15])
> + *
> + * @y_nf: vertical normalization scale parameter (5-bit unsigned integer; [0,31])
> + * @y_ns: vertical normalization shift parameter (4-bit unsigned integer; [0,15])
> + *
> + * These parameters should be chosen based on the image resolution, the position
> + * of the optical center, and the shape of pixels: so that no normalized distance
s/pixels:/pixels/
> + * is larger than 255. If the pixels have square shape, the two sets of parameters
> + * should be equal.
> + *
> + * The actual amount of correction is calculated with a third degree polynomial:
> + *
> + * c[0] * r + c[1] * r^2 + c[2] * r^3
> + *
> + * where `c` is the set of coefficients for the given color, and `r` is distance:
> + *
> + * @red: red coefficients (5.4 two's complement; [-16,15.9375])
> + * @blue: blue coefficients (5.4 two's complement; [-16,15.9375])
> + *
> + * Finally, the amount is clipped as requested:
> + *
> + * @h_clip_mode: maximum horizontal shift (from enum rkisp1_cif_isp_cac_h_clip_mode)
> + * @v_clip_mode: maximum vertical shift (from enum rkisp1_cif_isp_cac_v_clip_mode)
> + *
> + * A positive result will shift away from the optical center, while a negative
> + * one will shift towards the optical center. In the latter case, the pixel
> + * values at the edges are duplicated.
> + */
> +struct rkisp1_cif_isp_cac_config {
> + __u8 h_clip_mode;
> + __u8 v_clip_mode;
> +
> + __u16 h_count_start;
> + __u16 v_count_start;
> +
> + __u16 red[3];
> + __u16 blue[3];
> +
> + __u8 x_nf;
> + __u8 x_ns;
> +
> + __u8 y_nf;
> + __u8 y_ns;
> +};
> +
> /*---------- PART2: Measurement Statistics ------------*/
>
> /**
> @@ -1161,6 +1247,7 @@ enum rkisp1_ext_params_block_type {
> RKISP1_EXT_PARAMS_BLOCK_TYPE_COMPAND_EXPAND,
> RKISP1_EXT_PARAMS_BLOCK_TYPE_COMPAND_COMPRESS,
> RKISP1_EXT_PARAMS_BLOCK_TYPE_WDR,
> + RKISP1_EXT_PARAMS_BLOCK_TYPE_CAC,
> };
>
> /* For backward compatibility */
> @@ -1507,6 +1594,22 @@ struct rkisp1_ext_params_wdr_config {
> struct rkisp1_cif_isp_wdr_config config;
> } __attribute__((aligned(8)));
>
> +/**
> + * struct rkisp1_ext_params_cac_config - RkISP1 extensible params CAC config
> + *
> + * RkISP1 extensible parameters CAC block.
> + * Identified by :c:type:`RKISP1_EXT_PARAMS_BLOCK_TYPE_CAC`.
> + *
> + * @header: The RkISP1 extensible parameters header, see
> + * :c:type:`rkisp1_ext_params_block_header`
> + * @config: CAC configuration, see
> + * :c:type:`rkisp1_cif_isp_cac_config`
> + */
> +struct rkisp1_ext_params_cac_config {
> + struct rkisp1_ext_params_block_header header;
> + struct rkisp1_cif_isp_cac_config config;
> +} __attribute__((aligned(8)));
> +
> /*
> * The rkisp1_ext_params_compand_curve_config structure is counted twice as it
> * is used for both the COMPAND_EXPAND and COMPAND_COMPRESS block types.
> @@ -1532,7 +1635,8 @@ struct rkisp1_ext_params_wdr_config {
> sizeof(struct rkisp1_ext_params_compand_bls_config) +\
> sizeof(struct rkisp1_ext_params_compand_curve_config) +\
> sizeof(struct rkisp1_ext_params_compand_curve_config) +\
> - sizeof(struct rkisp1_ext_params_wdr_config))
> + sizeof(struct rkisp1_ext_params_wdr_config) +\
> + sizeof(struct rkisp1_ext_params_cac_config))
All minors, please add
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Thanks
j
>
> /**
> * enum rksip1_ext_param_buffer_version - RkISP1 extensible parameters version
> --
> 2.53.0
>
>
^ permalink raw reply
* [PATCH v5 00/12] scsi: ufs: Add TX Equalization support for UFS 5.0
From: Can Guo @ 2026-03-25 15:21 UTC (permalink / raw)
To: avri.altman, bvanassche, beanhuo, peter.wang, martin.petersen,
mani
Cc: linux-scsi, Can Guo, Matthias Brugger, AngeloGioacchino Del Regno,
open list:ARM/Mediatek SoC support:Keyword:mediatek,
moderated list:ARM/Mediatek SoC support:Keyword:mediatek,
moderated list:ARM/Mediatek SoC support:Keyword:mediatek
Hi,
The UFS v5.0 and UFSHCI v5.0 standards have published, introducing support
for HS-G6 (46.6 Gbps per lane) through the new UniPro V3.0 interconnect
layer and M-PHY V6.0 physical layer specifications. To achieve reliable
operation at these higher speeds, UniPro V3.0 introduces TX Equalization
and Pre-Coding mechanisms that are essential for signal integrity.
This patch series implements TX Equalization support in the UFS core
driver as specified in UFSHCI v5.0, along with the necessary vendor
operations and a reference implementation for Qualcomm UFS host
controllers.
Background
==========
TX Equalization is a signal conditioning technique that compensates for
channel impairments at high data rates (HS-G4 through HS-G6). It works
by adjusting two key parameters:
- PreShoot: Pre-emphasis applied before the main signal transition
- DeEmphasis: De-emphasis applied after the main signal transition
UniPro V3.0 defines TX Equalization Training (EQTR) procedure to
automatically discover optimal TX Equalization settings. The EQTR
procedure:
1. Starts from the most reliable link state (HS-G1)
2. Iterates through all possible PreShoot and DeEmphasis combinations
3. Evaluates signal quality using Figure of Merit (FOM) measurements
4. Selects the best settings for both host and device TX lanes
For HS-G6, Pre-Coding is also introduced to further improve signal
quality. Pre-Coding must be enabled on both transmitter and receiver
when the RX_FOM indicates it is required.
Implementation Overview
=======================
The implementation follows the UFSHCI v5.0 specification and consists of:
Core Infrastructure (Patches 1-6):
- New vops callback negotiate_pwr_mode() to allow vendors to negotiate
power mode parameters before applying TX Equalization settings
- Support for HS-G6 gear enumeration
- Complete TX EQTR procedure implementation in ufs-txeq.c
- Debugfs interface for TX Equalization parameter inspection and manual
retraining
- Module parameters for adaptive TX Equalization control
Qualcomm Implementation (Patches 7-11):
- PHY-specific configurations for TX EQTR procedure
- Vendor-specific FOM measurement support
- TX Equalization settings application
- Enable TX Equalization for HW version 0x7 and onwards
The implementation is designed to be vendor-agnostic, with platform-
specific details handled through the vops callbacks. Other vendors can
add support by implementing the three new vops:
- tx_eqtr_notify(): Called before/after TX EQTR for vendor setup
- apply_tx_eqtr_settings(): Apply vendor-specific PHY configurations
- get_rx_fom(): Retrieve vendor-specific FOM measurements if needed
Module Parameters
=================
The implementation provides several module parameters for flexibility:
- use_adaptive_txeq: Enable/disable adaptive TX Equalization (default: false)
- adaptive_txeq_gear: Minimum gear for adaptive TX EQ (default: HS-G6)
- use_txeq_presets: Use only the 8 standaird presets (default: false)
- txeq_presets_selected[]: Select specific presets for EQTR
Testing
=======
This patch series has been tested on Qualcomm platforms with UFS 5.0
devices, validating:
- Successful TX EQTR completion for HS-G6
- Proper FOM evaluation and optimal settings selection
- Pre-Coding enablement for HS-G6
- Power mode changes with TX Equalization settings applied
- Report of TX Equalization settings via debugfs entries
- Report of TX EQTR histories via debug entries (see next section)
- Re-training TX Equalization via debugfs entry
Example of TX EQTR history
==========================
# cat /sys/kernel/debug/ufshcd/*ufshcd*/tx_eq_hs_gear6/device_tx_eqtr_record
Device TX EQTR record summary -
Target Power Mode: HS-G6, Rate-B
Most recent record index: 2
Most recent record timestamp: 219573378 us
TX Lane 0 FOM - PreShoot\DeEmphasis
\ 0 1 2 3 4 5 6 7
0 50 70 65 - - - - x
1 x x x x x x x x
2 100 90 70 - - - - x
3 x x x x x x x x
4 95 90 - - - - - x
5 - - - - - - - x
6 x x x x x x x x
7 x x x x x x x x
TX Lane 1 FOM - PreShoot\DeEmphasis
\ 0 1 2 3 4 5 6 7
0 50 70 60 - - - - x
1 x x x x x x x x
2 100 80 65 - - - - x
3 x x x x x x x x
4 95 85 - - - - - x
5 - - - - - - - x
6 x x x x x x x x
7 x x x x x x x x
Patch Structure
===============
Patches 1-3: Preparatory changes for power mode negotiation and HS-G6
Patch 4: Core TX Equalization and EQTR implementation
Patches 5-7: Debugfs support for TX Equalization
Patches 8-12: Qualcomm vendor implementation
Next
====
One more series has been developed to enhance TX Equalization support,
which will be submitted for review after this series is accepted:
- Provide board specific (static) TX Equalization settings from DTS
- Parse static TX Equalization settings from DTS if provided
- Apply static TX Equalization settings if use_adaptive_txeq is disabled
- Add support for UFS v5.0 attributes qTxEQGnSettings & wTxEQGnSettingsExt
- Enable persistent storage and retrieval of optimal TX Equalization settings
v4 -> v5:
1. Addressed comments from Bean in patch 7, returned -EINVAL when
negotiated gear != requested gear in function ufshcd_retrain_tx_eq().
2. Addressed comments from Peter in patch 4, moved usage of
&hba->tx_eq_params[gear - 1] after checks on gear and improved the
checks on gear in function ufshcd_config_tx_eq_settings().
v3 -> v4:
1. Incorporated comments from Bart and Peter.
2. In patch 1, removed redundant checks on dev_req_params
3. In patch 1, moved error prints out of vops negotiate_pwr_mode()
4. In patch 1, removed vops implemenation ufs_versal2_negotiate_pwr_mode(),
sprd_ufs_negotiate_pwr_mode() and ufs_intel_lkf_negotiate_pwr_mode() as
they are simply doing memcpy().
5. In patch 3, initialize UFS_HS_GEAR_MAX as UFS_HS_G6.
6. In patch 4, adjusted places where UFS_HS_GEAR_MAX is used.
7. In patch 4, defined inline func ufs_hs_rate_to_str() instead of macro.
8. In patch 4, changed default value of use_txeq_presets to 'false'.
8. In patch 4, optimized ufshcd_tx_eq_params and ufshcd_tx_eq_settings.
9. In patch 4, optimized memory usage of ufshcd_tx_eq_params.
10. In patch 5, updated places which use fields in ufshcd_tx_eq_params.
11. In patch 7, used 'retrain' instead of 'refresh'.
12. In patch 10, introduced a few macros.
v2 -> v3:
1. Incorporated comments from Bart, Bean and Mani.
2. In patch 4, made ufshcd_config_pwr_mode() ignore TX EQTR error.
3. Added patch 6 to introduce helpers to pause/resume command processing.
4. In patch 7, changed debugfs entry to 'tx_eq_ctrl' and used 'refresh'
as input to trigger TX Equalization refreshing.
5. In patch 7, renamed ufshcd_retrain_tx_eq() to ufshcd_refresh_tx_eq().
6. Fixed typos and coding style issues.
v1 -> v2:
1. Incorporated Bart's comments.
2. Fixed typos and coding style issues.
3. Added enum ufshcd_pmc_policy and use enum instead of boolen parameter.
4. Updated TX Equalization debugfs entries structure.
5. Extracted ufshcd_pause/resume_command_processing() in ufshcd.c.
6. Updated sequence in Qualcomm's vops get_rx_fom() implementation.
Can Guo (12):
scsi: ufs: core: Introduce a new ufshcd vops negotiate_pwr_mode()
scsi: ufs: core: Pass force_pmc to ufshcd_config_pwr_mode() as a
parameter
scsi: ufs: core: Add UFS_HS_G6 and UFS_HS_GEAR_MAX to enum
ufs_hs_gear_tag
scsi: ufs: core: Add support for TX Equalization
scsi: ufs: core: Add debugfs entries for TX Equalization params
scsi: ufs: core: Add helpers to pause and resume command processing
scsi: ufs: core: Add support to retrain TX Equalization via debugfs
scsi: ufs: ufs-qcom: Fixup PAM-4 TX L0_L1_L2_L3 adaptation pattern
length
scsi: ufs: ufs-qcom: Implement vops tx_eqtr_notify()
scsi: ufs: ufs-qcom: Implement vops get_rx_fom()
scsi: ufs: ufs-qcom: Implement vops apply_tx_eqtr_settings()
scsi: ufs: ufs-qcom: Enable TX Equalization
drivers/ufs/core/Makefile | 2 +-
drivers/ufs/core/ufs-debugfs.c | 290 +++++++
drivers/ufs/core/ufs-txeq.c | 1293 ++++++++++++++++++++++++++++
drivers/ufs/core/ufshcd-priv.h | 59 +-
drivers/ufs/core/ufshcd.c | 192 ++++-
drivers/ufs/host/ufs-amd-versal2.c | 3 -
drivers/ufs/host/ufs-exynos.c | 34 +-
drivers/ufs/host/ufs-hisi.c | 23 +-
drivers/ufs/host/ufs-mediatek.c | 40 +-
drivers/ufs/host/ufs-qcom.c | 591 ++++++++++++-
drivers/ufs/host/ufs-qcom.h | 42 +
drivers/ufs/host/ufs-sprd.c | 3 -
drivers/ufs/host/ufshcd-pci.c | 7 +-
include/ufs/ufshcd.h | 174 +++-
include/ufs/unipro.h | 141 ++-
15 files changed, 2779 insertions(+), 115 deletions(-)
create mode 100644 drivers/ufs/core/ufs-txeq.c
--
2.34.1
^ permalink raw reply
* [PATCH v5 01/12] scsi: ufs: core: Introduce a new ufshcd vops negotiate_pwr_mode()
From: Can Guo @ 2026-03-25 15:21 UTC (permalink / raw)
To: avri.altman, bvanassche, beanhuo, peter.wang, martin.petersen,
mani
Cc: linux-scsi, Can Guo, Alim Akhtar, James E.J. Bottomley,
Sai Krishna Potthuri, Ajay Neeli, Peter Griffin,
Krzysztof Kozlowski, Chaotian Jing, Stanley Jhu, Orson Zhai,
Baolin Wang, Chunyan Zhang, Matthias Brugger,
AngeloGioacchino Del Regno, Bao D. Nguyen, Adrian Hunter,
Archana Patni, open list,
open list:UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER...,
moderated list:ARM/SAMSUNG S3C, S5P AND EXYNOS ARM ARCHITECTURES,
moderated list:UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER...,
open list:UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER...
In-Reply-To: <20260325152154.1604082-1-can.guo@oss.qualcomm.com>
Most vendor specific implemenations of vops pwr_change_notify(PRE_CHANGE)
are fulfilling two things at once:
- Vendor specific target power mode negotiation
- Vendor specific power mode change preparation
When TX Equalization is added into consideration, before power mode change
to a target power mode, TX Equalization Training (EQTR) needs be done for
that target power mode. In addition, UFSHCI spec requires to start TX EQTR
from HS-G1 (the most reliable High Speed Gear).
Adding TX EQTR before pwr_change_notify(PRE_CHANGE) is not applicable
because we don't know the negotiated power mode yet.
Adding TX EQTR post pwr_change_notify(PRE_CHANGE) is inappropriate
because pwr_change_notify(PRE_CHANGE) has finished preparation for a power
mode change to negotiated power mode, yet we are changing power mode to
HS-G1 for TX EQTR.
Add a new vops negotiate_pwr_mode() so that vendor specific power mode
negotiation can be fulfilled in its vendor specific implementations.
Later on, TX EQTR can be added post vops negotiate_pwr_mode() and before
vops pwr_change_notify(PRE_CHANGE).
Reviewed-by: Bean Huo <beanhuo@micron.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Can Guo <can.guo@oss.qualcomm.com>
---
drivers/ufs/core/ufshcd-priv.h | 14 +++++-
drivers/ufs/core/ufshcd.c | 70 ++++++++++++++++++++++++------
drivers/ufs/host/ufs-amd-versal2.c | 3 --
drivers/ufs/host/ufs-exynos.c | 34 +++++++--------
drivers/ufs/host/ufs-hisi.c | 23 +++++-----
drivers/ufs/host/ufs-mediatek.c | 40 ++++++++---------
drivers/ufs/host/ufs-qcom.c | 24 +++++-----
drivers/ufs/host/ufs-sprd.c | 3 --
drivers/ufs/host/ufshcd-pci.c | 6 +--
include/ufs/ufshcd.h | 17 +++++---
10 files changed, 143 insertions(+), 91 deletions(-)
diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h
index 7d6d19361af9..3b6958d9297a 100644
--- a/drivers/ufs/core/ufshcd-priv.h
+++ b/drivers/ufs/core/ufshcd-priv.h
@@ -167,14 +167,24 @@ static inline int ufshcd_vops_link_startup_notify(struct ufs_hba *hba,
return 0;
}
+static inline int ufshcd_vops_negotiate_pwr_mode(struct ufs_hba *hba,
+ const struct ufs_pa_layer_attr *dev_max_params,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ if (hba->vops && hba->vops->negotiate_pwr_mode)
+ return hba->vops->negotiate_pwr_mode(hba, dev_max_params,
+ dev_req_params);
+
+ return -ENOTSUPP;
+}
+
static inline int ufshcd_vops_pwr_change_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status,
- const struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
if (hba->vops && hba->vops->pwr_change_notify)
return hba->vops->pwr_change_notify(hba, status,
- dev_max_params, dev_req_params);
+ dev_req_params);
return -ENOTSUPP;
}
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 8349fe2090db..91b5d5b02d22 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -335,8 +335,6 @@ static void ufshcd_suspend_clkscaling(struct ufs_hba *hba);
static int ufshcd_scale_clks(struct ufs_hba *hba, unsigned long freq,
bool scale_up);
static irqreturn_t ufshcd_intr(int irq, void *__hba);
-static int ufshcd_change_power_mode(struct ufs_hba *hba,
- struct ufs_pa_layer_attr *pwr_mode);
static int ufshcd_setup_hba_vreg(struct ufs_hba *hba, bool on);
static int ufshcd_setup_vreg(struct ufs_hba *hba, bool on);
static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
@@ -4662,8 +4660,26 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
return 0;
}
-static int ufshcd_change_power_mode(struct ufs_hba *hba,
- struct ufs_pa_layer_attr *pwr_mode)
+/**
+ * ufshcd_dme_change_power_mode() - UniPro DME Power Mode change sequence
+ * @hba: per-adapter instance
+ * @pwr_mode: pointer to the target power mode (gear/lane) attributes
+ *
+ * This function handles the low-level DME (Device Management Entity)
+ * configuration required to transition the UFS link to a new power mode. It
+ * performs the following steps:
+ * 1. Checks if the requested mode matches the current state.
+ * 2. Sets M-PHY and UniPro attributes including Gear (PA_RXGEAR/TXGEAR),
+ * Lanes, Termination, and HS Series (PA_HSSERIES).
+ * 3. Configures default UniPro timeout values (DL_FC0, etc.) unless
+ * explicitly skipped via quirks.
+ * 4. Triggers the actual hardware mode change via ufshcd_uic_change_pwr_mode().
+ * 5. Updates the HBA's cached power information on success.
+ *
+ * Return: 0 on success, non-zero error code on failure.
+ */
+static int ufshcd_dme_change_power_mode(struct ufs_hba *hba,
+ struct ufs_pa_layer_attr *pwr_mode)
{
int ret;
@@ -4747,6 +4763,34 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba,
return ret;
}
+/**
+ * ufshcd_change_power_mode() - Change UFS Link Power Mode
+ * @hba: per-adapter instance
+ * @pwr_mode: pointer to the target power mode (gear/lane) attributes
+ *
+ * This function handles the high-level sequence for changing the UFS link
+ * power mode. It triggers vendor-specific pre-change notification,
+ * executes the DME (Device Management Entity) power mode change sequence,
+ * and, upon success, triggers vendor-specific post-change notification.
+ *
+ * Return: 0 on success, non-zero error code on failure.
+ */
+int ufshcd_change_power_mode(struct ufs_hba *hba,
+ struct ufs_pa_layer_attr *pwr_mode)
+{
+ int ret;
+
+ ufshcd_vops_pwr_change_notify(hba, PRE_CHANGE, pwr_mode);
+
+ ret = ufshcd_dme_change_power_mode(hba, pwr_mode);
+
+ if (!ret)
+ ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, pwr_mode);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_change_power_mode);
+
/**
* ufshcd_config_pwr_mode - configure a new power mode
* @hba: per-adapter instance
@@ -4760,19 +4804,17 @@ int ufshcd_config_pwr_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr final_params = { 0 };
int ret;
- ret = ufshcd_vops_pwr_change_notify(hba, PRE_CHANGE,
- desired_pwr_mode, &final_params);
+ ret = ufshcd_vops_negotiate_pwr_mode(hba, desired_pwr_mode,
+ &final_params);
+ if (ret) {
+ if (ret != -ENOTSUPP)
+ dev_err(hba->dev, "Failed to negotiate power mode: %d, use desired as is\n",
+ ret);
- if (ret)
memcpy(&final_params, desired_pwr_mode, sizeof(final_params));
+ }
- ret = ufshcd_change_power_mode(hba, &final_params);
-
- if (!ret)
- ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL,
- &final_params);
-
- return ret;
+ return ufshcd_change_power_mode(hba, &final_params);
}
EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode);
diff --git a/drivers/ufs/host/ufs-amd-versal2.c b/drivers/ufs/host/ufs-amd-versal2.c
index 40543db621a1..52031b7256fd 100644
--- a/drivers/ufs/host/ufs-amd-versal2.c
+++ b/drivers/ufs/host/ufs-amd-versal2.c
@@ -443,7 +443,6 @@ static int ufs_versal2_phy_ratesel(struct ufs_hba *hba, u32 activelanes, u32 rx_
}
static int ufs_versal2_pwr_change_notify(struct ufs_hba *hba, enum ufs_notify_change_status status,
- const struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
struct ufs_versal2_host *host = ufshcd_get_variant(hba);
@@ -451,8 +450,6 @@ static int ufs_versal2_pwr_change_notify(struct ufs_hba *hba, enum ufs_notify_ch
int ret = 0;
if (status == PRE_CHANGE) {
- memcpy(dev_req_params, dev_max_params, sizeof(struct ufs_pa_layer_attr));
-
/* If it is not a calibrated part, switch PWRMODE to SLOW_MODE */
if (!host->attcompval0 && !host->attcompval1 && !host->ctlecompval0 &&
!host->ctlecompval1) {
diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c
index 76fee3a79c77..77a6c8e44485 100644
--- a/drivers/ufs/host/ufs-exynos.c
+++ b/drivers/ufs/host/ufs-exynos.c
@@ -818,12 +818,10 @@ static u32 exynos_ufs_get_hs_gear(struct ufs_hba *hba)
}
static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba,
- const struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
struct phy *generic_phy = ufs->phy;
- struct ufs_host_params host_params;
int ret;
if (!dev_req_params) {
@@ -832,18 +830,6 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba,
goto out;
}
- ufshcd_init_host_params(&host_params);
-
- /* This driver only support symmetric gear setting e.g. hs_tx_gear == hs_rx_gear */
- host_params.hs_tx_gear = exynos_ufs_get_hs_gear(hba);
- host_params.hs_rx_gear = exynos_ufs_get_hs_gear(hba);
-
- ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
- if (ret) {
- pr_err("%s: failed to determine capabilities\n", __func__);
- goto out;
- }
-
if (ufs->drv_data->pre_pwr_change)
ufs->drv_data->pre_pwr_change(ufs, dev_req_params);
@@ -1677,17 +1663,30 @@ static int exynos_ufs_link_startup_notify(struct ufs_hba *hba,
return ret;
}
+static int exynos_ufs_negotiate_pwr_mode(struct ufs_hba *hba,
+ const struct ufs_pa_layer_attr *dev_max_params,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ struct ufs_host_params host_params;
+
+ ufshcd_init_host_params(&host_params);
+
+ /* This driver only support symmetric gear setting e.g. hs_tx_gear == hs_rx_gear */
+ host_params.hs_tx_gear = exynos_ufs_get_hs_gear(hba);
+ host_params.hs_rx_gear = exynos_ufs_get_hs_gear(hba);
+
+ return ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
+}
+
static int exynos_ufs_pwr_change_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status,
- const struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
int ret = 0;
switch (status) {
case PRE_CHANGE:
- ret = exynos_ufs_pre_pwr_mode(hba, dev_max_params,
- dev_req_params);
+ ret = exynos_ufs_pre_pwr_mode(hba, dev_req_params);
break;
case POST_CHANGE:
ret = exynos_ufs_post_pwr_mode(hba, dev_req_params);
@@ -2015,6 +2014,7 @@ static const struct ufs_hba_variant_ops ufs_hba_exynos_ops = {
.exit = exynos_ufs_exit,
.hce_enable_notify = exynos_ufs_hce_enable_notify,
.link_startup_notify = exynos_ufs_link_startup_notify,
+ .negotiate_pwr_mode = exynos_ufs_negotiate_pwr_mode,
.pwr_change_notify = exynos_ufs_pwr_change_notify,
.setup_clocks = exynos_ufs_setup_clocks,
.setup_xfer_req = exynos_ufs_specify_nexus_t_xfer_req,
diff --git a/drivers/ufs/host/ufs-hisi.c b/drivers/ufs/host/ufs-hisi.c
index 6f2e6bf31225..993e20ac211d 100644
--- a/drivers/ufs/host/ufs-hisi.c
+++ b/drivers/ufs/host/ufs-hisi.c
@@ -298,6 +298,17 @@ static void ufs_hisi_set_dev_cap(struct ufs_host_params *host_params)
ufshcd_init_host_params(host_params);
}
+static int ufs_hisi_negotiate_pwr_mode(struct ufs_hba *hba,
+ const struct ufs_pa_layer_attr *dev_max_params,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ struct ufs_host_params host_params;
+
+ ufs_hisi_set_dev_cap(&host_params);
+
+ return ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
+}
+
static void ufs_hisi_pwr_change_pre_change(struct ufs_hba *hba)
{
struct ufs_hisi_host *host = ufshcd_get_variant(hba);
@@ -362,10 +373,8 @@ static void ufs_hisi_pwr_change_pre_change(struct ufs_hba *hba)
static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status,
- const struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
- struct ufs_host_params host_params;
int ret = 0;
if (!dev_req_params) {
@@ -377,14 +386,6 @@ static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba,
switch (status) {
case PRE_CHANGE:
- ufs_hisi_set_dev_cap(&host_params);
- ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
- if (ret) {
- dev_err(hba->dev,
- "%s: failed to determine capabilities\n", __func__);
- goto out;
- }
-
ufs_hisi_pwr_change_pre_change(hba);
break;
case POST_CHANGE:
@@ -543,6 +544,7 @@ static const struct ufs_hba_variant_ops ufs_hba_hi3660_vops = {
.name = "hi3660",
.init = ufs_hi3660_init,
.link_startup_notify = ufs_hisi_link_startup_notify,
+ .negotiate_pwr_mode = ufs_hisi_negotiate_pwr_mode,
.pwr_change_notify = ufs_hisi_pwr_change_notify,
.suspend = ufs_hisi_suspend,
.resume = ufs_hisi_resume,
@@ -552,6 +554,7 @@ static const struct ufs_hba_variant_ops ufs_hba_hi3670_vops = {
.name = "hi3670",
.init = ufs_hi3670_init,
.link_startup_notify = ufs_hisi_link_startup_notify,
+ .negotiate_pwr_mode = ufs_hisi_negotiate_pwr_mode,
.pwr_change_notify = ufs_hisi_pwr_change_notify,
.suspend = ufs_hisi_suspend,
.resume = ufs_hisi_resume,
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 05892b9ac528..7b45cf0428af 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -1317,6 +1317,23 @@ static int ufs_mtk_init(struct ufs_hba *hba)
return err;
}
+static int ufs_mtk_negotiate_pwr_mode(struct ufs_hba *hba,
+ const struct ufs_pa_layer_attr *dev_max_params,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ struct ufs_host_params host_params;
+
+ ufshcd_init_host_params(&host_params);
+ host_params.hs_rx_gear = UFS_HS_G5;
+ host_params.hs_tx_gear = UFS_HS_G5;
+
+ if (dev_max_params->pwr_rx == SLOW_MODE ||
+ dev_max_params->pwr_tx == SLOW_MODE)
+ host_params.desired_working_mode = UFS_PWM_MODE;
+
+ return ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
+}
+
static bool ufs_mtk_pmc_via_fastauto(struct ufs_hba *hba,
struct ufs_pa_layer_attr *dev_req_params)
{
@@ -1372,26 +1389,10 @@ static void ufs_mtk_adjust_sync_length(struct ufs_hba *hba)
}
static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
- const struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
- struct ufs_host_params host_params;
- int ret;
-
- ufshcd_init_host_params(&host_params);
- host_params.hs_rx_gear = UFS_HS_G5;
- host_params.hs_tx_gear = UFS_HS_G5;
-
- if (dev_max_params->pwr_rx == SLOW_MODE ||
- dev_max_params->pwr_tx == SLOW_MODE)
- host_params.desired_working_mode = UFS_PWM_MODE;
-
- ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
- if (ret) {
- pr_info("%s: failed to determine capabilities\n",
- __func__);
- }
+ int ret = 0;
if (ufs_mtk_pmc_via_fastauto(hba, dev_req_params)) {
ufs_mtk_adjust_sync_length(hba);
@@ -1503,7 +1504,6 @@ static int ufs_mtk_auto_hibern8_disable(struct ufs_hba *hba)
static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba,
enum ufs_notify_change_status stage,
- const struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
int ret = 0;
@@ -1515,8 +1515,7 @@ static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba,
reg = ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER);
ufs_mtk_auto_hibern8_disable(hba);
}
- ret = ufs_mtk_pre_pwr_change(hba, dev_max_params,
- dev_req_params);
+ ret = ufs_mtk_pre_pwr_change(hba, dev_req_params);
break;
case POST_CHANGE:
if (ufshcd_is_auto_hibern8_supported(hba))
@@ -2318,6 +2317,7 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = {
.setup_clocks = ufs_mtk_setup_clocks,
.hce_enable_notify = ufs_mtk_hce_enable_notify,
.link_startup_notify = ufs_mtk_link_startup_notify,
+ .negotiate_pwr_mode = ufs_mtk_negotiate_pwr_mode,
.pwr_change_notify = ufs_mtk_pwr_change_notify,
.apply_dev_quirks = ufs_mtk_apply_dev_quirks,
.fixup_dev_quirks = ufs_mtk_fixup_dev_quirks,
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 375fd24ba458..cdc769886e82 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -966,13 +966,21 @@ static void ufs_qcom_set_tx_hs_equalizer(struct ufs_hba *hba, u32 gear, u32 tx_l
}
}
-static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
- enum ufs_notify_change_status status,
- const struct ufs_pa_layer_attr *dev_max_params,
- struct ufs_pa_layer_attr *dev_req_params)
+static int ufs_qcom_negotiate_pwr_mode(struct ufs_hba *hba,
+ const struct ufs_pa_layer_attr *dev_max_params,
+ struct ufs_pa_layer_attr *dev_req_params)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct ufs_host_params *host_params = &host->host_params;
+
+ return ufshcd_negotiate_pwr_params(host_params, dev_max_params, dev_req_params);
+}
+
+static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status status,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
int ret = 0;
if (!dev_req_params) {
@@ -982,13 +990,6 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
switch (status) {
case PRE_CHANGE:
- ret = ufshcd_negotiate_pwr_params(host_params, dev_max_params, dev_req_params);
- if (ret) {
- dev_err(hba->dev, "%s: failed to determine capabilities\n",
- __func__);
- return ret;
- }
-
/*
* During UFS driver probe, always update the PHY gear to match the negotiated
* gear, so that, if quirk UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH is enabled,
@@ -2341,6 +2342,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
.setup_clocks = ufs_qcom_setup_clocks,
.hce_enable_notify = ufs_qcom_hce_enable_notify,
.link_startup_notify = ufs_qcom_link_startup_notify,
+ .negotiate_pwr_mode = ufs_qcom_negotiate_pwr_mode,
.pwr_change_notify = ufs_qcom_pwr_change_notify,
.apply_dev_quirks = ufs_qcom_apply_dev_quirks,
.fixup_dev_quirks = ufs_qcom_fixup_dev_quirks,
diff --git a/drivers/ufs/host/ufs-sprd.c b/drivers/ufs/host/ufs-sprd.c
index 65bd8fb96b99..a5e8c591bead 100644
--- a/drivers/ufs/host/ufs-sprd.c
+++ b/drivers/ufs/host/ufs-sprd.c
@@ -161,14 +161,11 @@ static int ufs_sprd_common_init(struct ufs_hba *hba)
static int sprd_ufs_pwr_change_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status,
- const struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
struct ufs_sprd_host *host = ufshcd_get_variant(hba);
if (status == PRE_CHANGE) {
- memcpy(dev_req_params, dev_max_params,
- sizeof(struct ufs_pa_layer_attr));
if (host->unipro_ver >= UFS_UNIPRO_VER_1_8)
ufshcd_dme_configure_adapt(hba, dev_req_params->gear_tx,
PA_INITIAL_ADAPT);
diff --git a/drivers/ufs/host/ufshcd-pci.c b/drivers/ufs/host/ufshcd-pci.c
index 5f65dfad1a71..8a4f2381a32e 100644
--- a/drivers/ufs/host/ufshcd-pci.c
+++ b/drivers/ufs/host/ufshcd-pci.c
@@ -145,7 +145,7 @@ static int ufs_intel_set_lanes(struct ufs_hba *hba, u32 lanes)
pwr_info.lane_rx = lanes;
pwr_info.lane_tx = lanes;
- ret = ufshcd_config_pwr_mode(hba, &pwr_info);
+ ret = ufshcd_change_power_mode(hba, &pwr_info);
if (ret)
dev_err(hba->dev, "%s: Setting %u lanes, err = %d\n",
__func__, lanes, ret);
@@ -154,17 +154,15 @@ static int ufs_intel_set_lanes(struct ufs_hba *hba, u32 lanes)
static int ufs_intel_lkf_pwr_change_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status,
- const struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
int err = 0;
switch (status) {
case PRE_CHANGE:
- if (ufshcd_is_hs_mode(dev_max_params) &&
+ if (ufshcd_is_hs_mode(dev_req_params) &&
(hba->pwr_info.lane_rx != 2 || hba->pwr_info.lane_tx != 2))
ufs_intel_set_lanes(hba, 2);
- memcpy(dev_req_params, dev_max_params, sizeof(*dev_req_params));
break;
case POST_CHANGE:
if (ufshcd_is_hs_mode(dev_req_params)) {
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index 8563b6648976..51c2555bea73 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -302,11 +302,10 @@ struct ufs_pwr_mode_info {
* variant specific Uni-Pro initialization.
* @link_startup_notify: called before and after Link startup is carried out
* to allow variant specific Uni-Pro initialization.
+ * @negotiate_pwr_mode: called to negotiate power mode.
* @pwr_change_notify: called before and after a power mode change
* is carried out to allow vendor spesific capabilities
- * to be set. PRE_CHANGE can modify final_params based
- * on desired_pwr_mode, but POST_CHANGE must not alter
- * the final_params parameter
+ * to be set.
* @setup_xfer_req: called before any transfer request is issued
* to set some things
* @setup_task_mgmt: called before any task management request is issued
@@ -347,10 +346,12 @@ struct ufs_hba_variant_ops {
enum ufs_notify_change_status);
int (*link_startup_notify)(struct ufs_hba *,
enum ufs_notify_change_status);
- int (*pwr_change_notify)(struct ufs_hba *,
- enum ufs_notify_change_status status,
- const struct ufs_pa_layer_attr *desired_pwr_mode,
- struct ufs_pa_layer_attr *final_params);
+ int (*negotiate_pwr_mode)(struct ufs_hba *hba,
+ const struct ufs_pa_layer_attr *desired_pwr_mode,
+ struct ufs_pa_layer_attr *final_params);
+ int (*pwr_change_notify)(struct ufs_hba *hba,
+ enum ufs_notify_change_status status,
+ struct ufs_pa_layer_attr *final_params);
void (*setup_xfer_req)(struct ufs_hba *hba, int tag,
bool is_scsi_cmd);
void (*setup_task_mgmt)(struct ufs_hba *, int, u8);
@@ -1361,6 +1362,8 @@ extern int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
u8 attr_set, u32 mib_val, u8 peer);
extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
u32 *mib_val, u8 peer);
+extern int ufshcd_change_power_mode(struct ufs_hba *hba,
+ struct ufs_pa_layer_attr *pwr_mode);
extern int ufshcd_config_pwr_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *desired_pwr_mode);
extern int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode);
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v3] PCI: dw-rockchip: Enable async probe by default
From: Dmitry Torokhov @ 2026-03-25 15:23 UTC (permalink / raw)
To: Robin Murphy
Cc: Danilo Krummrich, Manivannan Sadhasivam, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Heiko Stuebner, Niklas Cassel, Shawn Lin,
Hans Zhang, Nicolas Frattaroli, Wilfred Mallawa, linux-pci,
linux-arm-kernel, linux-rockchip, linux-kernel, Anand Moon,
Grimmauld, Greg Kroah-Hartman, Rafael J. Wysocki, driver-core,
Lukas Wunner
In-Reply-To: <6cc25c83-6a5a-4785-9573-335371a94798@arm.com>
On Wed, Mar 25, 2026 at 03:01:03PM +0000, Robin Murphy wrote:
> On 25/03/2026 4:13 am, Dmitry Torokhov wrote:
> > On Thu, Mar 12, 2026 at 12:48:36PM +0000, Robin Murphy wrote:
> > > On 2026-03-11 9:09 pm, Danilo Krummrich wrote:
> > > > On Wed Mar 11, 2026 at 1:28 PM CET, Manivannan Sadhasivam wrote:
> > > > > On Wed, Mar 11, 2026 at 12:46:03PM +0100, Danilo Krummrich wrote:
> > > > > > On Wed Mar 11, 2026 at 6:24 AM CET, Manivannan Sadhasivam wrote:
> > > > > > > I have a contrary view here. If just a single driver or lib doesn't handle async
> > > > > > > probe, it cannot just force other drivers to not take the advantage of async
> > > > > > > probe. As I said above, enabling async probe easily saves a few hunderd ms or
> > > > > > > even more if there are more than one Root Port or Root Complex in an SoC.
> > > > > >
> > > > > > Then the driver or lib has to be fixed / improved first or the driver core has
> > > > > > to be enabled to deal with a case where PROBE_FORCE_SYNCHRONOUS is requested
> > > > > > from an async path, etc.
> > > > > >
> > > > > > In any case, applying the patch and breaking things (knowingly?) doesn't seem
> > > > > > like the correct approach.
> > > > > >
> > > > > > > I strongly agree with you here that the underlying issue should be fixed. But
> > > > > > > the real impact to end users is not this splat, but not having the boot time
> > > > > > > optimization that this patch brings in. As an end user, one would want their
> > > > > > > systems to boot quickly and they wouldn't bother much about a harmless warning
> > > > > > > splat appearing in the dmesg log.
> > > > > >
> > > > > > You mean quickly booting into a "harmless" potential deadlock condition the
> > > > > > warning splat tries to make people aware of? :)
> > > > > >
> > > > >
> > > > > Hmm, I overlooked the built-as-module part where the deadlock could be possible
> > > > > as indicated by the comment about the WARN_ON_ONCE().
> > > > >
> > > > > But what is the path forward here? Do you want the phylib to fix the
> > > > > request_module() call or fix the driver core instead?
> > > >
> > > > Here are a few thoughts.
> > > >
> > > > In general, I think the best would be to get rid of the (affected)
> > > > PROBE_FORCE_SYNCHRONOUS cases.
> > > >
> > > > Now, I guess this can be pretty hard for a PCI controller driver, as you can't
> > > > really predict what ends up being probed from you async context, i.e. it could
> > > > even be some other bus controller and things could even propagate further.
> > > >
> > > > Not sure how big of a deal it is in practice though, there are not a lot of
> > > > PROBE_FORCE_SYNCHRONOUS drivers (left), but note that specifying neither
> > > > PROBE_FORCE_SYNCHRONOUS nor PROBE_PREFER_ASYNCHRONOUS currently results in
> > > > synchronous by default.
> > > >
> > > > (Also, quite some other PCI controller drivers do set PROBE_PREFER_ASYNCHRONOUS
> > > > and apparently got lucky with it.)
> > > >
> > > > From a driver-core perspective I think we're rather limited on what we can do;
> > > > we are already in async context at this point and can't magically go back to
> > > > initcall context.
> > > >
> > > > So, the only thing I can think of is to kick off work on a workqueue, which in
> > > > the end would be the same as the deferred probe handling.
> > >
> > > Hmm, in fact, isn't the deferred probe mechanism itself actually quite
> > > appropriate? A suitable calling context isn't the most obvious "resource
> > > provider" to wait for, but ultimately it's still a case of "we don't
> > > have everything we need right now, but it's worth trying again soon".
> > > I may have missed some subtleties, but my instinct is that it could
> > > perhaps be as simple as something like this (completely untested).
> > >
> > > Cheers,
> > > Robin.
> > >
> > > ----->8-----
> > >
> > > diff --git a/drivers/base/dd.c b/drivers/base/dd.c
> > > index bea8da5f8a3a..3c4a0207ae3f 100644
> > > --- a/drivers/base/dd.c
> > > +++ b/drivers/base/dd.c
> > > @@ -954,6 +954,16 @@ static int __device_attach_driver(struct device_driver *drv, void *_data)
> > > if (data->check_async && async_allowed != data->want_async)
> > > return 0;
> > > + /*
> > > + * Bus drivers may probe asynchronously, but be adding a child device
> > > + * whose driver still wants a synchronous probe. In this case, just
> > > + * defer it, to be triggered by the parent driver probe succeeding.
> > > + */
> > > + if (!async_allowed && current_is_async()) {
> > > + driver_deferred_probe_add(dev);
> > > + return 0;
> > > + }
> >
> > That means that you are kicking the majority devices (for now) into
> > deferral path. I do not think this is optimal.
>
> And probing drivers under conditions where they may go wrong or deadlock is
> better? I've not yet had a chance to actually test this myself to see the
> effect on timings, but whatever it might be, I can't imagine any *other*
> method of re-serialising child driver probes could be significantly better
> (or if it could be, that might represent some improvement we could make to
> the deferred probe mechanism in general anyway).
There is serious disconnect as to what asynchronous and synchronous
probing means. You do not go "back" to synchronous probing.
/*
* Indicates whether we are considering asynchronous probing or
* not. Only initial binding after device or driver registration
* (including deferral processing) may be done asynchronously, the
* rest is always synchronous, as we expect it is being done by
* request from userspace.
*/
bool check_async;
So synchronous means that when you register device or driver we dun
probe immediately on the same thread that registered said device or
driver, while with async we _may_ schedule on a workqueue (but if the
system has already scheduled too much async it will be probed
synchronously or immediately).
So in the case we are discussing the probing of phy device is indeed
synchronous/immediate relative to the thread where the phy device is
registered.
>
> I have finally got a bit of time this afternoon to pick this up again, so
> I'll have a play and try to finish the write-up capturing all the reasoning
> so far (it's a long one...)
>
> > Does phy really need to request modules synchronously (and on its own)?
> > Why can't it rely on udev to load the modules and signal when phy
> > devices are ready?
>
> Getting hung up on what phylib does in this one particular case is rather
> missing the point. There is a reason that we're still not forcing
> async_probe on for everything by default. Many drivers will still not have
> been tested and validated to handle it correctly, and while the majority of
> latent issues will likely just be concurrency bugs which can be fixed with
> better locking or whatever, even then we should be encouraging developers to
> actively test and look for such bugs to make their drivers "async probe
> clean", rather than knowingly enabling bugs to surface in the wild as weird
> and subtle breakage on end-user systems.
No. We have identified (at least IMO) that what phylib does is wrong. I
am not advocating forcing this PCI host to be marked for asycn probing
right now, before the phy issue is fixed, but I object to adding
workarounds to driver core which hurt other cases and may lead to phylib
never be fixed.
>
> However, I imagine there will always remain some small minority of
> PROBE_FORCE_SYNCHRONOUS drivers - either for niche legitimate technical
> reasons, or just legacy drivers where updating them would take more effort
> than it's worth - so the driver core surely needs the ability to not do the
> wrong thing itself. That doesn't even need to be "optimal", it just needs to
> be functionally correct.
Again, your expectation of what sync probing means differs from what I
had in mind when implementing it. PROBE_FORCE_SYNCHRONOUS is typically
for drivers/modules that register both a device (typically a singleton)
and a driver, and want to unregister both and free all resources when
initialization fails for some reason. Think cases like PC keyboard
controller.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH v7 0/2] Add support for Variscite DART-MX95 and Sonata board
From: Stefano Radaelli @ 2026-03-25 15:25 UTC (permalink / raw)
To: Frank Li
Cc: Francesco Dolcini, devicetree, linux-kernel, pierluigi.p,
Stefano Radaelli, Shawn Guo, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, imx, linux-arm-kernel
In-Reply-To: <acP2UX6B5js_ozWm@lizhi-Precision-Tower-5810>
On Wed, Mar 25, 2026 at 10:50:57AM -0400, Frank Li wrote:
> >
> > How do you know that the correct copyright year is 2026?
> > The copyright years does not change to today just because it is the year
> > it was submitted.
>
> At least it should include 2026 because it is new files in kernel tree.
>
> >
> > I think that you should refrain yourself for doing these kind of changes
> > to the code when you apply patches.
>
> If original owner have concern, I can update it in my tree.
>
Hi Francesco, hi Frank,
thanks for the clarification.
In this specific case, I'm fine with keeping 2026 for these new files
introduced in the kernel tree.
Thank you all for taking care of this!
Best regards,
Stefano
^ permalink raw reply
* Re: [PATCH v3] PCI: dw-rockchip: Enable async probe by default
From: Dmitry Torokhov @ 2026-03-25 15:26 UTC (permalink / raw)
To: Danilo Krummrich
Cc: Robin Murphy, Manivannan Sadhasivam, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Heiko Stuebner, Niklas Cassel, Shawn Lin,
Hans Zhang, Nicolas Frattaroli, Wilfred Mallawa, linux-pci,
linux-arm-kernel, linux-rockchip, linux-kernel, Anand Moon,
Grimmauld, Greg Kroah-Hartman, Rafael J. Wysocki, driver-core,
Lukas Wunner
In-Reply-To: <DHBYL7Y262J2.263EOC2JNN4RK@kernel.org>
On Wed, Mar 25, 2026 at 04:13:03PM +0100, Danilo Krummrich wrote:
> On Wed Mar 25, 2026 at 5:13 AM CET, Dmitry Torokhov wrote:
> > That means that you are kicking the majority devices (for now) into
> > deferral path. I do not think this is optimal.
>
> That's not necessary, we'd only need to kick those into the deferral path that
> have PROBE_FORCE_SYNCHRONOUS, no?
Yes, it may limit the fallout, but as I explained in my other email
there seem to be a serious disconnect on what synchronous and
asynchronous probing mean.
I wonder, don't we get issues with phylib in other cases? Don't we ever
have a module resulting in creating a phy device triggering loading
another module on the same thread? Won't that result in a warning also?
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH v6 1/5] mm: rmap: support batched checks of the references for large folios
From: Andrew Morton @ 2026-03-25 15:30 UTC (permalink / raw)
To: Lorenzo Stoakes (Oracle)
Cc: David Hildenbrand (Arm), Baolin Wang, Barry Song, catalin.marinas,
will, lorenzo.stoakes, ryan.roberts, Liam.Howlett, vbabka, rppt,
surenb, mhocko, riel, harry.yoo, jannh, willy, dev.jain, linux-mm,
linux-arm-kernel, linux-kernel
In-Reply-To: <e227a7f7-0186-4d10-b7b4-c84ca8424bdd@lucifer.local>
On Wed, 25 Mar 2026 15:06:26 +0000 "Lorenzo Stoakes (Oracle)" <ljs@kernel.org> wrote:
> > > Sorry unclear here - does the series need more work or does a follow up patch
> > > need more work?
> >
> > Follow up!
>
> Ok good as in mm-stable now. Sadly means I don't get to review it but there we
> go.
Well, this was sent 6 weeks ago, at v6!
But please go ahead. If review is very bad, there's git-rebase
(happens sometimes) or some followup fix and a minor bisection hole
(happens a bit more often).
And those followup fixes will trickle in all the way out to 7.1-rc7,
via the hotfixes path. This happens a great deal - about half(?) of
hotfixes pertain to material we added in the current -rc cycle.
^ permalink raw reply
* Re: [PATCH v2 0/4] arm64: dts: imx952-evk: Add audio sound cards
From: Frank Li @ 2026-03-25 15:30 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, s.hauer, kernel, festevam, devicetree,
imx, linux-arm-kernel, linux-kernel, Shengjiu Wang
In-Reply-To: <20260316021439.2971610-1-shengjiu.wang@nxp.com>
On Mon, 16 Mar 2026 10:14:35 +0800, Shengjiu Wang wrote:
> Add audio device nodes and sound card (wm8962, PDM microphone, bt-sco).
>
> Changes in v2:
> - use macro FSL_EDMA_RX for audio nodes in patch 1/4
> - update commit message to add ASRC2 info in patch 2/4
> - add acked by Daniel in patch 2/4, 3/4, 4/4
>
> [...]
Applied, thanks!
[1/4] arm64: dts: imx952: Add audio device nodes
commit: 9cdf26f3cb3fad99d48c59e2e8630939ca75a37c
[2/4] arm64: dts: imx952-evk: Add sound-wm8962 support
commit: 48fe0319c1fe7c5b470e0b29975cd7395609319b
[3/4] arm64: dts: imx952-evk: Add bt-sco sound card support
commit: bf99a2ea2c82ad4baa9476f7f168c649313b1751
[4/4] arm64: dts: imx952-evk: Add PDM microphone sound card support
commit: 9846b69696e59097926f427dae90b3d7aed66846
Best regards,
--
Frank Li <Frank.Li@nxp.com>
^ permalink raw reply
* Re: [PATCH] arm64: dts: imx95-15x15-evk: remove regulator-always-on for reg_m2_pwr
From: Frank Li @ 2026-03-25 15:32 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, s.hauer, kernel, festevam, hongxing.zhu,
Sherry Sun
Cc: imx, linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20260317030418.441824-1-sherry.sun@nxp.com>
On Tue, 17 Mar 2026 11:04:18 +0800, Sherry Sun wrote:
> Now we use vpcie3v3aux-supply to keep 3.3Vaux supply enabled for the
> entire PCIe controller lifecycle, no need regulator-always-on property.
>
>
Applied, thanks!
[1/1] arm64: dts: imx95-15x15-evk: remove regulator-always-on for reg_m2_pwr
commit: 66df8383703f78ea6fd935e8b986802117d396dd
Best regards,
--
Frank Li <Frank.Li@nxp.com>
^ permalink raw reply
* Re: [PATCH v6 1/5] mm: rmap: support batched checks of the references for large folios
From: Lorenzo Stoakes (Oracle) @ 2026-03-25 15:32 UTC (permalink / raw)
To: Andrew Morton
Cc: David Hildenbrand (Arm), Baolin Wang, Barry Song, catalin.marinas,
will, lorenzo.stoakes, ryan.roberts, Liam.Howlett, vbabka, rppt,
surenb, mhocko, riel, harry.yoo, jannh, willy, dev.jain, linux-mm,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260325083016.a32095bea3f04488a7c9005a@linux-foundation.org>
On Wed, Mar 25, 2026 at 08:30:16AM -0700, Andrew Morton wrote:
> On Wed, 25 Mar 2026 15:06:26 +0000 "Lorenzo Stoakes (Oracle)" <ljs@kernel.org> wrote:
>
> > > > Sorry unclear here - does the series need more work or does a follow up patch
> > > > need more work?
> > >
> > > Follow up!
> >
> > Ok good as in mm-stable now. Sadly means I don't get to review it but there we
> > go.
>
> Well, this was sent 6 weeks ago, at v6!
Yup I know, I've struggled to clear my backlog.
>
> But please go ahead. If review is very bad, there's git-rebase
> (happens sometimes) or some followup fix and a minor bisection hole
> (happens a bit more often).
>
> And those followup fixes will trickle in all the way out to 7.1-rc7,
> via the hotfixes path. This happens a great deal - about half(?) of
> hotfixes pertain to material we added in the current -rc cycle.
>
Well given the other tags it's unlikely that would happen, so it doesn't feel
really worthwhile at this point.
Really I guess I'd like to know the timing of when mm-stable is taken so I can
know the deadline for stuff like this.
Thanks, Lorenzo
^ permalink raw reply
* Re: [PATCH v2] arm64: dts: imx8mp-frdm: add sd, ethernet, wifi, usb and hdmi support
From: Frank Li @ 2026-03-25 15:37 UTC (permalink / raw)
To: Fabian Pfitzner
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, devicetree, imx,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260316-fpf-imx8mp-frdm-v2-1-e2e8aadecb2f@pengutronix.de>
On Mon, Mar 16, 2026 at 10:25:04AM +0100, Fabian Pfitzner wrote:
> Add support for the following new features:
>
> - SD Card
> - Ethernet (FEC + EQOS)
> - Wifi
> - USB
> - HDMI
>
> The imx8mp-evk dt and the NXP downstream imx8mp-frdm dts were
> taken as a reference.
>
> Signed-off-by: Fabian Pfitzner <f.pfitzner@pengutronix.de>
> ---
Please rebase to https://git.kernel.org/pub/scm/linux/kernel/git/frank.li/linux.git/log/?h=for-next
Frank
> Changes in v2:
> - Reorder nodes by name
> - Remove unused "realtek,clkout-disable" property
> - Link to v1: https://lore.kernel.org/r/20260224-fpf-imx8mp-frdm-v1-1-d7f3b57c18e0@pengutronix.de
> ---
> arch/arm64/boot/dts/freescale/imx8mp-frdm.dts | 407 ++++++++++++++++++++++++++
> 1 file changed, 407 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/freescale/imx8mp-frdm.dts b/arch/arm64/boot/dts/freescale/imx8mp-frdm.dts
> index 55690f5e53d7e1fbf7eae8a1f31eb064465ccb6c..c3691887bb8456c56de27af2e8432657ae2d77e6 100644
> --- a/arch/arm64/boot/dts/freescale/imx8mp-frdm.dts
> +++ b/arch/arm64/boot/dts/freescale/imx8mp-frdm.dts
> @@ -42,6 +42,67 @@ memory@40000000 {
> reg = <0x0 0x40000000 0 0xc0000000>,
> <0x1 0x00000000 0 0x40000000>;
> };
> +
> + native-hdmi-connector {
> + compatible = "hdmi-connector";
> + label = "HDMI OUT";
> + type = "a";
> +
> + port {
> + hdmi_in: endpoint {
> + remote-endpoint = <&hdmi_tx_out>;
> + };
> + };
> + };
> +
> + reg_usdhc2_vmmc: regulator-sd {
> + compatible = "regulator-fixed";
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
> + regulator-name = "VSD_3V3";
> + regulator-min-microvolt = <3300000>;
> + regulator-max-microvolt = <3300000>;
> + gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
> + enable-active-high;
> + };
> +
> + reg_usb_vbus: regulator-vbus {
> + compatible = "regulator-fixed";
> + regulator-name = "USB_VBUS";
> + regulator-min-microvolt = <5000000>;
> + regulator-max-microvolt = <5000000>;
> + gpio = <&pcal6416_1 5 GPIO_ACTIVE_HIGH>;
> + enable-active-high;
> + };
> +
> + reg_usdhc1_vmmc: regulator-wifi-vmmc {
> + compatible = "regulator-fixed";
> + regulator-name = "WLAN_EN";
> + regulator-min-microvolt = <3300000>;
> + regulator-max-microvolt = <3300000>;
> + gpio = <&pcal6416_1 10 GPIO_ACTIVE_HIGH>;
> + /*
> + * IW612 wifi chip needs more delay than other wifi chips to complete
> + * the host interface initialization after power up, otherwise the
> + * internal state of IW612 may be unstable, resulting in the failure of
> + * the SDIO3.0 switch voltage.
> + */
> + enable-active-high;
> + startup-delay-us = <20000>;
> + };
> +
> + reg_usdhc1_vqmmc: regulator-wifi-vqmmc {
> + compatible = "regulator-fixed";
> + regulator-name = "regulator-wifi-vqmmc";
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + enable-active-high;
> + };
> +
> + sdio_pwrseq: usdhc1-pwrseq {
> + compatible = "mmc-pwrseq-simple";
> + reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
> + };
> };
>
> &A53_0 {
> @@ -60,6 +121,147 @@ &A53_3 {
> cpu-supply = <®_arm>;
> };
>
> +&eqos {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_eqos>;
> + phy-mode = "rgmii-id";
> + phy-handle = <ðphy0>;
> + snps,force_thresh_dma_mode;
> + snps,mtl-tx-config = <&mtl_tx_setup>;
> + snps,mtl-rx-config = <&mtl_rx_setup>;
> + status = "okay";
> +
> + mdio {
> + compatible = "snps,dwmac-mdio";
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + ethphy0: ethernet-phy@2 {
> + compatible = "ethernet-phy-ieee802.3-c22";
> + reg = <2>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_eqos_phy>;
> + reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
> + reset-assert-us = <10000>;
> + reset-deassert-us = <80000>;
> + };
> + };
> +
> + mtl_tx_setup: tx-queues-config {
> + snps,tx-queues-to-use = <5>;
> +
> + queue0 {
> + snps,dcb-algorithm;
> + snps,priority = <0x1>;
> + };
> +
> + queue1 {
> + snps,dcb-algorithm;
> + snps,priority = <0x2>;
> + };
> +
> + queue2 {
> + snps,dcb-algorithm;
> + snps,priority = <0x4>;
> + };
> +
> + queue3 {
> + snps,dcb-algorithm;
> + snps,priority = <0x8>;
> + };
> +
> + queue4 {
> + snps,dcb-algorithm;
> + snps,priority = <0xf0>;
> + };
> + };
> +
> + mtl_rx_setup: rx-queues-config {
> + snps,rx-queues-to-use = <5>;
> + snps,rx-sched-sp;
> +
> + queue0 {
> + snps,dcb-algorithm;
> + snps,priority = <0x1>;
> + snps,map-to-dma-channel = <0>;
> + };
> +
> + queue1 {
> + snps,dcb-algorithm;
> + snps,priority = <0x2>;
> + snps,map-to-dma-channel = <1>;
> + };
> +
> + queue2 {
> + snps,dcb-algorithm;
> + snps,priority = <0x4>;
> + snps,map-to-dma-channel = <2>;
> + };
> +
> + queue3 {
> + snps,dcb-algorithm;
> + snps,priority = <0x8>;
> + snps,map-to-dma-channel = <3>;
> + };
> +
> + queue4 {
> + snps,dcb-algorithm;
> + snps,priority = <0xf0>;
> + snps,map-to-dma-channel = <4>;
> + };
> + };
> +};
> +
> +&fec {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_fec>;
> + phy-mode = "rgmii-id";
> + phy-handle = <ðphy1>;
> + fsl,magic-packet;
> + status = "okay";
> +
> + mdio {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + ethphy1: ethernet-phy@1 {
> + compatible = "ethernet-phy-ieee802.3-c22";
> + reg = <1>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_fec_phy>;
> + eee-broken-1000t;
> + reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
> + reset-assert-us = <10000>;
> + reset-deassert-us = <80000>;
> + realtek,aldps-enable;
> + realtek,clkout-disable;
> + };
> + };
> +};
> +
> +
> +&hdmi_pvi {
> + status = "okay";
> +};
> +
> +&hdmi_tx {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_hdmi>;
> + status = "okay";
> +
> + ports {
> + port@1 {
> + hdmi_tx_out: endpoint {
> + remote-endpoint = <&hdmi_in>;
> + };
> + };
> + };
> +};
> +
> +&hdmi_tx_phy {
> + status = "okay";
> +};
> +
> &i2c1 {
> clock-frequency = <400000>;
> pinctrl-names = "default";
> @@ -218,6 +420,32 @@ &i2c3 {
> status = "okay";
> };
>
> +&lcdif3 {
> + status = "okay";
> +};
> +
> +&usb3_0 {
> + status = "okay";
> +};
> +
> +&usb3_1 {
> + status = "okay";
> +};
> +
> +&usb3_phy0 {
> + status = "okay";
> +};
> +
> +&usb3_phy1 {
> + vbus-supply = <®_usb_vbus>;
> + status = "okay";
> +};
> +
> +&usb_dwc3_1 {
> + dr_mode = "host";
> + status = "okay";
> +};
> +
> &snvs_pwrkey {
> status = "okay";
> };
> @@ -237,6 +465,36 @@ &uart3 {
> status = "okay";
> };
>
> +&usdhc1 {
> + assigned-clocks = <&clk IMX8MP_CLK_USDHC1>;
> + assigned-clock-rates = <200000000>;
> + pinctrl-names = "default", "state_100mhz", "state_200mhz";
> + pinctrl-0 = <&pinctrl_usdhc1>;
> + pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
> + pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
> + mmc-pwrseq = <&sdio_pwrseq>;
> + vmmc-supply = <®_usdhc1_vmmc>;
> + vqmmc-supply = <®_usdhc1_vqmmc>;
> + bus-width = <4>;
> + non-removable;
> + no-sd;
> + no-mmc;
> + status = "okay";
> +};
> +
> +&usdhc2 {
> + assigned-clocks = <&clk IMX8MP_CLK_USDHC2>;
> + assigned-clock-rates = <400000000>;
> + pinctrl-names = "default", "state_100mhz", "state_200mhz";
> + pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
> + pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
> + pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
> + cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
> + vmmc-supply = <®_usdhc2_vmmc>;
> + bus-width = <4>;
> + status = "okay";
> +};
> +
> &usdhc3 {
> assigned-clocks = <&clk IMX8MP_CLK_USDHC3>;
> assigned-clock-rates = <400000000>;
> @@ -250,6 +508,74 @@ &usdhc3 {
> };
>
> &iomuxc {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_hog>;
> +
> + pinctrl_eqos: eqosgrp {
> + fsl,pins = <
> + MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC 0x2
> + MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO 0x2
> + MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0 0x90
> + MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1 0x90
> + MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2 0x90
> + MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3 0x90
> + MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x90
> + MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x90
> + MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0 0x16
> + MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1 0x16
> + MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2 0x16
> + MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3 0x16
> + MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x16
> + MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x16
> + >;
> + };
> +
> + pinctrl_eqos_phy: eqosphygrp {
> + fsl,pins = <
> + MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22 0x10
> + >;
> + };
> +
> + pinctrl_fec: fecgrp {
> + fsl,pins = <
> + MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC 0x2
> + MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO 0x2
> + MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0 0x90
> + MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1 0x90
> + MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2 0x90
> + MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3 0x90
> + MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC 0x90
> + MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL 0x90
> + MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0 0x16
> + MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1 0x16
> + MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2 0x16
> + MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3 0x16
> + MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL 0x16
> + MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC 0x16
> + >;
> + };
> +
> + pinctrl_fec_phy: fecphygrp {
> + fsl,pins = <
> + MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02 0x10
> + >;
> + };
> +
> + pinctrl_hdmi: hdmigrp {
> + fsl,pins = <
> + MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC 0x10
> + >;
> + };
> +
> + pinctrl_hog: hoggrp {
> + fsl,pins = <
> + /* Pin might be required by multiple drivers
> + * (e. g. HDMI Audio and HDMI TX)
> + */
> + MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD 0x40000010
> + >;
> + };
> +
> pinctrl_i2c1: i2c1grp {
> fsl,pins = <
> MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c2
> @@ -289,6 +615,12 @@ MX8MP_IOMUXC_SD1_STROBE__GPIO2_IO11 0x146
> >;
> };
>
> + pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
> + fsl,pins = <
> + MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19 0x40
> + >;
> + };
> +
> pinctrl_uart2: uart2grp {
> fsl,pins = <
> MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x140
> @@ -305,6 +637,81 @@ MX8MP_IOMUXC_ECSPI1_MISO__UART3_DCE_CTS 0x140
> >;
> };
>
> + pinctrl_usdhc1: usdhc1grp {
> + fsl,pins = <
> + MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x190
> + MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x1d0
> + MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x1d0
> + MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d0
> + MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d0
> + MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d0
> + >;
> + };
> +
> + pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
> + fsl,pins = <
> + MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x194
> + MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x1d4
> + MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x1d4
> + MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d4
> + MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d4
> + MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d4
> + >;
> + };
> +
> + pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
> + fsl,pins = <
> + MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x196
> + MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x1d6
> + MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x1d6
> + MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d6
> + MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d6
> + MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d6
> + >;
> + };
> +
> + pinctrl_usdhc2: usdhc2grp {
> + fsl,pins = <
> + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x190
> + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d0
> + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d0
> + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d0
> + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d0
> + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d0
> + MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
> + >;
> + };
> +
> + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
> + fsl,pins = <
> + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x194
> + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d4
> + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d4
> + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d4
> + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d4
> + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d4
> + MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
> + >;
> + };
> +
> + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
> + fsl,pins = <
> + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x196
> + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d6
> + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d6
> + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d6
> + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d6
> + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d6
> + MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
> + >;
> + };
> +
> + pinctrl_usdhc2_gpio: usdhc2gpiogrp {
> + fsl,pins = <
> + MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12 0x1c4
> + >;
> + };
> +
> pinctrl_usdhc3: usdhc3grp {
> fsl,pins = <
> MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x190
>
> ---
> base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
> change-id: 20260224-fpf-imx8mp-frdm-402c4df06302
>
> Best regards,
> --
> Fabian Pfitzner <f.pfitzner@pengutronix.de>
>
^ 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