diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c index fca2176672c5..5e53d6b7036c 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c @@ -1180,6 +1180,7 @@ static const struct rvin_info rcar_info_r8a7795 = { .max_width = 4096, .max_height = 4096, .routes = rcar_info_r8a7795_routes, + .scaler = rvin_scaler_gen3, }; static const struct rvin_group_route rcar_info_r8a7795es1_routes[] = { @@ -1215,6 +1216,7 @@ static const struct rvin_info rcar_info_r8a7796 = { .max_width = 4096, .max_height = 4096, .routes = rcar_info_r8a7796_routes, + .scaler = rvin_scaler_gen3, }; static const struct rvin_group_route rcar_info_r8a77965_routes[] = { @@ -1232,6 +1234,7 @@ static const struct rvin_info rcar_info_r8a77965 = { .max_width = 4096, .max_height = 4096, .routes = rcar_info_r8a77965_routes, + .scaler = rvin_scaler_gen3, }; static const struct rvin_group_route rcar_info_r8a77970_routes[] = { @@ -1274,6 +1277,7 @@ static const struct rvin_info rcar_info_r8a77990 = { .max_width = 4096, .max_height = 4096, .routes = rcar_info_r8a77990_routes, + .scaler = rvin_scaler_gen3, }; static const struct rvin_group_route rcar_info_r8a77995_routes[] = { @@ -1287,6 +1291,7 @@ static const struct rvin_info rcar_info_r8a77995 = { .max_width = 4096, .max_height = 4096, .routes = rcar_info_r8a77995_routes, + .scaler = rvin_scaler_gen3, }; static const struct rvin_info rcar_info_r8a779a0 = { @@ -1415,6 +1420,10 @@ static int rcar_vin_probe(struct platform_device *pdev) ret = rvin_isp_init(vin); } else if (vin->info->use_mc) { ret = rvin_csi2_init(vin); + + if (vin->info->scaler && + rvin_group_id_to_master(vin->id) == vin->id) + vin->scaler = vin->info->scaler; } else { ret = rvin_parallel_init(vin); diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c index 48241bf6fb1b..98bfd445a649 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c @@ -74,6 +74,10 @@ /* 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 */ /* Register bit fields for R-Car VIN */ /* Video n Main Control Register bits */ @@ -140,6 +144,9 @@ #define VNCSI_IFMD_DES0 (1 << 25) #define VNCSI_IFMD_CSI_CHSEL(n) (((n) & 0xf) << 0) +/* Video n scaling control register (Gen3) */ +#define VNUDS_CTRL_AMD (1 << 30) + struct rvin_buffer { struct vb2_v4l2_buffer vb; struct list_head list; @@ -591,6 +598,69 @@ void rvin_scaler_gen2(struct rvin_dev *vin) 0, 0); } +static unsigned int rvin_uds_scale_ratio(unsigned int in, unsigned int out) +{ + unsigned int ratio; + + ratio = in * 4096 / out; + return ratio >= 0x10000 ? 0xffff : ratio; +} + +static unsigned int rvin_uds_filter_width(unsigned int ratio) +{ + if (ratio >= 0x1000) + return 64 * (ratio & 0xf000) / ratio; + + return 64; +} + +void rvin_scaler_gen3(struct rvin_dev *vin) +{ + unsigned int ratio_h, ratio_v; + unsigned int bwidth_h, bwidth_v; + u32 vnmc, clip_size; + + vnmc = rvin_read(vin, VNMC_REG); + + /* Disable scaler if not needed. */ + if (!rvin_scaler_needed(vin)) { + rvin_write(vin, vnmc & ~VNMC_SCLE, VNMC_REG); + return; + } + + ratio_h = rvin_uds_scale_ratio(vin->crop.width, vin->compose.width); + bwidth_h = rvin_uds_filter_width(ratio_h); + + ratio_v = rvin_uds_scale_ratio(vin->crop.height, vin->compose.height); + bwidth_v = rvin_uds_filter_width(ratio_v); + + clip_size = vin->compose.width << 16; + + switch (vin->format.field) { + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: + clip_size |= vin->compose.height / 2; + break; + default: + clip_size |= vin->compose.height; + break; + } + + rvin_write(vin, vnmc | VNMC_SCLE, VNMC_REG); + rvin_write(vin, VNUDS_CTRL_AMD, VNUDS_CTRL_REG); + rvin_write(vin, (ratio_h << 16) | ratio_v, VNUDS_SCALE_REG); + rvin_write(vin, (bwidth_h << 16) | bwidth_v, VNUDS_PASS_BWIDTH_REG); + rvin_write(vin, clip_size, VNUDS_CLIP_SIZE_REG); + + vin_dbg(vin, "Pre-Clip: %ux%u@%u:%u Post-Clip: %ux%u@%u:%u\n", + vin->crop.width, vin->crop.height, vin->crop.left, + vin->crop.top, vin->compose.width, vin->compose.height, + vin->compose.left, vin->compose.top); +} + void rvin_crop_scale_comp(struct rvin_dev *vin) { const struct rvin_video_format *fmt; diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c index 07564e05ed8c..073f70c6ac68 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c @@ -918,6 +918,9 @@ static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = { .vidioc_s_fmt_vid_cap = rvin_mc_s_fmt_vid_cap, .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap, + .vidioc_g_selection = rvin_g_selection, + .vidioc_s_selection = rvin_s_selection, + .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs, .vidioc_querybuf = vb2_ioctl_querybuf, diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h index 334c327889a0..cb206d3976dd 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h @@ -308,6 +308,7 @@ const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, /* Cropping, composing and scaling */ void rvin_scaler_gen2(struct rvin_dev *vin); +void rvin_scaler_gen3(struct rvin_dev *vin); void rvin_crop_scale_comp(struct rvin_dev *vin); int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel);