Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: microchip: microchip-isc: prepare for media controller support

Prepare the support for media-controller.
This means that the capabilities of the driver have changed and now it's
capable of media controller operations.
The driver will register its media device, and add the video entity to this
media device. The subdevices are registered to the same media device.
The ISC will have a base entity which is auto-detected as
microchip_isc_base.
It will also register a subdevice that allows cropping of the incoming
frame to the maximum frame size supported by the ISC.
The ISC will create a link between the subdevice that is asynchronously
registered and the microchip_isc_scaler entity.
Then, the microchip_isc_scaler and microchip_isc_base are connected
through another link.
This patch does not change the previous capability of the driver, the
fact that the format is still being propagated from the top video node
down to the sensor.

Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>

authored by

Eugen Hristev and committed by
Mauro Carvalho Chehab
920b2665 91b4e487

+391 -6
+1 -1
drivers/media/platform/microchip/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 microchip-isc-objs = microchip-sama5d2-isc.o 3 3 microchip-xisc-objs = microchip-sama7g5-isc.o 4 - microchip-isc-common-objs = microchip-isc-base.o microchip-isc-clk.o 4 + microchip-isc-common-objs = microchip-isc-base.o microchip-isc-clk.o microchip-isc-scaler.o 5 5 6 6 obj-$(CONFIG_VIDEO_MICROCHIP_ISC_BASE) += microchip-isc-common.o 7 7 obj-$(CONFIG_VIDEO_MICROCHIP_ISC) += microchip-isc.o
+69 -3
drivers/media/platform/microchip/microchip-isc-base.c
··· 1732 1732 struct isc_device, v4l2_dev); 1733 1733 struct isc_subdev_entity *subdev_entity = 1734 1734 container_of(notifier, struct isc_subdev_entity, notifier); 1735 + int pad; 1735 1736 1736 1737 if (video_is_registered(&isc->video_dev)) { 1737 1738 v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n"); ··· 1740 1739 } 1741 1740 1742 1741 subdev_entity->sd = subdev; 1742 + 1743 + pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode, 1744 + MEDIA_PAD_FL_SOURCE); 1745 + if (pad < 0) { 1746 + v4l2_err(&isc->v4l2_dev, "failed to find pad for %s\n", 1747 + subdev->name); 1748 + return pad; 1749 + } 1750 + 1751 + isc->remote_pad = pad; 1743 1752 1744 1753 return 0; 1745 1754 } ··· 1766 1755 v4l2_ctrl_handler_free(&isc->ctrls.handler); 1767 1756 } 1768 1757 1769 - static struct isc_format *find_format_by_code(struct isc_device *isc, 1770 - unsigned int code, int *index) 1758 + struct isc_format *isc_find_format_by_code(struct isc_device *isc, 1759 + unsigned int code, int *index) 1771 1760 { 1772 1761 struct isc_format *fmt = &isc->formats_list[0]; 1773 1762 unsigned int i; ··· 1783 1772 1784 1773 return NULL; 1785 1774 } 1775 + EXPORT_SYMBOL_GPL(isc_find_format_by_code); 1786 1776 1787 1777 static int isc_formats_init(struct isc_device *isc) 1788 1778 { ··· 1800 1788 NULL, &mbus_code)) { 1801 1789 mbus_code.index++; 1802 1790 1803 - fmt = find_format_by_code(isc, mbus_code.code, &i); 1791 + fmt = isc_find_format_by_code(isc, mbus_code.code, &i); 1804 1792 if (!fmt) { 1805 1793 v4l2_warn(&isc->v4l2_dev, "Mbus code %x not supported\n", 1806 1794 mbus_code.code); ··· 1938 1926 goto isc_async_complete_err; 1939 1927 } 1940 1928 1929 + ret = isc_scaler_link(isc); 1930 + if (ret < 0) 1931 + goto isc_async_complete_unregister_device; 1932 + 1933 + ret = media_device_register(&isc->mdev); 1934 + if (ret < 0) 1935 + goto isc_async_complete_unregister_device; 1936 + 1941 1937 return 0; 1938 + 1939 + isc_async_complete_unregister_device: 1940 + video_unregister_device(vdev); 1942 1941 1943 1942 isc_async_complete_err: 1944 1943 mutex_destroy(&isc->awb_mutex); ··· 2017 1994 return 0; 2018 1995 } 2019 1996 EXPORT_SYMBOL_GPL(microchip_isc_pipeline_init); 1997 + 1998 + int isc_mc_init(struct isc_device *isc, u32 ver) 1999 + { 2000 + const struct of_device_id *match; 2001 + int ret; 2002 + 2003 + isc->video_dev.entity.function = MEDIA_ENT_F_IO_V4L; 2004 + isc->video_dev.entity.flags = MEDIA_ENT_FL_DEFAULT; 2005 + isc->pads[ISC_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 2006 + 2007 + ret = media_entity_pads_init(&isc->video_dev.entity, ISC_PADS_NUM, 2008 + isc->pads); 2009 + if (ret < 0) { 2010 + dev_err(isc->dev, "media entity init failed\n"); 2011 + return ret; 2012 + } 2013 + 2014 + isc->mdev.dev = isc->dev; 2015 + 2016 + match = of_match_node(isc->dev->driver->of_match_table, 2017 + isc->dev->of_node); 2018 + 2019 + strscpy(isc->mdev.driver_name, KBUILD_MODNAME, 2020 + sizeof(isc->mdev.driver_name)); 2021 + strscpy(isc->mdev.model, match->compatible, sizeof(isc->mdev.model)); 2022 + snprintf(isc->mdev.bus_info, sizeof(isc->mdev.bus_info), "platform:%s", 2023 + isc->v4l2_dev.name); 2024 + isc->mdev.hw_revision = ver; 2025 + 2026 + media_device_init(&isc->mdev); 2027 + 2028 + isc->v4l2_dev.mdev = &isc->mdev; 2029 + 2030 + return isc_scaler_init(isc); 2031 + } 2032 + EXPORT_SYMBOL_GPL(isc_mc_init); 2033 + 2034 + void isc_mc_cleanup(struct isc_device *isc) 2035 + { 2036 + media_entity_cleanup(&isc->video_dev.entity); 2037 + media_device_cleanup(&isc->mdev); 2038 + } 2039 + EXPORT_SYMBOL_GPL(isc_mc_cleanup); 2020 2040 2021 2041 /* regmap configuration */ 2022 2042 #define MICROCHIP_ISC_REG_MAX 0xd5c
+262
drivers/media/platform/microchip/microchip-isc-scaler.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Microchip Image Sensor Controller (ISC) Scaler entity support 4 + * 5 + * Copyright (C) 2022 Microchip Technology, Inc. 6 + * 7 + * Author: Eugen Hristev <eugen.hristev@microchip.com> 8 + * 9 + */ 10 + 11 + #include <media/media-device.h> 12 + #include <media/media-entity.h> 13 + #include <media/v4l2-device.h> 14 + #include <media/v4l2-subdev.h> 15 + 16 + #include "microchip-isc-regs.h" 17 + #include "microchip-isc.h" 18 + 19 + static void isc_scaler_prepare_fmt(struct v4l2_mbus_framefmt *framefmt) 20 + { 21 + framefmt->colorspace = V4L2_COLORSPACE_SRGB; 22 + framefmt->field = V4L2_FIELD_NONE; 23 + framefmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 24 + framefmt->quantization = V4L2_QUANTIZATION_DEFAULT; 25 + framefmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; 26 + }; 27 + 28 + static int isc_scaler_get_fmt(struct v4l2_subdev *sd, 29 + struct v4l2_subdev_state *sd_state, 30 + struct v4l2_subdev_format *format) 31 + { 32 + struct isc_device *isc = container_of(sd, struct isc_device, scaler_sd); 33 + struct v4l2_mbus_framefmt *v4l2_try_fmt; 34 + 35 + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 36 + v4l2_try_fmt = v4l2_subdev_get_try_format(sd, sd_state, 37 + format->pad); 38 + format->format = *v4l2_try_fmt; 39 + 40 + return 0; 41 + } 42 + 43 + format->format = isc->scaler_format[format->pad]; 44 + 45 + return 0; 46 + } 47 + 48 + static int isc_scaler_set_fmt(struct v4l2_subdev *sd, 49 + struct v4l2_subdev_state *sd_state, 50 + struct v4l2_subdev_format *req_fmt) 51 + { 52 + struct isc_device *isc = container_of(sd, struct isc_device, scaler_sd); 53 + struct v4l2_mbus_framefmt *v4l2_try_fmt; 54 + struct isc_format *fmt; 55 + unsigned int i; 56 + 57 + /* Source format is fixed, we cannot change it */ 58 + if (req_fmt->pad == ISC_SCALER_PAD_SOURCE) { 59 + req_fmt->format = isc->scaler_format[ISC_SCALER_PAD_SOURCE]; 60 + return 0; 61 + } 62 + 63 + /* There is no limit on the frame size on the sink pad */ 64 + v4l_bound_align_image(&req_fmt->format.width, 16, UINT_MAX, 0, 65 + &req_fmt->format.height, 16, UINT_MAX, 0, 0); 66 + 67 + isc_scaler_prepare_fmt(&req_fmt->format); 68 + 69 + fmt = isc_find_format_by_code(isc, req_fmt->format.code, &i); 70 + 71 + if (!fmt) 72 + fmt = &isc->formats_list[0]; 73 + 74 + req_fmt->format.code = fmt->mbus_code; 75 + 76 + if (req_fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 77 + v4l2_try_fmt = v4l2_subdev_get_try_format(sd, sd_state, 78 + req_fmt->pad); 79 + *v4l2_try_fmt = req_fmt->format; 80 + /* Trying on the sink pad makes the source pad change too */ 81 + v4l2_try_fmt = v4l2_subdev_get_try_format(sd, sd_state, 82 + ISC_SCALER_PAD_SOURCE); 83 + *v4l2_try_fmt = req_fmt->format; 84 + 85 + v4l_bound_align_image(&v4l2_try_fmt->width, 86 + 16, isc->max_width, 0, 87 + &v4l2_try_fmt->height, 88 + 16, isc->max_height, 0, 0); 89 + /* if we are just trying, we are done */ 90 + return 0; 91 + } 92 + 93 + isc->scaler_format[ISC_SCALER_PAD_SINK] = req_fmt->format; 94 + 95 + /* The source pad is the same as the sink, but we have to crop it */ 96 + isc->scaler_format[ISC_SCALER_PAD_SOURCE] = 97 + isc->scaler_format[ISC_SCALER_PAD_SINK]; 98 + v4l_bound_align_image 99 + (&isc->scaler_format[ISC_SCALER_PAD_SOURCE].width, 16, 100 + isc->max_width, 0, 101 + &isc->scaler_format[ISC_SCALER_PAD_SOURCE].height, 16, 102 + isc->max_height, 0, 0); 103 + 104 + return 0; 105 + } 106 + 107 + static int isc_scaler_enum_mbus_code(struct v4l2_subdev *sd, 108 + struct v4l2_subdev_state *sd_state, 109 + struct v4l2_subdev_mbus_code_enum *code) 110 + { 111 + struct isc_device *isc = container_of(sd, struct isc_device, scaler_sd); 112 + 113 + /* 114 + * All formats supported by the ISC are supported by the scaler. 115 + * Advertise the formats which the ISC can take as input, as the scaler 116 + * entity cropping is part of the PFE module (parallel front end) 117 + */ 118 + if (code->index < isc->formats_list_size) { 119 + code->code = isc->formats_list[code->index].mbus_code; 120 + return 0; 121 + } 122 + 123 + return -EINVAL; 124 + } 125 + 126 + static int isc_scaler_g_sel(struct v4l2_subdev *sd, 127 + struct v4l2_subdev_state *sd_state, 128 + struct v4l2_subdev_selection *sel) 129 + { 130 + struct isc_device *isc = container_of(sd, struct isc_device, scaler_sd); 131 + 132 + if (sel->pad == ISC_SCALER_PAD_SOURCE) 133 + return -EINVAL; 134 + 135 + if (sel->target != V4L2_SEL_TGT_CROP_BOUNDS && 136 + sel->target != V4L2_SEL_TGT_CROP) 137 + return -EINVAL; 138 + 139 + sel->r.height = isc->scaler_format[ISC_SCALER_PAD_SOURCE].height; 140 + sel->r.width = isc->scaler_format[ISC_SCALER_PAD_SOURCE].width; 141 + 142 + sel->r.left = 0; 143 + sel->r.top = 0; 144 + 145 + return 0; 146 + } 147 + 148 + static int isc_scaler_init_cfg(struct v4l2_subdev *sd, 149 + struct v4l2_subdev_state *sd_state) 150 + { 151 + struct v4l2_mbus_framefmt *v4l2_try_fmt = 152 + v4l2_subdev_get_try_format(sd, sd_state, 0); 153 + struct v4l2_rect *try_crop; 154 + struct isc_device *isc = container_of(sd, struct isc_device, scaler_sd); 155 + 156 + *v4l2_try_fmt = isc->scaler_format[ISC_SCALER_PAD_SOURCE]; 157 + 158 + try_crop = v4l2_subdev_get_try_crop(sd, sd_state, 0); 159 + 160 + try_crop->top = 0; 161 + try_crop->left = 0; 162 + try_crop->width = v4l2_try_fmt->width; 163 + try_crop->height = v4l2_try_fmt->height; 164 + 165 + return 0; 166 + } 167 + 168 + static const struct v4l2_subdev_pad_ops isc_scaler_pad_ops = { 169 + .enum_mbus_code = isc_scaler_enum_mbus_code, 170 + .set_fmt = isc_scaler_set_fmt, 171 + .get_fmt = isc_scaler_get_fmt, 172 + .get_selection = isc_scaler_g_sel, 173 + .init_cfg = isc_scaler_init_cfg, 174 + }; 175 + 176 + static const struct v4l2_subdev_ops xisc_scaler_subdev_ops = { 177 + .pad = &isc_scaler_pad_ops, 178 + }; 179 + 180 + int isc_scaler_init(struct isc_device *isc) 181 + { 182 + int ret; 183 + 184 + v4l2_subdev_init(&isc->scaler_sd, &xisc_scaler_subdev_ops); 185 + 186 + isc->scaler_sd.owner = THIS_MODULE; 187 + isc->scaler_sd.dev = isc->dev; 188 + snprintf(isc->scaler_sd.name, sizeof(isc->scaler_sd.name), 189 + "microchip_isc_scaler"); 190 + 191 + isc->scaler_sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 192 + isc->scaler_sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; 193 + isc->scaler_pads[ISC_SCALER_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 194 + isc->scaler_pads[ISC_SCALER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 195 + 196 + isc_scaler_prepare_fmt(&isc->scaler_format[ISC_SCALER_PAD_SOURCE]); 197 + isc->scaler_format[ISC_SCALER_PAD_SOURCE].height = isc->max_height; 198 + isc->scaler_format[ISC_SCALER_PAD_SOURCE].width = isc->max_width; 199 + isc->scaler_format[ISC_SCALER_PAD_SOURCE].code = 200 + isc->formats_list[0].mbus_code; 201 + 202 + isc->scaler_format[ISC_SCALER_PAD_SINK] = 203 + isc->scaler_format[ISC_SCALER_PAD_SOURCE]; 204 + 205 + ret = media_entity_pads_init(&isc->scaler_sd.entity, 206 + ISC_SCALER_PADS_NUM, 207 + isc->scaler_pads); 208 + if (ret < 0) { 209 + dev_err(isc->dev, "scaler sd media entity init failed\n"); 210 + return ret; 211 + } 212 + 213 + ret = v4l2_device_register_subdev(&isc->v4l2_dev, &isc->scaler_sd); 214 + if (ret < 0) { 215 + dev_err(isc->dev, "scaler sd failed to register subdev\n"); 216 + return ret; 217 + } 218 + 219 + return ret; 220 + } 221 + EXPORT_SYMBOL_GPL(isc_scaler_init); 222 + 223 + int isc_scaler_link(struct isc_device *isc) 224 + { 225 + int ret; 226 + 227 + ret = media_create_pad_link(&isc->current_subdev->sd->entity, 228 + isc->remote_pad, &isc->scaler_sd.entity, 229 + ISC_SCALER_PAD_SINK, 230 + MEDIA_LNK_FL_ENABLED | 231 + MEDIA_LNK_FL_IMMUTABLE); 232 + 233 + if (ret < 0) { 234 + dev_err(isc->dev, "Failed to create pad link: %s to %s\n", 235 + isc->current_subdev->sd->entity.name, 236 + isc->scaler_sd.entity.name); 237 + return ret; 238 + } 239 + 240 + dev_dbg(isc->dev, "link with %s pad: %d\n", 241 + isc->current_subdev->sd->name, isc->remote_pad); 242 + 243 + ret = media_create_pad_link(&isc->scaler_sd.entity, 244 + ISC_SCALER_PAD_SOURCE, 245 + &isc->video_dev.entity, ISC_PAD_SINK, 246 + MEDIA_LNK_FL_ENABLED | 247 + MEDIA_LNK_FL_IMMUTABLE); 248 + 249 + if (ret < 0) { 250 + dev_err(isc->dev, "Failed to create pad link: %s to %s\n", 251 + isc->scaler_sd.entity.name, 252 + isc->video_dev.entity.name); 253 + return ret; 254 + } 255 + 256 + dev_dbg(isc->dev, "link with %s pad: %d\n", isc->scaler_sd.name, 257 + ISC_SCALER_PAD_SOURCE); 258 + 259 + return ret; 260 + } 261 + EXPORT_SYMBOL_GPL(isc_scaler_link); 262 +
+37
drivers/media/platform/microchip/microchip-isc.h
··· 183 183 u32 his_entry; 184 184 }; 185 185 186 + enum isc_mc_pads { 187 + ISC_PAD_SINK = 0, 188 + ISC_PADS_NUM = 1, 189 + }; 190 + 191 + enum isc_scaler_pads { 192 + ISC_SCALER_PAD_SINK = 0, 193 + ISC_SCALER_PAD_SOURCE = 1, 194 + ISC_SCALER_PADS_NUM = 2, 195 + }; 196 + 186 197 /* 187 198 * struct isc_device - ISC device driver data/config struct 188 199 * @regmap: Register map ··· 270 259 * be used as an input to the controller 271 260 * @controller_formats_size: size of controller_formats array 272 261 * @formats_list_size: size of formats_list array 262 + * @pads: media controller pads for isc video entity 263 + * @mdev: media device that is registered by the isc 264 + * @remote_pad: remote pad on the connected subdevice 265 + * @scaler_sd: subdevice for the scaler that isc registers 266 + * @scaler_pads: media controller pads for the scaler subdevice 267 + * @scaler_format: current format for the scaler subdevice 273 268 */ 274 269 struct isc_device { 275 270 struct regmap *regmap; ··· 365 348 struct isc_format *formats_list; 366 349 u32 controller_formats_size; 367 350 u32 formats_list_size; 351 + 352 + struct { 353 + struct media_pad pads[ISC_PADS_NUM]; 354 + struct media_device mdev; 355 + 356 + u32 remote_pad; 357 + }; 358 + 359 + struct { 360 + struct v4l2_subdev scaler_sd; 361 + struct media_pad scaler_pads[ISC_SCALER_PADS_NUM]; 362 + struct v4l2_mbus_framefmt scaler_format[ISC_SCALER_PADS_NUM]; 363 + }; 368 364 }; 369 365 370 366 extern const struct regmap_config microchip_isc_regmap_config; ··· 389 359 void microchip_isc_subdev_cleanup(struct isc_device *isc); 390 360 void microchip_isc_clk_cleanup(struct isc_device *isc); 391 361 362 + int isc_scaler_link(struct isc_device *isc); 363 + int isc_scaler_init(struct isc_device *isc); 364 + int isc_mc_init(struct isc_device *isc, u32 ver); 365 + void isc_mc_cleanup(struct isc_device *isc); 366 + 367 + struct isc_format *isc_find_format_by_code(struct isc_device *isc, 368 + unsigned int code, int *index); 392 369 #endif
+11 -1
drivers/media/platform/microchip/microchip-sama5d2-isc.c
··· 536 536 break; 537 537 } 538 538 539 + regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver); 540 + 541 + ret = isc_mc_init(isc, ver); 542 + if (ret < 0) 543 + goto isc_probe_mc_init_err; 544 + 539 545 pm_runtime_set_active(dev); 540 546 pm_runtime_enable(dev); 541 547 pm_request_idle(dev); ··· 561 555 goto unprepare_clk; 562 556 } 563 557 564 - regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver); 565 558 dev_info(dev, "Microchip ISC version %x\n", ver); 566 559 567 560 return 0; ··· 570 565 571 566 disable_pm: 572 567 pm_runtime_disable(dev); 568 + 569 + isc_probe_mc_init_err: 570 + isc_mc_cleanup(isc); 573 571 574 572 cleanup_subdev: 575 573 microchip_isc_subdev_cleanup(isc); ··· 593 585 struct isc_device *isc = platform_get_drvdata(pdev); 594 586 595 587 pm_runtime_disable(&pdev->dev); 588 + 589 + isc_mc_cleanup(isc); 596 590 597 591 microchip_isc_subdev_cleanup(isc); 598 592
+11 -1
drivers/media/platform/microchip/microchip-sama7g5-isc.c
··· 526 526 break; 527 527 } 528 528 529 + regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver); 530 + 531 + ret = isc_mc_init(isc, ver); 532 + if (ret < 0) 533 + goto isc_probe_mc_init_err; 534 + 529 535 pm_runtime_set_active(dev); 530 536 pm_runtime_enable(dev); 531 537 pm_request_idle(dev); 532 538 533 - regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver); 534 539 dev_info(dev, "Microchip XISC version %x\n", ver); 535 540 536 541 return 0; 542 + 543 + isc_probe_mc_init_err: 544 + isc_mc_cleanup(isc); 537 545 538 546 cleanup_subdev: 539 547 microchip_isc_subdev_cleanup(isc); ··· 562 554 struct isc_device *isc = platform_get_drvdata(pdev); 563 555 564 556 pm_runtime_disable(&pdev->dev); 557 + 558 + isc_mc_cleanup(isc); 565 559 566 560 microchip_isc_subdev_cleanup(isc); 567 561