/* Register offsets for R-Car VIN */ #define VNMC_REG 0x00 /* Video n Main Control Register */ #define VNMS_REG 0x04 /* Video n Module Status Register */ #define VNFC_REG 0x08 /* Video n Frame Capture Register */ #define VNSLPRC_REG 0x0C /* Video n Start Line Pre-Clip Register */ #define VNELPRC_REG 0x10 /* Video n End Line Pre-Clip Register */ #define VNSPPRC_REG 0x14 /* Video n Start Pixel Pre-Clip Register */ #define VNEPPRC_REG 0x18 /* Video n End Pixel Pre-Clip Register */ #define VNIS_REG 0x2C /* Video n Image Stride Register */ #define VNMB_REG(m) (0x30 + ((m) << 2)) /* Video n Memory Base m Register */ #define VNIE_REG 0x40 /* Video n Interrupt Enable Register */ #define VNINTS_REG 0x44 /* Video n Interrupt Status Register */ #define VNSI_REG 0x48 /* Video n Scanline Interrupt Register */ #define VNMTC_REG 0x4C /* Video n Memory Transfer Control Register */ #define VNDMR_REG 0x58 /* Video n Data Mode Register */ #define VNDMR2_REG 0x5C /* Video n Data Mode Register 2 */ #define VNUVAOF_REG 0x60 /* Video n UV Address Offset Register */
/* Register offsets specific for Gen2 */ #define VNSLPOC_REG 0x1C /* Video n Start Line Post-Clip Register */ #define VNELPOC_REG 0x20 /* Video n End Line Post-Clip Register */ #define VNSPPOC_REG 0x24 /* Video n Start Pixel Post-Clip Register */ #define VNEPPOC_REG 0x28 /* Video n End Pixel Post-Clip Register */ #define VNYS_REG 0x50 /* Video n Y Scale Register */ #define VNXS_REG 0x54 /* Video n X Scale Register */ #define VNC1A_REG 0x80 /* Video n Coefficient Set C1A Register */ #define VNC1B_REG 0x84 /* Video n Coefficient Set C1B Register */ #define VNC1C_REG 0x88 /* Video n Coefficient Set C1C Register */ #define VNC2A_REG 0x90 /* Video n Coefficient Set C2A Register */ #define VNC2B_REG 0x94 /* Video n Coefficient Set C2B Register */ #define VNC2C_REG 0x98 /* Video n Coefficient Set C2C Register */ #define VNC3A_REG 0xA0 /* Video n Coefficient Set C3A Register */ #define VNC3B_REG 0xA4 /* Video n Coefficient Set C3B Register */ #define VNC3C_REG 0xA8 /* Video n Coefficient Set C3C Register */ #define VNC4A_REG 0xB0 /* Video n Coefficient Set C4A Register */ #define VNC4B_REG 0xB4 /* Video n Coefficient Set C4B Register */ #define VNC4C_REG 0xB8 /* Video n Coefficient Set C4C Register */ #define VNC5A_REG 0xC0 /* Video n Coefficient Set C5A Register */ #define VNC5B_REG 0xC4 /* Video n Coefficient Set C5B Register */ #define VNC5C_REG 0xC8 /* Video n Coefficient Set C5C Register */ #define VNC6A_REG 0xD0 /* Video n Coefficient Set C6A Register */ #define VNC6B_REG 0xD4 /* Video n Coefficient Set C6B Register */ #define VNC6C_REG 0xD8 /* Video n Coefficient Set C6C Register */ #define VNC7A_REG 0xE0 /* Video n Coefficient Set C7A Register */ #define VNC7B_REG 0xE4 /* Video n Coefficient Set C7B Register */ #define VNC7C_REG 0xE8 /* Video n Coefficient Set C7C Register */ #define VNC8A_REG 0xF0 /* Video n Coefficient Set C8A Register */ #define VNC8B_REG 0xF4 /* Video n Coefficient Set C8B Register */ #define VNC8C_REG 0xF8 /* Video n Coefficient Set C8C Register */
/* Register offsets specific for Gen3 */ #define VNCSI_IFMD_REG 0x20 /* Video n CSI2 Interface Mode Register */ #define VNUDS_CTRL_REG 0x80 /* Video n scaling control register */ #define VNUDS_SCALE_REG 0x84 /* Video n scaling factor register */ #define VNUDS_PASS_BWIDTH_REG 0x90 /* Video n passband register */ #define VNUDS_CLIP_SIZE_REG 0xa4 /* Video n UDS output size clipping reg */
input_is_yuv = true; break; case MEDIA_BUS_FMT_RGB888_1X24:
vnmc |= VNMC_INF_RGB888; break; case MEDIA_BUS_FMT_UYVY10_2X10: /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ if (!vin->is_csi &&
vin->parallel.mbus_type == V4L2_MBUS_BT656)
vnmc |= VNMC_INF_YUV10_BT656; else
vnmc |= VNMC_INF_YUV10_BT601;
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: case MEDIA_BUS_FMT_Y8_1X8:
vnmc |= VNMC_INF_RAW8; if (vin->info->model == RCAR_GEN4)
vnmc |= VNMC_EXINF_RAW8; break; case MEDIA_BUS_FMT_SBGGR10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SRGGB10_1X10:
vnmc |= VNMC_INF_RGB666; break; default: break;
}
/* Enable VSYNC Field Toggle mode after one VSYNC input */ if (vin->info->model == RCAR_GEN3 || vin->info->model == RCAR_GEN4)
dmr2 = VNDMR2_FTEV; else
dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1);
if (!vin->is_csi) { /* Hsync Signal Polarity Select */ if (!(vin->parallel.bus.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
dmr2 |= VNDMR2_HPS;
/* Vsync Signal Polarity Select */ if (!(vin->parallel.bus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
dmr2 |= VNDMR2_VPS;
/* Data Enable Polarity Select */ if (vin->parallel.bus.flags & V4L2_MBUS_DATA_ENABLE_LOW)
dmr2 |= VNDMR2_CES;
staticenum 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;
}
staticvoid rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr)
{ conststruct rvin_video_format *fmt; int offsetx, offsety;
dma_addr_t offset;
/* * There is no HW support for composition do the beast we can * by modifying the buffer offset
*/
offsetx = vin->compose.left * fmt->bpp;
offsety = vin->compose.top * vin->format.bytesperline;
offset = addr + offsetx + offsety;
/* * The address needs to be 128 bytes aligned. Driver should never accept * settings that do not satisfy this in the first place...
*/ if (WARN_ON((offsetx | offsety | offset) & HW_BUFFER_MASK)) return;
rvin_write(vin, offset, VNMB_REG(slot));
}
/* * Moves a buffer from the queue to the HW slot. If no buffer is * available use the scratch buffer. The scratch buffer is never * returned to userspace, its only function is to enable the capture * loop to keep running.
*/ staticvoid rvin_fill_hw_slot(struct rvin_dev *vin, int slot)
{ struct rvin_buffer *buf; struct vb2_v4l2_buffer *vbuf;
dma_addr_t phys_addr;
/* A already populated slot shall never be overwritten. */ if (WARN_ON(vin->buf_hw[slot].buffer)) return;
if (list_empty(&vin->buf_list)) {
vin->buf_hw[slot].buffer = NULL;
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->buf_hw[slot].buffer = vbuf;
status = rvin_read(vin, VNINTS_REG); if (!status) goto done;
rvin_write(vin, status, VNINTS_REG);
handled = 1;
/* Signal Start of Frame. */ if (status & VNINTS_VRS) { struct v4l2_event event = {
.type = V4L2_EVENT_FRAME_SYNC,
.u.frame_sync.frame_sequence = vin->sequence,
};
v4l2_event_queue(&vin->vdev, &event);
}
/* Nothing to do if nothing was captured. */
capture = vin->format.field == V4L2_FIELD_NONE ||
vin->format.field == V4L2_FIELD_ALTERNATE ?
VNINTS_FIS : VNINTS_EFS; if (!(status & capture)) goto done;
/* Nothing to do if not running. */ if (!vin->running) {
vin_dbg(vin, "IRQ while not running, ignoring\n"); goto done;
}
/* Prepare for capture and update state */
vnms = rvin_read(vin, VNMS_REG);
slot = (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT;
/* * To hand buffers back in a known order to userspace start * to capture first from slot 0.
*/ if (!vin->sequence) { if (slot != 0) {
vin_dbg(vin, "Starting sync slot: %d\n", slot); goto done;
}
switch (fmt.format.code) { case MEDIA_BUS_FMT_YUYV8_1X16: case MEDIA_BUS_FMT_UYVY8_1X16: case MEDIA_BUS_FMT_UYVY8_2X8: case MEDIA_BUS_FMT_UYVY10_2X10: case MEDIA_BUS_FMT_RGB888_1X24: 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; case MEDIA_BUS_FMT_Y8_1X8: if (vin->format.pixelformat != V4L2_PIX_FMT_GREY) return -EPIPE; break; case MEDIA_BUS_FMT_SBGGR10_1X10: if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR10) return -EPIPE; break; case MEDIA_BUS_FMT_SGBRG10_1X10: if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG10) return -EPIPE; break; case MEDIA_BUS_FMT_SGRBG10_1X10: if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG10) return -EPIPE; break; case MEDIA_BUS_FMT_SRGGB10_1X10: if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB10) return -EPIPE; break; default: return -EPIPE;
}
vin->mbus_code = fmt.format.code;
switch (fmt.format.field) { case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: case V4L2_FIELD_NONE: case V4L2_FIELD_INTERLACED_TB: case V4L2_FIELD_INTERLACED_BT: case V4L2_FIELD_INTERLACED: /* Supported natively */ break; case V4L2_FIELD_ALTERNATE: switch (vin->format.field) { 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: case V4L2_FIELD_INTERLACED: /* Use VIN hardware to combine the two fields */
fmt.format.height *= 2; break; default: return -EPIPE;
} break; default: return -EPIPE;
}
/* Return unprocessed buffers from hardware. */ for (unsignedint i = 0; i < HW_BUFFER_NUM; i++) { if (vin->buf_hw[i].buffer)
vb2_buffer_done(&vin->buf_hw[i].buffer->vb2_buf,
VB2_BUF_STATE_ERROR);
}
/* * There is no need to have locking around changing the routing * as it's only possible to do so when no VIN in the group is * streaming so nothing can race with the VNMC register.
*/ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel)
{ conststruct rvin_group_route *route;
u32 ifmd = 0;
u32 vnmc; int ret;
ret = pm_runtime_resume_and_get(vin->dev); if (ret < 0) return ret;
/* Make register writes take effect immediately. */
vnmc = rvin_read(vin, VNMC_REG);
rvin_write(vin, vnmc & ~VNMC_VUP, VNMC_REG);
/* * Set data expansion mode to "pad with 0s" by inspecting the routes * table to find out which bit fields are available in the IFMD * register. IFMD_DES1 controls data expansion mode for CSI20/21, * IFMD_DES0 controls data expansion mode for CSI40/41.
*/ for (route = vin->info->routes; route->chsel; route++) { if (route->csi == RVIN_CSI20 || route->csi == RVIN_CSI21)
ifmd |= VNCSI_IFMD_DES1; else
ifmd |= VNCSI_IFMD_DES0;
if (ifmd == (VNCSI_IFMD_DES0 | VNCSI_IFMD_DES1)) break;
}
if (ifmd) {
ifmd |= VNCSI_IFMD_CSI_CHSEL(chsel);
rvin_write(vin, ifmd, VNCSI_IFMD_REG);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.