From 6778948f9de86c3cfaf36725a7c87dcff9ba247f Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 08:20:59 +0000 Subject: [PATCH] kernel_5.10 no rt --- kernel/drivers/media/platform/rcar-vin/rcar-dma.c | 272 ++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 213 insertions(+), 59 deletions(-) diff --git a/kernel/drivers/media/platform/rcar-vin/rcar-dma.c b/kernel/drivers/media/platform/rcar-vin/rcar-dma.c index 70a8cc4..692dea3 100644 --- a/kernel/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/kernel/drivers/media/platform/rcar-vin/rcar-dma.c @@ -85,6 +85,7 @@ #define VNMC_INF_YUV8_BT601 (1 << 16) #define VNMC_INF_YUV10_BT656 (2 << 16) #define VNMC_INF_YUV10_BT601 (3 << 16) +#define VNMC_INF_RAW8 (4 << 16) #define VNMC_INF_YUV16 (5 << 16) #define VNMC_INF_RGB888 (6 << 16) #define VNMC_VUP (1 << 10) @@ -111,15 +112,20 @@ #define VNIE_EFE (1 << 1) /* Video n Data Mode Register bits */ +#define VNDMR_A8BIT(n) (((n) & 0xff) << 24) +#define VNDMR_A8BIT_MASK (0xff << 24) #define VNDMR_EXRGB (1 << 8) #define VNDMR_BPSM (1 << 4) +#define VNDMR_ABIT (1 << 2) #define VNDMR_DTMD_YCSEP (1 << 1) -#define VNDMR_DTMD_ARGB1555 (1 << 0) +#define VNDMR_DTMD_ARGB (1 << 0) +#define VNDMR_DTMD_YCSEP_420 (3 << 0) /* Video n Data Mode Register 2 bits */ #define VNDMR2_VPS (1 << 30) #define VNDMR2_HPS (1 << 29) #define VNDMR2_CES (1 << 28) +#define VNDMR2_YDS (1 << 22) #define VNDMR2_FTEV (1 << 17) #define VNDMR2_VLV(n) ((n & 0xf) << 12) @@ -486,7 +492,7 @@ } /* Use previous value if its XS value is closer */ - if (p_prev_set && p_set && + if (p_prev_set && xs - p_prev_set->xs_value < p_set->xs_value - xs) p_set = p_prev_set; @@ -526,12 +532,17 @@ static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin) { + unsigned int crop_height; u32 xs, ys; /* Set scaling coefficient */ + crop_height = vin->crop.height; + if (V4L2_FIELD_HAS_BOTH(vin->format.field)) + crop_height *= 2; + ys = 0; - if (vin->crop.height != vin->compose.height) - ys = (4096 * vin->crop.height) / vin->compose.height; + if (crop_height != vin->compose.height) + ys = (4096 * crop_height) / vin->compose.height; rvin_write(vin, ys, VNYS_REG); xs = 0; @@ -554,16 +565,11 @@ rvin_write(vin, 0, VNSPPOC_REG); rvin_write(vin, 0, VNSLPOC_REG); rvin_write(vin, vin->format.width - 1, VNEPPOC_REG); - switch (vin->format.field) { - case V4L2_FIELD_INTERLACED: - case V4L2_FIELD_INTERLACED_TB: - case V4L2_FIELD_INTERLACED_BT: + + if (V4L2_FIELD_HAS_BOTH(vin->format.field)) rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG); - break; - default: + else rvin_write(vin, vin->format.height - 1, VNELPOC_REG); - break; - } vin_dbg(vin, "Pre-Clip: %ux%u@%u:%u YS: %d XS: %d Post-Clip: %ux%u@%u:%u\n", @@ -574,33 +580,37 @@ void rvin_crop_scale_comp(struct rvin_dev *vin) { + const struct rvin_video_format *fmt; + u32 stride; + /* Set Start/End Pixel/Line Pre-Clip */ rvin_write(vin, vin->crop.left, VNSPPRC_REG); rvin_write(vin, vin->crop.left + vin->crop.width - 1, VNEPPRC_REG); - - switch (vin->format.field) { - case V4L2_FIELD_INTERLACED: - case V4L2_FIELD_INTERLACED_TB: - case V4L2_FIELD_INTERLACED_BT: - rvin_write(vin, vin->crop.top / 2, VNSLPRC_REG); - rvin_write(vin, (vin->crop.top + vin->crop.height) / 2 - 1, - VNELPRC_REG); - break; - default: - rvin_write(vin, vin->crop.top, VNSLPRC_REG); - rvin_write(vin, vin->crop.top + vin->crop.height - 1, - VNELPRC_REG); - break; - } + rvin_write(vin, vin->crop.top, VNSLPRC_REG); + rvin_write(vin, vin->crop.top + vin->crop.height - 1, VNELPRC_REG); /* TODO: Add support for the UDS scaler. */ if (vin->info->model != RCAR_GEN3) rvin_crop_scale_comp_gen2(vin); - if (vin->format.pixelformat == V4L2_PIX_FMT_NV16) - rvin_write(vin, ALIGN(vin->format.width, 0x20), VNIS_REG); - else - rvin_write(vin, ALIGN(vin->format.width, 0x10), VNIS_REG); + fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); + stride = vin->format.bytesperline / fmt->bpp; + + /* For RAW8 format bpp is 1, but the hardware process RAW8 + * format in 2 pixel unit hence configure VNIS_REG as stride / 2. + */ + switch (vin->format.pixelformat) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + stride /= 2; + break; + default: + break; + } + + rvin_write(vin, stride, VNIS_REG); } /* ----------------------------------------------------------------------------- @@ -632,9 +642,14 @@ case V4L2_FIELD_INTERLACED_BT: vnmc = VNMC_IM_FULL | VNMC_FOC; break; + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: case V4L2_FIELD_NONE: vnmc = VNMC_IM_ODD_EVEN; progressive = true; + break; + case V4L2_FIELD_ALTERNATE: + vnmc = VNMC_IM_ODD_EVEN; break; default: vnmc = VNMC_IM_ODD; @@ -677,11 +692,17 @@ input_is_yuv = true; break; + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + vnmc |= VNMC_INF_RAW8; + break; default: break; } - /* Enable VSYNC Field Toogle mode after one VSYNC input */ + /* Enable VSYNC Field Toggle mode after one VSYNC input */ if (vin->info->model == RCAR_GEN3) dmr2 = VNDMR2_FTEV; else @@ -689,27 +710,39 @@ if (!vin->is_csi) { /* Hsync Signal Polarity Select */ - if (!(vin->parallel->mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) + if (!(vin->parallel->bus.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) dmr2 |= VNDMR2_HPS; /* Vsync Signal Polarity Select */ - if (!(vin->parallel->mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) + if (!(vin->parallel->bus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) dmr2 |= VNDMR2_VPS; /* Data Enable Polarity Select */ - if (vin->parallel->mbus_flags & V4L2_MBUS_DATA_ENABLE_LOW) + if (vin->parallel->bus.flags & V4L2_MBUS_DATA_ENABLE_LOW) dmr2 |= VNDMR2_CES; + + switch (vin->mbus_code) { + case MEDIA_BUS_FMT_UYVY8_2X8: + if (vin->parallel->bus.bus_width == 8 && + vin->parallel->bus.data_shift == 8) + dmr2 |= VNDMR2_YDS; + break; + default: + break; + } } /* * Output format */ switch (vin->format.pixelformat) { + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV16: rvin_write(vin, - ALIGN(vin->format.width * vin->format.height, 0x80), - VNUVAOF_REG); - dmr = VNDMR_DTMD_YCSEP; + ALIGN(vin->format.bytesperline * vin->format.height, + 0x80), VNUVAOF_REG); + dmr = vin->format.pixelformat == V4L2_PIX_FMT_NV12 ? + VNDMR_DTMD_YCSEP_420 : VNDMR_DTMD_YCSEP; output_is_yuv = true; break; case V4L2_PIX_FMT_YUYV: @@ -721,7 +754,7 @@ output_is_yuv = true; break; case V4L2_PIX_FMT_XRGB555: - dmr = VNDMR_DTMD_ARGB1555; + dmr = VNDMR_DTMD_ARGB; break; case V4L2_PIX_FMT_RGB565: dmr = 0; @@ -729,6 +762,18 @@ case V4L2_PIX_FMT_XBGR32: /* Note: not supported on M1 */ dmr = VNDMR_EXRGB; + break; + case V4L2_PIX_FMT_ARGB555: + dmr = (vin->alpha ? VNDMR_ABIT : 0) | VNDMR_DTMD_ARGB; + break; + case V4L2_PIX_FMT_ABGR32: + dmr = VNDMR_A8BIT(vin->alpha) | VNDMR_EXRGB | VNDMR_DTMD_ARGB; + break; + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + dmr = 0; break; default: vin_err(vin, "Invalid pixelformat (0x%x)\n", @@ -788,13 +833,25 @@ return rvin_read(vin, VNMS_REG) & VNMS_CA; } +static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms) +{ + if (vin->format.field == V4L2_FIELD_ALTERNATE) { + /* If FS is set it is an Even field. */ + if (vnms & VNMS_FS) + return V4L2_FIELD_BOTTOM; + return V4L2_FIELD_TOP; + } + + return vin->format.field; +} + static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr) { const struct rvin_video_format *fmt; int offsetx, offsety; dma_addr_t offset; - fmt = rvin_format_from_pixel(vin->format.pixelformat); + fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); /* * There is no HW support for composition do the beast we can @@ -825,33 +882,63 @@ struct rvin_buffer *buf; struct vb2_v4l2_buffer *vbuf; dma_addr_t phys_addr; + int prev; /* A already populated slot shall never be overwritten. */ - if (WARN_ON(vin->queue_buf[slot] != NULL)) + if (WARN_ON(vin->buf_hw[slot].buffer)) return; - vin_dbg(vin, "Filling HW slot: %d\n", slot); + prev = (slot == 0 ? HW_BUFFER_NUM : slot) - 1; - if (list_empty(&vin->buf_list)) { - vin->queue_buf[slot] = NULL; + if (vin->buf_hw[prev].type == HALF_TOP) { + vbuf = vin->buf_hw[prev].buffer; + vin->buf_hw[slot].buffer = vbuf; + vin->buf_hw[slot].type = HALF_BOTTOM; + switch (vin->format.pixelformat) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV16: + phys_addr = vin->buf_hw[prev].phys + + vin->format.sizeimage / 4; + break; + default: + phys_addr = vin->buf_hw[prev].phys + + vin->format.sizeimage / 2; + break; + } + } else if (list_empty(&vin->buf_list)) { + vin->buf_hw[slot].buffer = NULL; + vin->buf_hw[slot].type = FULL; phys_addr = vin->scratch_phys; } else { /* Keep track of buffer we give to HW */ buf = list_entry(vin->buf_list.next, struct rvin_buffer, list); vbuf = &buf->vb; list_del_init(to_buf_list(vbuf)); - vin->queue_buf[slot] = vbuf; + vin->buf_hw[slot].buffer = vbuf; + + vin->buf_hw[slot].type = + V4L2_FIELD_IS_SEQUENTIAL(vin->format.field) ? + HALF_TOP : FULL; /* Setup DMA */ phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); } + vin_dbg(vin, "Filling HW slot: %d type: %d buffer: %p\n", + slot, vin->buf_hw[slot].type, vin->buf_hw[slot].buffer); + + vin->buf_hw[slot].phys = phys_addr; rvin_set_slot_addr(vin, slot, phys_addr); } static int rvin_capture_start(struct rvin_dev *vin) { int slot, ret; + + for (slot = 0; slot < HW_BUFFER_NUM; slot++) { + vin->buf_hw[slot].buffer = NULL; + vin->buf_hw[slot].type = FULL; + } for (slot = 0; slot < HW_BUFFER_NUM; slot++) rvin_fill_hw_slot(vin, slot); @@ -936,13 +1023,24 @@ } /* Capture frame */ - if (vin->queue_buf[slot]) { - vin->queue_buf[slot]->field = vin->format.field; - vin->queue_buf[slot]->sequence = vin->sequence; - vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); - vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, + if (vin->buf_hw[slot].buffer) { + /* + * Nothing to do but refill the hardware slot if + * capture only filled first half of vb2 buffer. + */ + if (vin->buf_hw[slot].type == HALF_TOP) { + vin->buf_hw[slot].buffer = NULL; + rvin_fill_hw_slot(vin, slot); + goto done; + } + + vin->buf_hw[slot].buffer->field = + rvin_get_active_field(vin, vnms); + vin->buf_hw[slot].buffer->sequence = vin->sequence; + vin->buf_hw[slot].buffer->vb2_buf.timestamp = ktime_get_ns(); + vb2_buffer_done(&vin->buf_hw[slot].buffer->vb2_buf, VB2_BUF_STATE_DONE); - vin->queue_buf[slot] = NULL; + vin->buf_hw[slot].buffer = NULL; } else { /* Scratch buffer was used, dropping frame. */ vin_dbg(vin, "Dropping frame %u\n", vin->sequence); @@ -963,14 +1061,22 @@ enum vb2_buffer_state state) { struct rvin_buffer *buf, *node; - int i; + struct vb2_v4l2_buffer *freed[HW_BUFFER_NUM]; + unsigned int i, n; for (i = 0; i < HW_BUFFER_NUM; i++) { - if (vin->queue_buf[i]) { - vb2_buffer_done(&vin->queue_buf[i]->vb2_buf, - state); - vin->queue_buf[i] = NULL; + freed[i] = vin->buf_hw[i].buffer; + vin->buf_hw[i].buffer = NULL; + + for (n = 0; n < i; n++) { + if (freed[i] == freed[n]) { + freed[i] = NULL; + break; + } } + + if (freed[i]) + vb2_buffer_done(&freed[i]->vb2_buf, state); } list_for_each_entry_safe(buf, node, &vin->buf_list, list) { @@ -1042,11 +1148,27 @@ case MEDIA_BUS_FMT_UYVY8_2X8: case MEDIA_BUS_FMT_UYVY10_2X10: case MEDIA_BUS_FMT_RGB888_1X24: - vin->mbus_code = fmt.format.code; + break; + case MEDIA_BUS_FMT_SBGGR8_1X8: + if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR8) + return -EPIPE; + break; + case MEDIA_BUS_FMT_SGBRG8_1X8: + if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG8) + return -EPIPE; + break; + case MEDIA_BUS_FMT_SGRBG8_1X8: + if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG8) + return -EPIPE; + break; + case MEDIA_BUS_FMT_SRGGB8_1X8: + if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB8) + return -EPIPE; break; default: return -EPIPE; } + vin->mbus_code = fmt.format.code; switch (fmt.format.field) { case V4L2_FIELD_TOP: @@ -1064,6 +1186,7 @@ case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: case V4L2_FIELD_NONE: + case V4L2_FIELD_ALTERNATE: break; case V4L2_FIELD_INTERLACED_TB: case V4L2_FIELD_INTERLACED_BT: @@ -1273,7 +1396,7 @@ vin->state = STOPPED; for (i = 0; i < HW_BUFFER_NUM; i++) - vin->queue_buf[i] = NULL; + vin->buf_hw[i].buffer = NULL; /* buffer queue */ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -1343,5 +1466,36 @@ pm_runtime_put(vin->dev); - return ret; + return 0; +} + +void rvin_set_alpha(struct rvin_dev *vin, unsigned int alpha) +{ + unsigned long flags; + u32 dmr; + + spin_lock_irqsave(&vin->qlock, flags); + + vin->alpha = alpha; + + if (vin->state == STOPPED) + goto out; + + switch (vin->format.pixelformat) { + case V4L2_PIX_FMT_ARGB555: + dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_ABIT; + if (vin->alpha) + dmr |= VNDMR_ABIT; + break; + case V4L2_PIX_FMT_ABGR32: + dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_A8BIT_MASK; + dmr |= VNDMR_A8BIT(vin->alpha); + break; + default: + goto out; + } + + rvin_write(vin, dmr, VNDMR_REG); +out: + spin_unlock_irqrestore(&vin->qlock, flags); } -- Gitblit v1.6.2