18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * vsp1_uds.c -- R-Car VSP1 Up and Down Scaler 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013-2014 Renesas Electronics Corporation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/gfp.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "vsp1.h" 168c2ecf20Sopenharmony_ci#include "vsp1_dl.h" 178c2ecf20Sopenharmony_ci#include "vsp1_pipe.h" 188c2ecf20Sopenharmony_ci#include "vsp1_uds.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define UDS_MIN_SIZE 4U 218c2ecf20Sopenharmony_ci#define UDS_MAX_SIZE 8190U 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define UDS_MIN_FACTOR 0x0100 248c2ecf20Sopenharmony_ci#define UDS_MAX_FACTOR 0xffff 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 278c2ecf20Sopenharmony_ci * Device Access 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic inline void vsp1_uds_write(struct vsp1_uds *uds, 318c2ecf20Sopenharmony_ci struct vsp1_dl_body *dlb, u32 reg, u32 data) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci vsp1_dl_body_write(dlb, reg + uds->entity.index * VI6_UDS_OFFSET, data); 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 378c2ecf20Sopenharmony_ci * Scaling Computation 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_civoid vsp1_uds_set_alpha(struct vsp1_entity *entity, struct vsp1_dl_body *dlb, 418c2ecf20Sopenharmony_ci unsigned int alpha) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct vsp1_uds *uds = to_uds(&entity->subdev); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci vsp1_uds_write(uds, dlb, VI6_UDS_ALPVAL, 468c2ecf20Sopenharmony_ci alpha << VI6_UDS_ALPVAL_VAL0_SHIFT); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* 508c2ecf20Sopenharmony_ci * uds_output_size - Return the output size for an input size and scaling ratio 518c2ecf20Sopenharmony_ci * @input: input size in pixels 528c2ecf20Sopenharmony_ci * @ratio: scaling ratio in U4.12 fixed-point format 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_cistatic unsigned int uds_output_size(unsigned int input, unsigned int ratio) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci if (ratio > 4096) { 578c2ecf20Sopenharmony_ci /* Down-scaling */ 588c2ecf20Sopenharmony_ci unsigned int mp; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci mp = ratio / 4096; 618c2ecf20Sopenharmony_ci mp = mp < 4 ? 1 : (mp < 8 ? 2 : 4); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return (input - 1) / mp * mp * 4096 / ratio + 1; 648c2ecf20Sopenharmony_ci } else { 658c2ecf20Sopenharmony_ci /* Up-scaling */ 668c2ecf20Sopenharmony_ci return (input - 1) * 4096 / ratio + 1; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* 718c2ecf20Sopenharmony_ci * uds_output_limits - Return the min and max output sizes for an input size 728c2ecf20Sopenharmony_ci * @input: input size in pixels 738c2ecf20Sopenharmony_ci * @minimum: minimum output size (returned) 748c2ecf20Sopenharmony_ci * @maximum: maximum output size (returned) 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_cistatic void uds_output_limits(unsigned int input, 778c2ecf20Sopenharmony_ci unsigned int *minimum, unsigned int *maximum) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci *minimum = max(uds_output_size(input, UDS_MAX_FACTOR), UDS_MIN_SIZE); 808c2ecf20Sopenharmony_ci *maximum = min(uds_output_size(input, UDS_MIN_FACTOR), UDS_MAX_SIZE); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* 848c2ecf20Sopenharmony_ci * uds_passband_width - Return the passband filter width for a scaling ratio 858c2ecf20Sopenharmony_ci * @ratio: scaling ratio in U4.12 fixed-point format 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistatic unsigned int uds_passband_width(unsigned int ratio) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci if (ratio >= 4096) { 908c2ecf20Sopenharmony_ci /* Down-scaling */ 918c2ecf20Sopenharmony_ci unsigned int mp; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci mp = ratio / 4096; 948c2ecf20Sopenharmony_ci mp = mp < 4 ? 1 : (mp < 8 ? 2 : 4); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return 64 * 4096 * mp / ratio; 978c2ecf20Sopenharmony_ci } else { 988c2ecf20Sopenharmony_ci /* Up-scaling */ 998c2ecf20Sopenharmony_ci return 64; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic unsigned int uds_compute_ratio(unsigned int input, unsigned int output) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci /* TODO: This is an approximation that will need to be refined. */ 1068c2ecf20Sopenharmony_ci return (input - 1) * 4096 / (output - 1); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 1108c2ecf20Sopenharmony_ci * V4L2 Subdevice Pad Operations 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic int uds_enum_mbus_code(struct v4l2_subdev *subdev, 1148c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 1158c2ecf20Sopenharmony_ci struct v4l2_subdev_mbus_code_enum *code) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci static const unsigned int codes[] = { 1188c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_ARGB8888_1X32, 1198c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_AYUV8_1X32, 1208c2ecf20Sopenharmony_ci }; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, 1238c2ecf20Sopenharmony_ci ARRAY_SIZE(codes)); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int uds_enum_frame_size(struct v4l2_subdev *subdev, 1278c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 1288c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_size_enum *fse) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct vsp1_uds *uds = to_uds(subdev); 1318c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *config; 1328c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 1338c2ecf20Sopenharmony_ci int ret = 0; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci config = vsp1_entity_get_pad_config(&uds->entity, cfg, fse->which); 1368c2ecf20Sopenharmony_ci if (!config) 1378c2ecf20Sopenharmony_ci return -EINVAL; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci format = vsp1_entity_get_pad_format(&uds->entity, config, 1408c2ecf20Sopenharmony_ci UDS_PAD_SINK); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci mutex_lock(&uds->entity.lock); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (fse->index || fse->code != format->code) { 1458c2ecf20Sopenharmony_ci ret = -EINVAL; 1468c2ecf20Sopenharmony_ci goto done; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (fse->pad == UDS_PAD_SINK) { 1508c2ecf20Sopenharmony_ci fse->min_width = UDS_MIN_SIZE; 1518c2ecf20Sopenharmony_ci fse->max_width = UDS_MAX_SIZE; 1528c2ecf20Sopenharmony_ci fse->min_height = UDS_MIN_SIZE; 1538c2ecf20Sopenharmony_ci fse->max_height = UDS_MAX_SIZE; 1548c2ecf20Sopenharmony_ci } else { 1558c2ecf20Sopenharmony_ci uds_output_limits(format->width, &fse->min_width, 1568c2ecf20Sopenharmony_ci &fse->max_width); 1578c2ecf20Sopenharmony_ci uds_output_limits(format->height, &fse->min_height, 1588c2ecf20Sopenharmony_ci &fse->max_height); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cidone: 1628c2ecf20Sopenharmony_ci mutex_unlock(&uds->entity.lock); 1638c2ecf20Sopenharmony_ci return ret; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void uds_try_format(struct vsp1_uds *uds, 1678c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *config, 1688c2ecf20Sopenharmony_ci unsigned int pad, struct v4l2_mbus_framefmt *fmt) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 1718c2ecf20Sopenharmony_ci unsigned int minimum; 1728c2ecf20Sopenharmony_ci unsigned int maximum; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci switch (pad) { 1758c2ecf20Sopenharmony_ci case UDS_PAD_SINK: 1768c2ecf20Sopenharmony_ci /* Default to YUV if the requested format is not supported. */ 1778c2ecf20Sopenharmony_ci if (fmt->code != MEDIA_BUS_FMT_ARGB8888_1X32 && 1788c2ecf20Sopenharmony_ci fmt->code != MEDIA_BUS_FMT_AYUV8_1X32) 1798c2ecf20Sopenharmony_ci fmt->code = MEDIA_BUS_FMT_AYUV8_1X32; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci fmt->width = clamp(fmt->width, UDS_MIN_SIZE, UDS_MAX_SIZE); 1828c2ecf20Sopenharmony_ci fmt->height = clamp(fmt->height, UDS_MIN_SIZE, UDS_MAX_SIZE); 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci case UDS_PAD_SOURCE: 1868c2ecf20Sopenharmony_ci /* The UDS scales but can't perform format conversion. */ 1878c2ecf20Sopenharmony_ci format = vsp1_entity_get_pad_format(&uds->entity, config, 1888c2ecf20Sopenharmony_ci UDS_PAD_SINK); 1898c2ecf20Sopenharmony_ci fmt->code = format->code; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci uds_output_limits(format->width, &minimum, &maximum); 1928c2ecf20Sopenharmony_ci fmt->width = clamp(fmt->width, minimum, maximum); 1938c2ecf20Sopenharmony_ci uds_output_limits(format->height, &minimum, &maximum); 1948c2ecf20Sopenharmony_ci fmt->height = clamp(fmt->height, minimum, maximum); 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci fmt->field = V4L2_FIELD_NONE; 1998c2ecf20Sopenharmony_ci fmt->colorspace = V4L2_COLORSPACE_SRGB; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int uds_set_format(struct v4l2_subdev *subdev, 2038c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 2048c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct vsp1_uds *uds = to_uds(subdev); 2078c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *config; 2088c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 2098c2ecf20Sopenharmony_ci int ret = 0; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci mutex_lock(&uds->entity.lock); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci config = vsp1_entity_get_pad_config(&uds->entity, cfg, fmt->which); 2148c2ecf20Sopenharmony_ci if (!config) { 2158c2ecf20Sopenharmony_ci ret = -EINVAL; 2168c2ecf20Sopenharmony_ci goto done; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci uds_try_format(uds, config, fmt->pad, &fmt->format); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci format = vsp1_entity_get_pad_format(&uds->entity, config, fmt->pad); 2228c2ecf20Sopenharmony_ci *format = fmt->format; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (fmt->pad == UDS_PAD_SINK) { 2258c2ecf20Sopenharmony_ci /* Propagate the format to the source pad. */ 2268c2ecf20Sopenharmony_ci format = vsp1_entity_get_pad_format(&uds->entity, config, 2278c2ecf20Sopenharmony_ci UDS_PAD_SOURCE); 2288c2ecf20Sopenharmony_ci *format = fmt->format; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci uds_try_format(uds, config, UDS_PAD_SOURCE, format); 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cidone: 2348c2ecf20Sopenharmony_ci mutex_unlock(&uds->entity.lock); 2358c2ecf20Sopenharmony_ci return ret; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 2398c2ecf20Sopenharmony_ci * V4L2 Subdevice Operations 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops uds_pad_ops = { 2438c2ecf20Sopenharmony_ci .init_cfg = vsp1_entity_init_cfg, 2448c2ecf20Sopenharmony_ci .enum_mbus_code = uds_enum_mbus_code, 2458c2ecf20Sopenharmony_ci .enum_frame_size = uds_enum_frame_size, 2468c2ecf20Sopenharmony_ci .get_fmt = vsp1_subdev_get_pad_format, 2478c2ecf20Sopenharmony_ci .set_fmt = uds_set_format, 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops uds_ops = { 2518c2ecf20Sopenharmony_ci .pad = &uds_pad_ops, 2528c2ecf20Sopenharmony_ci}; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 2558c2ecf20Sopenharmony_ci * VSP1 Entity Operations 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic void uds_configure_stream(struct vsp1_entity *entity, 2598c2ecf20Sopenharmony_ci struct vsp1_pipeline *pipe, 2608c2ecf20Sopenharmony_ci struct vsp1_dl_list *dl, 2618c2ecf20Sopenharmony_ci struct vsp1_dl_body *dlb) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct vsp1_uds *uds = to_uds(&entity->subdev); 2648c2ecf20Sopenharmony_ci const struct v4l2_mbus_framefmt *output; 2658c2ecf20Sopenharmony_ci const struct v4l2_mbus_framefmt *input; 2668c2ecf20Sopenharmony_ci unsigned int hscale; 2678c2ecf20Sopenharmony_ci unsigned int vscale; 2688c2ecf20Sopenharmony_ci bool multitap; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, 2718c2ecf20Sopenharmony_ci UDS_PAD_SINK); 2728c2ecf20Sopenharmony_ci output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, 2738c2ecf20Sopenharmony_ci UDS_PAD_SOURCE); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci hscale = uds_compute_ratio(input->width, output->width); 2768c2ecf20Sopenharmony_ci vscale = uds_compute_ratio(input->height, output->height); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* 2818c2ecf20Sopenharmony_ci * Multi-tap scaling can't be enabled along with alpha scaling when 2828c2ecf20Sopenharmony_ci * scaling down with a factor lower than or equal to 1/2 in either 2838c2ecf20Sopenharmony_ci * direction. 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_ci if (uds->scale_alpha && (hscale >= 8192 || vscale >= 8192)) 2868c2ecf20Sopenharmony_ci multitap = false; 2878c2ecf20Sopenharmony_ci else 2888c2ecf20Sopenharmony_ci multitap = true; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci vsp1_uds_write(uds, dlb, VI6_UDS_CTRL, 2918c2ecf20Sopenharmony_ci (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) | 2928c2ecf20Sopenharmony_ci (multitap ? VI6_UDS_CTRL_BC : 0)); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci vsp1_uds_write(uds, dlb, VI6_UDS_PASS_BWIDTH, 2958c2ecf20Sopenharmony_ci (uds_passband_width(hscale) 2968c2ecf20Sopenharmony_ci << VI6_UDS_PASS_BWIDTH_H_SHIFT) | 2978c2ecf20Sopenharmony_ci (uds_passband_width(vscale) 2988c2ecf20Sopenharmony_ci << VI6_UDS_PASS_BWIDTH_V_SHIFT)); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* Set the scaling ratios. */ 3018c2ecf20Sopenharmony_ci vsp1_uds_write(uds, dlb, VI6_UDS_SCALE, 3028c2ecf20Sopenharmony_ci (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) | 3038c2ecf20Sopenharmony_ci (vscale << VI6_UDS_SCALE_VFRAC_SHIFT)); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void uds_configure_partition(struct vsp1_entity *entity, 3078c2ecf20Sopenharmony_ci struct vsp1_pipeline *pipe, 3088c2ecf20Sopenharmony_ci struct vsp1_dl_list *dl, 3098c2ecf20Sopenharmony_ci struct vsp1_dl_body *dlb) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct vsp1_uds *uds = to_uds(&entity->subdev); 3128c2ecf20Sopenharmony_ci struct vsp1_partition *partition = pipe->partition; 3138c2ecf20Sopenharmony_ci const struct v4l2_mbus_framefmt *output; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, 3168c2ecf20Sopenharmony_ci UDS_PAD_SOURCE); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* Input size clipping. */ 3198c2ecf20Sopenharmony_ci vsp1_uds_write(uds, dlb, VI6_UDS_HSZCLIP, VI6_UDS_HSZCLIP_HCEN | 3208c2ecf20Sopenharmony_ci (0 << VI6_UDS_HSZCLIP_HCL_OFST_SHIFT) | 3218c2ecf20Sopenharmony_ci (partition->uds_sink.width 3228c2ecf20Sopenharmony_ci << VI6_UDS_HSZCLIP_HCL_SIZE_SHIFT)); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* Output size clipping. */ 3258c2ecf20Sopenharmony_ci vsp1_uds_write(uds, dlb, VI6_UDS_CLIP_SIZE, 3268c2ecf20Sopenharmony_ci (partition->uds_source.width 3278c2ecf20Sopenharmony_ci << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) | 3288c2ecf20Sopenharmony_ci (output->height 3298c2ecf20Sopenharmony_ci << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT)); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic unsigned int uds_max_width(struct vsp1_entity *entity, 3338c2ecf20Sopenharmony_ci struct vsp1_pipeline *pipe) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct vsp1_uds *uds = to_uds(&entity->subdev); 3368c2ecf20Sopenharmony_ci const struct v4l2_mbus_framefmt *output; 3378c2ecf20Sopenharmony_ci const struct v4l2_mbus_framefmt *input; 3388c2ecf20Sopenharmony_ci unsigned int hscale; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, 3418c2ecf20Sopenharmony_ci UDS_PAD_SINK); 3428c2ecf20Sopenharmony_ci output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, 3438c2ecf20Sopenharmony_ci UDS_PAD_SOURCE); 3448c2ecf20Sopenharmony_ci hscale = output->width / input->width; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* 3478c2ecf20Sopenharmony_ci * The maximum width of the UDS is 304 pixels. These are input pixels 3488c2ecf20Sopenharmony_ci * in the event of up-scaling, and output pixels in the event of 3498c2ecf20Sopenharmony_ci * downscaling. 3508c2ecf20Sopenharmony_ci * 3518c2ecf20Sopenharmony_ci * To support overlapping partition windows we clamp at units of 256 and 3528c2ecf20Sopenharmony_ci * the remaining pixels are reserved. 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_ci if (hscale <= 2) 3558c2ecf20Sopenharmony_ci return 256; 3568c2ecf20Sopenharmony_ci else if (hscale <= 4) 3578c2ecf20Sopenharmony_ci return 512; 3588c2ecf20Sopenharmony_ci else if (hscale <= 8) 3598c2ecf20Sopenharmony_ci return 1024; 3608c2ecf20Sopenharmony_ci else 3618c2ecf20Sopenharmony_ci return 2048; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 3658c2ecf20Sopenharmony_ci * Partition Algorithm Support 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void uds_partition(struct vsp1_entity *entity, 3698c2ecf20Sopenharmony_ci struct vsp1_pipeline *pipe, 3708c2ecf20Sopenharmony_ci struct vsp1_partition *partition, 3718c2ecf20Sopenharmony_ci unsigned int partition_idx, 3728c2ecf20Sopenharmony_ci struct vsp1_partition_window *window) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct vsp1_uds *uds = to_uds(&entity->subdev); 3758c2ecf20Sopenharmony_ci const struct v4l2_mbus_framefmt *output; 3768c2ecf20Sopenharmony_ci const struct v4l2_mbus_framefmt *input; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* Initialise the partition state. */ 3798c2ecf20Sopenharmony_ci partition->uds_sink = *window; 3808c2ecf20Sopenharmony_ci partition->uds_source = *window; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, 3838c2ecf20Sopenharmony_ci UDS_PAD_SINK); 3848c2ecf20Sopenharmony_ci output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, 3858c2ecf20Sopenharmony_ci UDS_PAD_SOURCE); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci partition->uds_sink.width = window->width * input->width 3888c2ecf20Sopenharmony_ci / output->width; 3898c2ecf20Sopenharmony_ci partition->uds_sink.left = window->left * input->width 3908c2ecf20Sopenharmony_ci / output->width; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci *window = partition->uds_sink; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic const struct vsp1_entity_operations uds_entity_ops = { 3968c2ecf20Sopenharmony_ci .configure_stream = uds_configure_stream, 3978c2ecf20Sopenharmony_ci .configure_partition = uds_configure_partition, 3988c2ecf20Sopenharmony_ci .max_width = uds_max_width, 3998c2ecf20Sopenharmony_ci .partition = uds_partition, 4008c2ecf20Sopenharmony_ci}; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 4038c2ecf20Sopenharmony_ci * Initialization and Cleanup 4048c2ecf20Sopenharmony_ci */ 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistruct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct vsp1_uds *uds; 4098c2ecf20Sopenharmony_ci char name[6]; 4108c2ecf20Sopenharmony_ci int ret; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci uds = devm_kzalloc(vsp1->dev, sizeof(*uds), GFP_KERNEL); 4138c2ecf20Sopenharmony_ci if (uds == NULL) 4148c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci uds->entity.ops = &uds_entity_ops; 4178c2ecf20Sopenharmony_ci uds->entity.type = VSP1_ENTITY_UDS; 4188c2ecf20Sopenharmony_ci uds->entity.index = index; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci sprintf(name, "uds.%u", index); 4218c2ecf20Sopenharmony_ci ret = vsp1_entity_init(vsp1, &uds->entity, name, 2, &uds_ops, 4228c2ecf20Sopenharmony_ci MEDIA_ENT_F_PROC_VIDEO_SCALER); 4238c2ecf20Sopenharmony_ci if (ret < 0) 4248c2ecf20Sopenharmony_ci return ERR_PTR(ret); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci return uds; 4278c2ecf20Sopenharmony_ci} 428