diff --git a/drivers/media/platform/rockchip/rga/Makefile b/drivers/media/platform/rockchip/rga/Makefile index 1bbecdc3d8df..7326a548f3dc 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 0152b8ef2da2..b3cb6bf8eb86 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -913,6 +913,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 feaf40acd4ee..bd431534d0d3 100644 --- a/drivers/media/platform/rockchip/rga/rga.h +++ b/drivers/media/platform/rockchip/rga/rga.h @@ -169,5 +169,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 000000000000..ca1c268303dd --- /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 + */ + +#include +#include +#include +#include + +#include + +#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); + + 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->out.pix : &ctx->in.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 000000000000..85fd8ae257ec --- /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 + */ +#ifndef __RGA3_HW_H__ +#define __RGA3_HW_H__ + +#include +#include + +#define RGA3_CMDBUF_SIZE 0xb8 + +#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