124a63d4cSSven Püschel // SPDX-License-Identifier: GPL-2.0-only 224a63d4cSSven Püschel /* 324a63d4cSSven Püschel * Copyright (C) 2025-2026 Pengutronix e.K. 424a63d4cSSven Püschel * Author: Sven Püschel <s.pueschel@pengutronix.de> 524a63d4cSSven Püschel */ 624a63d4cSSven Püschel 724a63d4cSSven Püschel #include <linux/pm_runtime.h> 824a63d4cSSven Püschel #include <linux/bitfield.h> 924a63d4cSSven Püschel #include <linux/delay.h> 1024a63d4cSSven Püschel #include <linux/printk.h> 1124a63d4cSSven Püschel 1224a63d4cSSven Püschel #include <media/v4l2-common.h> 1324a63d4cSSven Püschel 1424a63d4cSSven Püschel #include "rga3-hw.h" 1524a63d4cSSven Püschel #include "rga.h" 1624a63d4cSSven Püschel 1724a63d4cSSven Püschel static unsigned int rga3_get_scaling(unsigned int src, unsigned int dst) 1824a63d4cSSven Püschel { 1924a63d4cSSven Püschel /* 2024a63d4cSSven Püschel * RGA3 scaling factor calculation as described in chapter 5.4.7 Resize 2124a63d4cSSven Püschel * of the TRM Part 2. The resulting scaling factor is a 16-bit value 2224a63d4cSSven Püschel * and therefore normalized with 2^16. 2324a63d4cSSven Püschel * 2424a63d4cSSven Püschel * While the TRM also mentions (dst-1)/(src-1) for the up-scaling case, 2524a63d4cSSven Püschel * it didn't work as the value always exceeds 16 bit. Flipping the 2624a63d4cSSven Püschel * factors results in a correct up-scaling. This is possible as the 2724a63d4cSSven Püschel * RGA3 has the RGA3_WIN_SCALE_XXX_UP bit to determine if it does 2824a63d4cSSven Püschel * an up or downscale. 2924a63d4cSSven Püschel * 3024a63d4cSSven Püschel * The scaling factor can potentially cause a slightly larger scaling 3124a63d4cSSven Püschel * (e.g. 1/2px larger scale and then cropped to the destination size). 3224a63d4cSSven Püschel * This can be seen when scaling 128x128px RGBA to 256x256px RGBA. 3324a63d4cSSven Püschel * The RGA2 scaling factor calculation (without the various +/-1 3424a63d4cSSven Püschel * doesn't work for the RGA3. It's assumed that this is an hardware 3524a63d4cSSven Püschel * accuracy limitation, as the vendor kernel driver uses the same 3624a63d4cSSven Püschel * scaling factor calculation. 3724a63d4cSSven Püschel * 3824a63d4cSSven Püschel * With a scaling factor of 1.0 the calculation technically also 3924a63d4cSSven Püschel * overflows 16 bit. This isn't relevant, as in this case the 4024a63d4cSSven Püschel * RGA3_WIN_SCALE_XXX_BYPASS bit completely skips the scaling operation. 4124a63d4cSSven Püschel */ 4224a63d4cSSven Püschel if (dst > src) { 4324a63d4cSSven Püschel if (((src - 1) << 16) % (dst - 1) == 0) 4424a63d4cSSven Püschel return ((src - 1) << 16) / (dst - 1) - 1; 4524a63d4cSSven Püschel else 4624a63d4cSSven Püschel return ((src - 1) << 16) / (dst - 1); 4724a63d4cSSven Püschel } else { 4824a63d4cSSven Püschel return ((dst - 1) << 16) / (src - 1) + 1; 4924a63d4cSSven Püschel } 5024a63d4cSSven Püschel } 5124a63d4cSSven Püschel 5224a63d4cSSven Püschel /* 5324a63d4cSSven Püschel * Check if the given format can be captured, as the RGA3 doesn't support all 5424a63d4cSSven Püschel * input formats also on it's output. 5524a63d4cSSven Püschel */ 5624a63d4cSSven Püschel static bool rga3_can_capture(const struct rga3_fmt *fmt) 5724a63d4cSSven Püschel { 5824a63d4cSSven Püschel return fmt->hw_format <= RGA3_COLOR_FMT_LAST_OUTPUT; 5924a63d4cSSven Püschel } 6024a63d4cSSven Püschel 6124a63d4cSSven Püschel /* 6224a63d4cSSven Püschel * Map the transformations to the RGA3 command buffer. 6324a63d4cSSven Püschel * Currently this is just the scaling settings and a fixed alpha value. 6424a63d4cSSven Püschel */ 6524a63d4cSSven Püschel static void rga3_cmd_set_trans_info(struct rga_ctx *ctx) 6624a63d4cSSven Püschel { 6724a63d4cSSven Püschel u32 *cmd = ctx->cmdbuf_virt; 6824a63d4cSSven Püschel unsigned int src_h, src_w, dst_h, dst_w; 6924a63d4cSSven Püschel unsigned int reg; 7024a63d4cSSven Püschel u16 hor_scl_fac, ver_scl_fac; 7124a63d4cSSven Püschel const struct rga3_fmt *in = ctx->in.fmt; 7224a63d4cSSven Püschel 7324a63d4cSSven Püschel /* Support basic input cropping to support 1088px inputs */ 7424a63d4cSSven Püschel src_h = ctx->in.crop.height; 7524a63d4cSSven Püschel src_w = ctx->in.crop.width; 7624a63d4cSSven Püschel dst_h = ctx->out.pix.height; 7724a63d4cSSven Püschel dst_w = ctx->out.pix.width; 7824a63d4cSSven Püschel 7924a63d4cSSven Püschel reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG; 8024a63d4cSSven Püschel cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_SCALE_HOR_UP, dst_w > src_w) 8124a63d4cSSven Püschel | FIELD_PREP(RGA3_WIN_SCALE_HOR_BYPASS, dst_w == src_w) 8224a63d4cSSven Püschel | FIELD_PREP(RGA3_WIN_SCALE_VER_UP, dst_h > src_h) 8324a63d4cSSven Püschel | FIELD_PREP(RGA3_WIN_SCALE_VER_BYPASS, dst_h == src_h); 8424a63d4cSSven Püschel 8524a63d4cSSven Püschel hor_scl_fac = rga3_get_scaling(src_w, dst_w); 8624a63d4cSSven Püschel ver_scl_fac = rga3_get_scaling(src_h, dst_h); 8724a63d4cSSven Püschel reg = RGA3_WIN0_SCL_FAC - RGA3_FIRST_CMD_REG; 8824a63d4cSSven Püschel cmd[reg >> 2] = FIELD_PREP(RGA3_SCALE_HOR_FAC, hor_scl_fac) 8924a63d4cSSven Püschel | FIELD_PREP(RGA3_SCALE_VER_FAC, ver_scl_fac); 9024a63d4cSSven Püschel 9124a63d4cSSven Püschel if (v4l2_format_info(in->fourcc)->has_alpha) { 9224a63d4cSSven Püschel /* copy alpha from input */ 9324a63d4cSSven Püschel reg = RGA3_OVLP_TOP_ALPHA - RGA3_FIRST_CMD_REG; 9424a63d4cSSven Püschel cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1) 9524a63d4cSSven Püschel | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1); 9624a63d4cSSven Püschel reg = RGA3_OVLP_BOT_ALPHA - RGA3_FIRST_CMD_REG; 9724a63d4cSSven Püschel cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1) 9824a63d4cSSven Püschel | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1); 9924a63d4cSSven Püschel } else { 10024a63d4cSSven Püschel /* just use a 255 alpha value */ 10124a63d4cSSven Püschel reg = RGA3_OVLP_TOP_CTRL - RGA3_FIRST_CMD_REG; 10224a63d4cSSven Püschel cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff) 10324a63d4cSSven Püschel | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1); 10424a63d4cSSven Püschel reg = RGA3_OVLP_BOT_CTRL - RGA3_FIRST_CMD_REG; 10524a63d4cSSven Püschel cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff) 10624a63d4cSSven Püschel | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1); 10724a63d4cSSven Püschel } 10824a63d4cSSven Püschel } 10924a63d4cSSven Püschel 11024a63d4cSSven Püschel static void rga3_cmd_set_win0_addr(struct rga_ctx *ctx, 11124a63d4cSSven Püschel const struct rga_addrs *addrs) 11224a63d4cSSven Püschel { 11324a63d4cSSven Püschel u32 *cmd = ctx->cmdbuf_virt; 11424a63d4cSSven Püschel unsigned int reg; 11524a63d4cSSven Püschel 11624a63d4cSSven Püschel reg = RGA3_WIN0_Y_BASE - RGA3_FIRST_CMD_REG; 11724a63d4cSSven Püschel cmd[reg >> 2] = addrs->y_addr; 11824a63d4cSSven Püschel reg = RGA3_WIN0_U_BASE - RGA3_FIRST_CMD_REG; 11924a63d4cSSven Püschel cmd[reg >> 2] = addrs->u_addr; 12024a63d4cSSven Püschel } 12124a63d4cSSven Püschel 12224a63d4cSSven Püschel static void rga3_cmd_set_wr_addr(struct rga_ctx *ctx, 12324a63d4cSSven Püschel const struct rga_addrs *addrs) 12424a63d4cSSven Püschel { 12524a63d4cSSven Püschel u32 *cmd = ctx->cmdbuf_virt; 12624a63d4cSSven Püschel unsigned int reg; 12724a63d4cSSven Püschel 12824a63d4cSSven Püschel reg = RGA3_WR_Y_BASE - RGA3_FIRST_CMD_REG; 12924a63d4cSSven Püschel cmd[reg >> 2] = addrs->y_addr; 13024a63d4cSSven Püschel reg = RGA3_WR_U_BASE - RGA3_FIRST_CMD_REG; 13124a63d4cSSven Püschel cmd[reg >> 2] = addrs->u_addr; 13224a63d4cSSven Püschel } 13324a63d4cSSven Püschel 13424a63d4cSSven Püschel /* Map the input pixel format to win0 of the comamnd buffer. */ 13524a63d4cSSven Püschel static void rga3_cmd_set_win0_format(struct rga_ctx *ctx) 13624a63d4cSSven Püschel { 13724a63d4cSSven Püschel u32 *cmd = ctx->cmdbuf_virt; 13824a63d4cSSven Püschel const struct rga3_fmt *in = ctx->in.fmt; 13924a63d4cSSven Püschel const struct rga3_fmt *out = ctx->out.fmt; 14024a63d4cSSven Püschel const struct v4l2_format_info *in_fmt, *out_fmt; 14124a63d4cSSven Püschel unsigned int act_h, act_w, src_h, src_w; 14224a63d4cSSven Püschel bool r2y, y2r; 14324a63d4cSSven Püschel u8 rd_format; 14424a63d4cSSven Püschel const struct v4l2_pix_format_mplane *csc_pix; 14524a63d4cSSven Püschel u8 csc_mode; 14624a63d4cSSven Püschel unsigned int reg; 14724a63d4cSSven Püschel 14824a63d4cSSven Püschel act_h = ctx->in.pix.height; 14924a63d4cSSven Püschel act_w = ctx->in.pix.width; 15024a63d4cSSven Püschel /* Support basic input cropping to support 1088px inputs */ 15124a63d4cSSven Püschel src_h = ctx->in.crop.height; 15224a63d4cSSven Püschel src_w = ctx->in.crop.width; 15324a63d4cSSven Püschel 15424a63d4cSSven Püschel in_fmt = v4l2_format_info(in->fourcc); 15524a63d4cSSven Püschel out_fmt = v4l2_format_info(out->fourcc); 15624a63d4cSSven Püschel r2y = v4l2_is_format_rgb(in_fmt) && v4l2_is_format_yuv(out_fmt); 15724a63d4cSSven Püschel y2r = v4l2_is_format_yuv(in_fmt) && v4l2_is_format_rgb(out_fmt); 15824a63d4cSSven Püschel 15924a63d4cSSven Püschel /* The Hardware only supports formats with 1/2 planes */ 16024a63d4cSSven Püschel if (in_fmt->comp_planes == 2) 16124a63d4cSSven Püschel rd_format = RGA3_RDWR_FORMAT_SEMI_PLANAR; 16224a63d4cSSven Püschel else 16324a63d4cSSven Püschel rd_format = RGA3_RDWR_FORMAT_INTERLEAVED; 16424a63d4cSSven Püschel 16524a63d4cSSven Püschel /* set pixel format and CSC */ 16624a63d4cSSven Püschel csc_pix = r2y ? &ctx->out.pix : &ctx->in.pix; 16724a63d4cSSven Püschel switch (csc_pix->ycbcr_enc) { 16824a63d4cSSven Püschel case V4L2_YCBCR_ENC_BT2020: 16924a63d4cSSven Püschel csc_mode = RGA3_WIN_CSC_MODE_BT2020_L; 17024a63d4cSSven Püschel break; 17124a63d4cSSven Püschel case V4L2_YCBCR_ENC_709: 17224a63d4cSSven Püschel csc_mode = RGA3_WIN_CSC_MODE_BT709_L; 17324a63d4cSSven Püschel break; 17424a63d4cSSven Püschel default: /* should be fixed to BT601 in adjust_and_map_format */ 17524a63d4cSSven Püschel if (csc_pix->quantization == V4L2_QUANTIZATION_LIM_RANGE) 17624a63d4cSSven Püschel csc_mode = RGA3_WIN_CSC_MODE_BT601_L; 17724a63d4cSSven Püschel else 17824a63d4cSSven Püschel csc_mode = RGA3_WIN_CSC_MODE_BT601_F; 17924a63d4cSSven Püschel break; 18024a63d4cSSven Püschel } 18124a63d4cSSven Püschel 18224a63d4cSSven Püschel reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG; 18324a63d4cSSven Püschel cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_ENABLE, 1) 18424a63d4cSSven Püschel | FIELD_PREP(RGA3_WIN_PIC_FORMAT, in->hw_format) 18524a63d4cSSven Püschel | FIELD_PREP(RGA3_WIN_YC_SWAP, in->yc_swap) 18624a63d4cSSven Püschel | FIELD_PREP(RGA3_WIN_RBUV_SWAP, in->rbuv_swap) 18724a63d4cSSven Püschel | FIELD_PREP(RGA3_WIN_RD_FORMAT, rd_format) 18824a63d4cSSven Püschel | FIELD_PREP(RGA3_WIN_R2Y, r2y) 18924a63d4cSSven Püschel | FIELD_PREP(RGA3_WIN_Y2R, y2r) 19024a63d4cSSven Püschel | FIELD_PREP(RGA3_WIN_CSC_MODE, csc_mode); 19124a63d4cSSven Püschel 19224a63d4cSSven Püschel /* set stride */ 19324a63d4cSSven Püschel reg = RGA3_WIN0_VIR_STRIDE - RGA3_FIRST_CMD_REG; 19424a63d4cSSven Püschel /* stride needs to be in words */ 19524a63d4cSSven Püschel cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2; 19624a63d4cSSven Püschel reg = RGA3_WIN0_UV_VIR_STRIDE - RGA3_FIRST_CMD_REG; 19724a63d4cSSven Püschel /* The Hardware only supports formats with 1/2 planes */ 19824a63d4cSSven Püschel if (ctx->in.pix.num_planes == 2) 19924a63d4cSSven Püschel cmd[reg >> 2] = ctx->in.pix.plane_fmt[1].bytesperline >> 2; 20024a63d4cSSven Püschel else 20124a63d4cSSven Püschel cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2; 20224a63d4cSSven Püschel 20324a63d4cSSven Püschel /* set size */ 20424a63d4cSSven Püschel reg = RGA3_WIN0_ACT_SIZE - RGA3_FIRST_CMD_REG; 20524a63d4cSSven Püschel cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, act_w) 20624a63d4cSSven Püschel | FIELD_PREP(RGA3_HEIGHT, act_h); 20724a63d4cSSven Püschel reg = RGA3_WIN0_SRC_SIZE - RGA3_FIRST_CMD_REG; 20824a63d4cSSven Püschel cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, src_w) 20924a63d4cSSven Püschel | FIELD_PREP(RGA3_HEIGHT, src_h); 21024a63d4cSSven Püschel } 21124a63d4cSSven Püschel 21224a63d4cSSven Püschel /* Map the output pixel format to the command buffer */ 21324a63d4cSSven Püschel static void rga3_cmd_set_wr_format(struct rga_ctx *ctx) 21424a63d4cSSven Püschel { 21524a63d4cSSven Püschel u32 *cmd = ctx->cmdbuf_virt; 21624a63d4cSSven Püschel const struct rga3_fmt *out = ctx->out.fmt; 21724a63d4cSSven Püschel const struct v4l2_format_info *out_fmt; 21824a63d4cSSven Püschel unsigned int dst_h, dst_w; 21924a63d4cSSven Püschel u8 wr_format; 22024a63d4cSSven Püschel unsigned int reg; 22124a63d4cSSven Püschel 22224a63d4cSSven Püschel dst_h = ctx->out.pix.height; 22324a63d4cSSven Püschel dst_w = ctx->out.pix.width; 22424a63d4cSSven Püschel 22524a63d4cSSven Püschel out_fmt = v4l2_format_info(out->fourcc); 22624a63d4cSSven Püschel 22724a63d4cSSven Püschel /* The Hardware only supports formats with 1/2 planes */ 22824a63d4cSSven Püschel if (out_fmt->comp_planes == 2) 22924a63d4cSSven Püschel wr_format = RGA3_RDWR_FORMAT_SEMI_PLANAR; 23024a63d4cSSven Püschel else 23124a63d4cSSven Püschel wr_format = RGA3_RDWR_FORMAT_INTERLEAVED; 23224a63d4cSSven Püschel 23324a63d4cSSven Püschel /* set pixel format */ 23424a63d4cSSven Püschel reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG; 23524a63d4cSSven Püschel cmd[reg >> 2] = FIELD_PREP(RGA3_WR_PIC_FORMAT, out->hw_format) 23624a63d4cSSven Püschel | FIELD_PREP(RGA3_WR_YC_SWAP, out->yc_swap) 23724a63d4cSSven Püschel | FIELD_PREP(RGA3_WR_RBUV_SWAP, out->rbuv_swap) 23824a63d4cSSven Püschel | FIELD_PREP(RGA3_WR_FORMAT, wr_format) 23924a63d4cSSven Püschel /* Use the max value to avoid limiting the write speed */ 24024a63d4cSSven Püschel | FIELD_PREP(RGA3_WR_SW_OUTSTANDING_MAX, 63); 24124a63d4cSSven Püschel 24224a63d4cSSven Püschel /* set stride */ 24324a63d4cSSven Püschel reg = RGA3_WR_VIR_STRIDE - RGA3_FIRST_CMD_REG; 24424a63d4cSSven Püschel /* stride needs to be in words */ 24524a63d4cSSven Püschel cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2; 24624a63d4cSSven Püschel reg = RGA3_WR_PL_VIR_STRIDE - RGA3_FIRST_CMD_REG; 24724a63d4cSSven Püschel /* The Hardware only supports formats with 1/2 planes */ 24824a63d4cSSven Püschel if (ctx->out.pix.num_planes == 2) 24924a63d4cSSven Püschel cmd[reg >> 2] = ctx->out.pix.plane_fmt[1].bytesperline >> 2; 25024a63d4cSSven Püschel else 25124a63d4cSSven Püschel cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2; 25224a63d4cSSven Püschel 25324a63d4cSSven Püschel /* Set size. 25424a63d4cSSven Püschel * As two inputs are not supported, we don't use win1. 25524a63d4cSSven Püschel * Therefore only set the size for win0. 25624a63d4cSSven Püschel */ 25724a63d4cSSven Püschel reg = RGA3_WIN0_DST_SIZE - RGA3_FIRST_CMD_REG; 25824a63d4cSSven Püschel cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, dst_w) 25924a63d4cSSven Püschel | FIELD_PREP(RGA3_HEIGHT, dst_h); 26024a63d4cSSven Püschel } 26124a63d4cSSven Püschel 26224a63d4cSSven Püschel static void rga3_hw_setup_cmdbuf(struct rga_ctx *ctx) 26324a63d4cSSven Püschel { 26424a63d4cSSven Püschel memset(ctx->cmdbuf_virt, 0, RGA3_CMDBUF_SIZE); 26524a63d4cSSven Püschel 26624a63d4cSSven Püschel rga3_cmd_set_win0_format(ctx); 26724a63d4cSSven Püschel rga3_cmd_set_trans_info(ctx); 26824a63d4cSSven Püschel rga3_cmd_set_wr_format(ctx); 26924a63d4cSSven Püschel } 27024a63d4cSSven Püschel 27124a63d4cSSven Püschel static void rga3_hw_start(struct rockchip_rga *rga, 27224a63d4cSSven Püschel struct rga_vb_buffer *src, struct rga_vb_buffer *dst) 27324a63d4cSSven Püschel { 27424a63d4cSSven Püschel struct rga_ctx *ctx = rga->curr; 27524a63d4cSSven Püschel 27624a63d4cSSven Püschel rga3_cmd_set_win0_addr(ctx, &src->dma_addrs); 27724a63d4cSSven Püschel rga3_cmd_set_wr_addr(ctx, &dst->dma_addrs); 27824a63d4cSSven Püschel 27924a63d4cSSven Püschel rga_write(rga, RGA3_CMD_ADDR, ctx->cmdbuf_phy); 28024a63d4cSSven Püschel 28124a63d4cSSven Püschel /* sync CMD buf for RGA */ 28224a63d4cSSven Püschel dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy, 28324a63d4cSSven Püschel PAGE_SIZE, DMA_BIDIRECTIONAL); 28424a63d4cSSven Püschel 28524a63d4cSSven Püschel /* set to master mode and start the conversion */ 28624a63d4cSSven Püschel rga_write(rga, RGA3_SYS_CTRL, 28724a63d4cSSven Püschel FIELD_PREP(RGA3_CMD_MODE, RGA3_CMD_MODE_MASTER)); 28824a63d4cSSven Püschel rga_write(rga, RGA3_INT_EN, FIELD_PREP(RGA3_INT_FRM_DONE, 1)); 28924a63d4cSSven Püschel rga_write(rga, RGA3_CMD_CTRL, 29024a63d4cSSven Püschel FIELD_PREP(RGA3_CMD_LINE_START_PULSE, 1)); 29124a63d4cSSven Püschel } 29224a63d4cSSven Püschel 29324a63d4cSSven Püschel static bool rga3_handle_irq(struct rockchip_rga *rga) 29424a63d4cSSven Püschel { 29524a63d4cSSven Püschel u32 intr; 29624a63d4cSSven Püschel 29724a63d4cSSven Püschel intr = rga_read(rga, RGA3_INT_RAW); 29824a63d4cSSven Püschel /* clear all interrupts */ 29924a63d4cSSven Püschel rga_write(rga, RGA3_INT_CLR, intr); 30024a63d4cSSven Püschel 30124a63d4cSSven Püschel return FIELD_GET(RGA3_INT_FRM_DONE, intr); 30224a63d4cSSven Püschel } 30324a63d4cSSven Püschel 30424a63d4cSSven Püschel static void rga3_get_version(struct rockchip_rga *rga) 30524a63d4cSSven Püschel { 30624a63d4cSSven Püschel u32 version = rga_read(rga, RGA3_VERSION_NUM); 30724a63d4cSSven Püschel 30824a63d4cSSven Püschel rga->version.major = FIELD_GET(RGA3_VERSION_NUM_MAJOR, version); 30924a63d4cSSven Püschel rga->version.minor = FIELD_GET(RGA3_VERSION_NUM_MINOR, version); 31024a63d4cSSven Püschel } 31124a63d4cSSven Püschel 31224a63d4cSSven Püschel static struct rga3_fmt rga3_formats[] = { 31324a63d4cSSven Püschel { 31424a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_RGB24, 31524a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_BGR888, 31624a63d4cSSven Püschel .rbuv_swap = 1, 31724a63d4cSSven Püschel }, 31824a63d4cSSven Püschel { 31924a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_BGR24, 32024a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_BGR888, 32124a63d4cSSven Püschel }, 32224a63d4cSSven Püschel { 32324a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_ABGR32, 32424a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_BGRA8888, 32524a63d4cSSven Püschel }, 32624a63d4cSSven Püschel { 32724a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_RGBA32, 32824a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_BGRA8888, 32924a63d4cSSven Püschel .rbuv_swap = 1, 33024a63d4cSSven Püschel }, 33124a63d4cSSven Püschel { 33224a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_XBGR32, 33324a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_BGRA8888, 33424a63d4cSSven Püschel }, 33524a63d4cSSven Püschel { 33624a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_RGBX32, 33724a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_BGRA8888, 33824a63d4cSSven Püschel .rbuv_swap = 1, 33924a63d4cSSven Püschel }, 34024a63d4cSSven Püschel { 34124a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_RGB565, 34224a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_BGR565, 34324a63d4cSSven Püschel .rbuv_swap = 1, 34424a63d4cSSven Püschel }, 34524a63d4cSSven Püschel { 34624a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_NV12M, 34724a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_YUV420, 34824a63d4cSSven Püschel }, 34924a63d4cSSven Püschel { 35024a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_NV12, 35124a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_YUV420, 35224a63d4cSSven Püschel }, 35324a63d4cSSven Püschel { 35424a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_NV21M, 35524a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_YUV420, 35624a63d4cSSven Püschel .rbuv_swap = 1, 35724a63d4cSSven Püschel }, 35824a63d4cSSven Püschel { 35924a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_NV21, 36024a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_YUV420, 36124a63d4cSSven Püschel .rbuv_swap = 1, 36224a63d4cSSven Püschel }, 36324a63d4cSSven Püschel { 36424a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_NV16M, 36524a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_YUV422, 36624a63d4cSSven Püschel }, 36724a63d4cSSven Püschel { 36824a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_NV16, 36924a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_YUV422, 37024a63d4cSSven Püschel }, 37124a63d4cSSven Püschel { 37224a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_NV61M, 37324a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_YUV422, 37424a63d4cSSven Püschel .rbuv_swap = 1, 37524a63d4cSSven Püschel }, 37624a63d4cSSven Püschel { 37724a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_NV61, 37824a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_YUV422, 37924a63d4cSSven Püschel .rbuv_swap = 1, 38024a63d4cSSven Püschel }, 38124a63d4cSSven Püschel { 38224a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_YUYV, 38324a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_YUV422, 38424a63d4cSSven Püschel .yc_swap = 1, 38524a63d4cSSven Püschel }, 38624a63d4cSSven Püschel { 38724a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_YVYU, 38824a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_YUV422, 38924a63d4cSSven Püschel .yc_swap = 1, 39024a63d4cSSven Püschel .rbuv_swap = 1, 39124a63d4cSSven Püschel }, 39224a63d4cSSven Püschel { 39324a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_UYVY, 39424a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_YUV422, 39524a63d4cSSven Püschel }, 39624a63d4cSSven Püschel { 39724a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_VYUY, 39824a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_YUV422, 39924a63d4cSSven Püschel .rbuv_swap = 1, 40024a63d4cSSven Püschel }, 40124a63d4cSSven Püschel /* Input only formats last to keep rga3_enum_format simple */ 40224a63d4cSSven Püschel { 40324a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_ARGB32, 40424a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_ABGR8888, 40524a63d4cSSven Püschel .rbuv_swap = 1, 40624a63d4cSSven Püschel }, 40724a63d4cSSven Püschel { 40824a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_BGRA32, 40924a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_ABGR8888, 41024a63d4cSSven Püschel }, 41124a63d4cSSven Püschel { 41224a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_XRGB32, 41324a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_ABGR8888, 41424a63d4cSSven Püschel .rbuv_swap = 1, 41524a63d4cSSven Püschel }, 41624a63d4cSSven Püschel { 41724a63d4cSSven Püschel .fourcc = V4L2_PIX_FMT_BGRX32, 41824a63d4cSSven Püschel .hw_format = RGA3_COLOR_FMT_ABGR8888, 41924a63d4cSSven Püschel }, 42024a63d4cSSven Püschel }; 42124a63d4cSSven Püschel 42224a63d4cSSven Püschel static int rga3_enum_format(struct v4l2_fmtdesc *f) 42324a63d4cSSven Püschel { 42424a63d4cSSven Püschel struct rga3_fmt *fmt; 42524a63d4cSSven Püschel 42624a63d4cSSven Püschel if (f->index >= ARRAY_SIZE(rga3_formats)) 42724a63d4cSSven Püschel return -EINVAL; 42824a63d4cSSven Püschel 42924a63d4cSSven Püschel fmt = &rga3_formats[f->index]; 43024a63d4cSSven Püschel if (V4L2_TYPE_IS_CAPTURE(f->type) && !rga3_can_capture(fmt)) 43124a63d4cSSven Püschel return -EINVAL; 43224a63d4cSSven Püschel 43324a63d4cSSven Püschel f->pixelformat = fmt->fourcc; 43424a63d4cSSven Püschel return 0; 43524a63d4cSSven Püschel } 43624a63d4cSSven Püschel 43724a63d4cSSven Püschel static void *rga3_adjust_and_map_format(struct rga_ctx *ctx, 43824a63d4cSSven Püschel struct v4l2_pix_format_mplane *format, 43924a63d4cSSven Püschel bool is_output) 44024a63d4cSSven Püschel { 44124a63d4cSSven Püschel unsigned int i; 44224a63d4cSSven Püschel const struct v4l2_format_info *format_info; 44324a63d4cSSven Püschel const struct v4l2_pix_format_mplane *other_format; 44424a63d4cSSven Püschel const struct v4l2_format_info *other_format_info; 44524a63d4cSSven Püschel 44624a63d4cSSven Püschel if (!format) 44724a63d4cSSven Püschel return &rga3_formats[0]; 44824a63d4cSSven Püschel 44924a63d4cSSven Püschel format_info = v4l2_format_info(format->pixelformat); 45024a63d4cSSven Püschel other_format = is_output ? &ctx->out.pix : &ctx->in.pix; 45124a63d4cSSven Püschel other_format_info = v4l2_format_info(other_format->pixelformat); 45224a63d4cSSven Püschel 453*7acc334cSSven Püschel /* 454*7acc334cSSven Püschel * Only apply the quantization restrictions when we need to 455*7acc334cSSven Püschel * convert between RGB and YUV. Otherwise there is no point 456*7acc334cSSven Püschel * to limit the quantization for operations like scaling or 457*7acc334cSSven Püschel * rotations. 458*7acc334cSSven Püschel */ 459*7acc334cSSven Püschel if (v4l2_is_format_yuv(format_info) && 460*7acc334cSSven Püschel v4l2_is_format_rgb(other_format_info)) { 46124a63d4cSSven Püschel /* 46224a63d4cSSven Püschel * The RGA3 only supports BT601, BT709 and BT2020 RGB<->YUV conversions 46324a63d4cSSven Püschel * Additionally BT709 and BT2020 only support limited range YUV. 46424a63d4cSSven Püschel */ 46524a63d4cSSven Püschel switch (format->ycbcr_enc) { 46624a63d4cSSven Püschel case V4L2_YCBCR_ENC_601: 46724a63d4cSSven Püschel /* supports full and limited range */ 46824a63d4cSSven Püschel break; 46924a63d4cSSven Püschel case V4L2_YCBCR_ENC_709: 47024a63d4cSSven Püschel case V4L2_YCBCR_ENC_BT2020: 47124a63d4cSSven Püschel format->quantization = V4L2_QUANTIZATION_LIM_RANGE; 47224a63d4cSSven Püschel break; 47324a63d4cSSven Püschel default: 47424a63d4cSSven Püschel format->ycbcr_enc = V4L2_YCBCR_ENC_601; 47524a63d4cSSven Püschel format->quantization = V4L2_QUANTIZATION_FULL_RANGE; 47624a63d4cSSven Püschel break; 47724a63d4cSSven Püschel } 47824a63d4cSSven Püschel } 47924a63d4cSSven Püschel 48024a63d4cSSven Püschel for (i = 0; i < ARRAY_SIZE(rga3_formats); i++) { 48124a63d4cSSven Püschel if (!is_output && !rga3_can_capture(&rga3_formats[i])) 48224a63d4cSSven Püschel continue; 48324a63d4cSSven Püschel 48424a63d4cSSven Püschel if (rga3_formats[i].fourcc == format->pixelformat) 48524a63d4cSSven Püschel return &rga3_formats[i]; 48624a63d4cSSven Püschel } 48724a63d4cSSven Püschel 48824a63d4cSSven Püschel format->pixelformat = rga3_formats[0].fourcc; 48924a63d4cSSven Püschel return &rga3_formats[0]; 49024a63d4cSSven Püschel } 49124a63d4cSSven Püschel 49224a63d4cSSven Püschel const struct rga_hw rga3_hw = { 49324a63d4cSSven Püschel .card_type = "rga3", 49424a63d4cSSven Püschel .has_internal_iommu = false, 49524a63d4cSSven Püschel .cmdbuf_size = RGA3_CMDBUF_SIZE, 49624a63d4cSSven Püschel .min_width = RGA3_MIN_WIDTH, 49724a63d4cSSven Püschel .min_height = RGA3_MIN_HEIGHT, 49824a63d4cSSven Püschel /* use output size, as it's a bit smaller than the input size */ 49924a63d4cSSven Püschel .max_width = RGA3_MAX_OUTPUT_WIDTH, 50024a63d4cSSven Püschel .max_height = RGA3_MAX_OUTPUT_HEIGHT, 50124a63d4cSSven Püschel .max_scaling_factor = RGA3_MAX_SCALING_FACTOR, 50224a63d4cSSven Püschel .stride_alignment = 16, 50324a63d4cSSven Püschel .features = 0, 50424a63d4cSSven Püschel 50524a63d4cSSven Püschel .setup_cmdbuf = rga3_hw_setup_cmdbuf, 50624a63d4cSSven Püschel .start = rga3_hw_start, 50724a63d4cSSven Püschel .handle_irq = rga3_handle_irq, 50824a63d4cSSven Püschel .get_version = rga3_get_version, 50924a63d4cSSven Püschel .enum_format = rga3_enum_format, 51024a63d4cSSven Püschel .adjust_and_map_format = rga3_adjust_and_map_format, 51124a63d4cSSven Püschel }; 512