From c624fe63c0a9d3c410a7602e705f28c4ea00770d Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Tue, 13 Apr 2021 19:20:41 +0200 Subject: media: dt-bindings: media: renesas,csi2: Add r8a779a0 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for R-Car V3U. Signed-off-by: Niklas Söderlund Acked-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/renesas,csi2.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/media/renesas,csi2.yaml b/Documentation/devicetree/bindings/media/renesas,csi2.yaml index 23703b767f5b..e6a036721082 100644 --- a/Documentation/devicetree/bindings/media/renesas,csi2.yaml +++ b/Documentation/devicetree/bindings/media/renesas,csi2.yaml @@ -30,6 +30,7 @@ properties: - renesas,r8a77970-csi2 # R-Car V3M - renesas,r8a77980-csi2 # R-Car V3H - renesas,r8a77990-csi2 # R-Car E3 + - renesas,r8a779a0-csi2 # R-Car V3U reg: maxItems: 1 -- cgit v1.2.3 From b4173cd9981d366e7b612168055ecf935ee80eee Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Sat, 12 Jun 2021 10:46:29 +0200 Subject: media: rcar-csi2: Add r8a779a0 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the R-Car V3U (r8a779a0) to the driver. The V3U have the CSI-2 modules connected to ISPs instead of directly to the R-Car VIN DMA engines. The ISP performs channel selection based on CSI-2 VC/DT pairs and routes the video data. This requires the R-Car CSI-2 media entity to modeled differently then on other SoCs as it on the V3U only have a single source pad connected to the ISP. Signed-off-by: Niklas Söderlund Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-csi2.c | 191 +++++++++++++++++++++++++++- 1 file changed, 185 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index e28eff039688..f5ec7cc1c90c 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -126,6 +126,12 @@ struct rcar_csi2; #define PHTW_CWEN BIT(8) #define PHTW_TESTDIN_CODE(n) ((n & 0xff)) +#define PHYFRX_REG 0x64 +#define PHYFRX_FORCERX_MODE_3 BIT(3) +#define PHYFRX_FORCERX_MODE_2 BIT(2) +#define PHYFRX_FORCERX_MODE_1 BIT(1) +#define PHYFRX_FORCERX_MODE_0 BIT(0) + struct phtw_value { u16 data; u16 code; @@ -136,6 +142,31 @@ struct rcsi2_mbps_reg { u16 reg; }; +static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = { + { .mbps = 1500, .reg = 0xcc }, + { .mbps = 1550, .reg = 0x1d }, + { .mbps = 1600, .reg = 0x27 }, + { .mbps = 1650, .reg = 0x30 }, + { .mbps = 1700, .reg = 0x39 }, + { .mbps = 1750, .reg = 0x42 }, + { .mbps = 1800, .reg = 0x4b }, + { .mbps = 1850, .reg = 0x55 }, + { .mbps = 1900, .reg = 0x5e }, + { .mbps = 1950, .reg = 0x67 }, + { .mbps = 2000, .reg = 0x71 }, + { .mbps = 2050, .reg = 0x79 }, + { .mbps = 2100, .reg = 0x83 }, + { .mbps = 2150, .reg = 0x8c }, + { .mbps = 2200, .reg = 0x95 }, + { .mbps = 2250, .reg = 0x9e }, + { .mbps = 2300, .reg = 0xa7 }, + { .mbps = 2350, .reg = 0xb0 }, + { .mbps = 2400, .reg = 0xba }, + { .mbps = 2450, .reg = 0xc3 }, + { .mbps = 2500, .reg = 0xcc }, + { /* sentinel */ }, +}; + static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = { { .mbps = 80, .reg = 0x86 }, { .mbps = 90, .reg = 0x86 }, @@ -200,6 +231,72 @@ static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = { #define PHYPLL_REG 0x68 #define PHYPLL_HSFREQRANGE(n) ((n) << 16) +static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = { + { .mbps = 80, .reg = 0x00 }, + { .mbps = 90, .reg = 0x10 }, + { .mbps = 100, .reg = 0x20 }, + { .mbps = 110, .reg = 0x30 }, + { .mbps = 120, .reg = 0x01 }, + { .mbps = 130, .reg = 0x11 }, + { .mbps = 140, .reg = 0x21 }, + { .mbps = 150, .reg = 0x31 }, + { .mbps = 160, .reg = 0x02 }, + { .mbps = 170, .reg = 0x12 }, + { .mbps = 180, .reg = 0x22 }, + { .mbps = 190, .reg = 0x32 }, + { .mbps = 205, .reg = 0x03 }, + { .mbps = 220, .reg = 0x13 }, + { .mbps = 235, .reg = 0x23 }, + { .mbps = 250, .reg = 0x33 }, + { .mbps = 275, .reg = 0x04 }, + { .mbps = 300, .reg = 0x14 }, + { .mbps = 325, .reg = 0x25 }, + { .mbps = 350, .reg = 0x35 }, + { .mbps = 400, .reg = 0x05 }, + { .mbps = 450, .reg = 0x16 }, + { .mbps = 500, .reg = 0x26 }, + { .mbps = 550, .reg = 0x37 }, + { .mbps = 600, .reg = 0x07 }, + { .mbps = 650, .reg = 0x18 }, + { .mbps = 700, .reg = 0x28 }, + { .mbps = 750, .reg = 0x39 }, + { .mbps = 800, .reg = 0x09 }, + { .mbps = 850, .reg = 0x19 }, + { .mbps = 900, .reg = 0x29 }, + { .mbps = 950, .reg = 0x3a }, + { .mbps = 1000, .reg = 0x0a }, + { .mbps = 1050, .reg = 0x1a }, + { .mbps = 1100, .reg = 0x2a }, + { .mbps = 1150, .reg = 0x3b }, + { .mbps = 1200, .reg = 0x0b }, + { .mbps = 1250, .reg = 0x1b }, + { .mbps = 1300, .reg = 0x2b }, + { .mbps = 1350, .reg = 0x3c }, + { .mbps = 1400, .reg = 0x0c }, + { .mbps = 1450, .reg = 0x1c }, + { .mbps = 1500, .reg = 0x2c }, + { .mbps = 1550, .reg = 0x3d }, + { .mbps = 1600, .reg = 0x0d }, + { .mbps = 1650, .reg = 0x1d }, + { .mbps = 1700, .reg = 0x2e }, + { .mbps = 1750, .reg = 0x3e }, + { .mbps = 1800, .reg = 0x0e }, + { .mbps = 1850, .reg = 0x1e }, + { .mbps = 1900, .reg = 0x2f }, + { .mbps = 1950, .reg = 0x3f }, + { .mbps = 2000, .reg = 0x0f }, + { .mbps = 2050, .reg = 0x40 }, + { .mbps = 2100, .reg = 0x41 }, + { .mbps = 2150, .reg = 0x42 }, + { .mbps = 2200, .reg = 0x43 }, + { .mbps = 2300, .reg = 0x45 }, + { .mbps = 2350, .reg = 0x46 }, + { .mbps = 2400, .reg = 0x47 }, + { .mbps = 2450, .reg = 0x48 }, + { .mbps = 2500, .reg = 0x49 }, + { /* sentinel */ }, +}; + static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = { { .mbps = 80, .reg = 0x00 }, { .mbps = 90, .reg = 0x10 }, @@ -355,6 +452,7 @@ struct rcar_csi2_info { unsigned int csi0clkfreqrange; unsigned int num_channels; bool clear_ulps; + bool use_isp; }; struct rcar_csi2 { @@ -609,9 +707,12 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv) rcsi2_write(priv, PHTC_REG, 0); /* Configure */ - rcsi2_write(priv, VCDT_REG, vcdt); - if (vcdt2) - rcsi2_write(priv, VCDT2_REG, vcdt2); + if (!priv->info->use_isp) { + rcsi2_write(priv, VCDT_REG, vcdt); + if (vcdt2) + rcsi2_write(priv, VCDT2_REG, vcdt2); + } + /* Lanes are zero indexed. */ rcsi2_write(priv, LSWAP_REG, LSWAP_L0SEL(priv->lane_swap[0] - 1) | @@ -636,6 +737,11 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv) rcsi2_write(priv, CSI0CLKFCPR_REG, CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange)); + if (priv->info->use_isp) + rcsi2_write(priv, PHYFRX_REG, + PHYFRX_FORCERX_MODE_3 | PHYFRX_FORCERX_MODE_2 | + PHYFRX_FORCERX_MODE_1 | PHYFRX_FORCERX_MODE_0); + rcsi2_write(priv, PHYCNT_REG, phycnt); rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN | LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP); @@ -647,6 +753,9 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv) if (ret) return ret; + if (priv->info->use_isp) + rcsi2_write(priv, PHYFRX_REG, 0); + /* Run post PHY start initialization, if needed. */ if (priv->info->phy_post_init) { ret = priv->info->phy_post_init(priv); @@ -1063,6 +1172,62 @@ static int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv) return rcsi2_phtw_write_array(priv, step1); } +static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv, + unsigned int mbps) +{ + /* In case of 1500Mbps or less */ + static const struct phtw_value step1[] = { + { .data = 0xcc, .code = 0xe2 }, + { /* sentinel */ }, + }; + + static const struct phtw_value step2[] = { + { .data = 0x01, .code = 0xe3 }, + { .data = 0x11, .code = 0xe4 }, + { .data = 0x01, .code = 0xe5 }, + { /* sentinel */ }, + }; + + /* In case of 1500Mbps or less */ + static const struct phtw_value step3[] = { + { .data = 0x38, .code = 0x08 }, + { /* sentinel */ }, + }; + + static const struct phtw_value step4[] = { + { .data = 0x01, .code = 0x00 }, + { .data = 0x4b, .code = 0xac }, + { .data = 0x03, .code = 0x00 }, + { .data = 0x80, .code = 0x07 }, + { /* sentinel */ }, + }; + + int ret; + + if (mbps != 0 && mbps <= 1500) + ret = rcsi2_phtw_write_array(priv, step1); + else + ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3u, 0xe2); + if (ret) + return ret; + + ret = rcsi2_phtw_write_array(priv, step2); + if (ret) + return ret; + + if (mbps != 0 && mbps <= 1500) { + ret = rcsi2_phtw_write_array(priv, step3); + if (ret) + return ret; + } + + ret = rcsi2_phtw_write_array(priv, step4); + if (ret) + return ret; + + return ret; +} + /* ----------------------------------------------------------------------------- * Platform Device Driver. */ @@ -1155,6 +1320,14 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { .num_channels = 2, }; +static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = { + .init_phtw = rcsi2_init_phtw_v3u, + .hsfreqrange = hsfreqrange_v3u, + .csi0clkfreqrange = 0x20, + .clear_ulps = true, + .use_isp = true, +}; + static const struct of_device_id rcar_csi2_of_table[] = { { .compatible = "renesas,r8a774a1-csi2", @@ -1200,6 +1373,10 @@ static const struct of_device_id rcar_csi2_of_table[] = { .compatible = "renesas,r8a77990-csi2", .data = &rcar_csi2_info_r8a77990, }, + { + .compatible = "renesas,r8a779a0-csi2", + .data = &rcar_csi2_info_r8a779a0, + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, rcar_csi2_of_table); @@ -1220,7 +1397,7 @@ static int rcsi2_probe(struct platform_device *pdev) { const struct soc_device_attribute *attr; struct rcar_csi2 *priv; - unsigned int i; + unsigned int i, num_pads; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -1265,11 +1442,13 @@ static int rcsi2_probe(struct platform_device *pdev) priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; priv->subdev.entity.ops = &rcar_csi2_entity_ops; + num_pads = priv->info->use_isp ? 2 : NR_OF_RCAR_CSI2_PAD; + priv->pads[RCAR_CSI2_SINK].flags = MEDIA_PAD_FL_SINK; - for (i = RCAR_CSI2_SOURCE_VC0; i < NR_OF_RCAR_CSI2_PAD; i++) + for (i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++) priv->pads[i].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_pads_init(&priv->subdev.entity, NR_OF_RCAR_CSI2_PAD, + ret = media_entity_pads_init(&priv->subdev.entity, num_pads, priv->pads); if (ret) goto error; -- cgit v1.2.3 From b2dc5680aeb418deeacbe9628697fa0b0f2dc54a Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 9 Jul 2021 16:25:50 +0200 Subject: media: rcar-vin: Refactor controls creation for video device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The controls for the video device are created in different code paths depending on if the driver is using the media graph centric model (Gen3) or the device centric model (Gen2 and earlier). This have lead to code duplication that can be consolidated. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 82 ++++++++++++++++------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 33957cc9118c..6ea561fcd7a3 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -405,6 +405,45 @@ static const struct v4l2_ctrl_ops rvin_ctrl_ops = { .s_ctrl = rvin_s_ctrl, }; +static void rvin_free_controls(struct rvin_dev *vin) +{ + v4l2_ctrl_handler_free(&vin->ctrl_handler); + vin->vdev.ctrl_handler = NULL; +} + +static int rvin_create_controls(struct rvin_dev *vin, struct v4l2_subdev *subdev) +{ + int ret; + + ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 16); + if (ret < 0) + return ret; + + /* The VIN directly deals with alpha component. */ + v4l2_ctrl_new_std(&vin->ctrl_handler, &rvin_ctrl_ops, + V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); + + if (vin->ctrl_handler.error) { + ret = vin->ctrl_handler.error; + rvin_free_controls(vin); + return ret; + } + + /* For the non-MC mode add controls from the subdevice. */ + if (subdev) { + ret = v4l2_ctrl_add_handler(&vin->ctrl_handler, + subdev->ctrl_handler, NULL, true); + if (ret < 0) { + rvin_free_controls(vin); + return ret; + } + } + + vin->vdev.ctrl_handler = &vin->ctrl_handler; + + return 0; +} + /* ----------------------------------------------------------------------------- * Async notifier */ @@ -490,28 +529,10 @@ static int rvin_parallel_subdevice_attach(struct rvin_dev *vin, return ret; /* Add the controls */ - ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 16); + ret = rvin_create_controls(vin, subdev); if (ret < 0) return ret; - v4l2_ctrl_new_std(&vin->ctrl_handler, &rvin_ctrl_ops, - V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); - - if (vin->ctrl_handler.error) { - ret = vin->ctrl_handler.error; - v4l2_ctrl_handler_free(&vin->ctrl_handler); - return ret; - } - - ret = v4l2_ctrl_add_handler(&vin->ctrl_handler, subdev->ctrl_handler, - NULL, true); - if (ret < 0) { - v4l2_ctrl_handler_free(&vin->ctrl_handler); - return ret; - } - - vin->vdev.ctrl_handler = &vin->ctrl_handler; - vin->parallel.subdev = subdev; return 0; @@ -522,10 +543,8 @@ static void rvin_parallel_subdevice_detach(struct rvin_dev *vin) rvin_v4l2_unregister(vin); vin->parallel.subdev = NULL; - if (!vin->info->use_mc) { - v4l2_ctrl_handler_free(&vin->ctrl_handler); - vin->vdev.ctrl_handler = NULL; - } + if (!vin->info->use_mc) + rvin_free_controls(vin); } static int rvin_parallel_notify_complete(struct v4l2_async_notifier *notifier) @@ -935,21 +954,10 @@ static int rvin_mc_init(struct rvin_dev *vin) if (ret) rvin_group_put(vin); - ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 1); + ret = rvin_create_controls(vin, NULL); if (ret < 0) return ret; - v4l2_ctrl_new_std(&vin->ctrl_handler, &rvin_ctrl_ops, - V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); - - if (vin->ctrl_handler.error) { - ret = vin->ctrl_handler.error; - v4l2_ctrl_handler_free(&vin->ctrl_handler); - return ret; - } - - vin->vdev.ctrl_handler = &vin->ctrl_handler; - return ret; } @@ -1450,7 +1458,7 @@ static int rcar_vin_probe(struct platform_device *pdev) return 0; error_group_unregister: - v4l2_ctrl_handler_free(&vin->ctrl_handler); + rvin_free_controls(vin); if (vin->info->use_mc) { mutex_lock(&vin->group->lock); @@ -1485,7 +1493,7 @@ static int rcar_vin_remove(struct platform_device *pdev) rvin_group_put(vin); } - v4l2_ctrl_handler_free(&vin->ctrl_handler); + rvin_free_controls(vin); rvin_dma_unregister(vin); -- cgit v1.2.3 From 8f7112630bd0c7f43ae4fba9f054c74c1fba650a Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 9 Jul 2021 16:25:51 +0200 Subject: media: rcar-vin: Fix error paths for rvin_mc_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error paths of rvin_mc_init() do not clean up properly, fix this. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 6ea561fcd7a3..bea388075216 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -946,17 +946,23 @@ static int rvin_mc_init(struct rvin_dev *vin) if (ret) return ret; + ret = rvin_create_controls(vin, NULL); + if (ret < 0) + return ret; + ret = rvin_group_get(vin); if (ret) - return ret; + goto err_controls; ret = rvin_mc_parse_of_graph(vin); if (ret) - rvin_group_put(vin); + goto err_group; - ret = rvin_create_controls(vin, NULL); - if (ret < 0) - return ret; + return 0; +err_group: + rvin_group_put(vin); +err_controls: + rvin_free_controls(vin); return ret; } -- cgit v1.2.3 From 6df3057792911c59032327886599d9625534958a Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 9 Jul 2021 16:25:52 +0200 Subject: media: rcar-vin: Improve async notifier cleanup paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cleanup code for the async notifiers can be refactored to own functions to reduce code duplication and improve readability. While at it rename the CSI-2 initialization function _csi2_ instead of _mc_ to match. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 51 +++++++++++++++++------------ 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index bea388075216..2957fa10252f 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -383,6 +383,16 @@ out: kref_put(&group->refcount, rvin_group_release); } +static void rvin_group_notifier_cleanup(struct rvin_dev *vin) +{ + mutex_lock(&vin->group->lock); + if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) { + v4l2_async_notifier_unregister(&vin->group->notifier); + v4l2_async_notifier_cleanup(&vin->group->notifier); + } + mutex_unlock(&vin->group->lock); +} + /* ----------------------------------------------------------------------------- * Controls */ @@ -676,6 +686,12 @@ out: return ret; } +static void rvin_parallel_cleanup(struct rvin_dev *vin) +{ + v4l2_async_notifier_unregister(&vin->notifier); + v4l2_async_notifier_cleanup(&vin->notifier); +} + static int rvin_parallel_init(struct rvin_dev *vin) { int ret; @@ -937,7 +953,16 @@ static int rvin_mc_parse_of_graph(struct rvin_dev *vin) return 0; } -static int rvin_mc_init(struct rvin_dev *vin) +static void rvin_csi2_cleanup(struct rvin_dev *vin) +{ + if (!vin->info->use_mc) + return; + + rvin_group_notifier_cleanup(vin); + rvin_group_put(vin); +} + +static int rvin_csi2_init(struct rvin_dev *vin) { int ret; @@ -1449,7 +1474,7 @@ static int rcar_vin_probe(struct platform_device *pdev) platform_set_drvdata(pdev, vin); if (vin->info->use_mc) { - ret = rvin_mc_init(vin); + ret = rvin_csi2_init(vin); if (ret) goto error_dma_unregister; } @@ -1462,20 +1487,9 @@ static int rcar_vin_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); return 0; - error_group_unregister: rvin_free_controls(vin); - - if (vin->info->use_mc) { - mutex_lock(&vin->group->lock); - if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) { - v4l2_async_notifier_unregister(&vin->group->notifier); - v4l2_async_notifier_cleanup(&vin->group->notifier); - } - mutex_unlock(&vin->group->lock); - rvin_group_put(vin); - } - + rvin_csi2_cleanup(vin); error_dma_unregister: rvin_dma_unregister(vin); @@ -1490,14 +1504,9 @@ static int rcar_vin_remove(struct platform_device *pdev) rvin_v4l2_unregister(vin); - v4l2_async_notifier_unregister(&vin->notifier); - v4l2_async_notifier_cleanup(&vin->notifier); + rvin_parallel_cleanup(vin); - if (vin->info->use_mc) { - v4l2_async_notifier_unregister(&vin->group->notifier); - v4l2_async_notifier_cleanup(&vin->group->notifier); - rvin_group_put(vin); - } + rvin_csi2_cleanup(vin); rvin_free_controls(vin); -- cgit v1.2.3 From 27b9a6f9e8fe1403958b0a9fa16ed53cb3a5aa1d Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 9 Jul 2021 16:25:53 +0200 Subject: media: rcar-vin: Improve reuse of parallel notifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for adding a new media graph layout move the code reuse of the parallel notifier setup from probe directly to the current media graph initialization function. This is needed as there will be no parallel interface in the new graph layout. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 47 ++++++++++++++--------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 2957fa10252f..674766be1ad5 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -702,9 +702,8 @@ static int rvin_parallel_init(struct rvin_dev *vin) if (ret) return ret; - /* If using mc, it's fine not to have any input registered. */ if (!vin->parallel.asd) - return vin->info->use_mc ? 0 : -ENODEV; + return -ENODEV; vin_dbg(vin, "Found parallel subdevice %pOF\n", to_of_node(vin->parallel.asd->match.fwnode)); @@ -955,11 +954,10 @@ static int rvin_mc_parse_of_graph(struct rvin_dev *vin) static void rvin_csi2_cleanup(struct rvin_dev *vin) { - if (!vin->info->use_mc) - return; - + rvin_parallel_cleanup(vin); rvin_group_notifier_cleanup(vin); rvin_group_put(vin); + rvin_free_controls(vin); } static int rvin_csi2_init(struct rvin_dev *vin) @@ -979,11 +977,18 @@ static int rvin_csi2_init(struct rvin_dev *vin) if (ret) goto err_controls; + /* It's OK to not have a parallel subdevice. */ + ret = rvin_parallel_init(vin); + if (ret && ret != -ENODEV) + goto err_group; + ret = rvin_mc_parse_of_graph(vin); if (ret) - goto err_group; + goto err_parallel; return 0; +err_parallel: + rvin_parallel_cleanup(vin); err_group: rvin_group_put(vin); err_controls: @@ -1473,27 +1478,20 @@ static int rcar_vin_probe(struct platform_device *pdev) platform_set_drvdata(pdev, vin); - if (vin->info->use_mc) { + if (vin->info->use_mc) ret = rvin_csi2_init(vin); - if (ret) - goto error_dma_unregister; - } + else + ret = rvin_parallel_init(vin); - ret = rvin_parallel_init(vin); - if (ret) - goto error_group_unregister; + if (ret) { + rvin_dma_unregister(vin); + return ret; + } pm_suspend_ignore_children(&pdev->dev, true); pm_runtime_enable(&pdev->dev); return 0; -error_group_unregister: - rvin_free_controls(vin); - rvin_csi2_cleanup(vin); -error_dma_unregister: - rvin_dma_unregister(vin); - - return ret; } static int rcar_vin_remove(struct platform_device *pdev) @@ -1504,11 +1502,10 @@ static int rcar_vin_remove(struct platform_device *pdev) rvin_v4l2_unregister(vin); - rvin_parallel_cleanup(vin); - - rvin_csi2_cleanup(vin); - - rvin_free_controls(vin); + if (vin->info->use_mc) + rvin_csi2_cleanup(vin); + else + rvin_parallel_cleanup(vin); rvin_dma_unregister(vin); -- cgit v1.2.3 From 161b56a82dba29c70fd92c5eb1a8502731a0c832 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 9 Jul 2021 16:25:54 +0200 Subject: media: rcar-vin: Rename array storing subdevice information MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VIN group have always been connected to CSI-2 receivers and this have spilled over to the naming of the array storing the subdevice information. In preparation for connecting other types of subdevices rename the array to remotes. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 32 ++++++++++++++--------------- drivers/media/platform/rcar-vin/rcar-vin.h | 8 +++++--- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 674766be1ad5..a44cfa993ec8 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -49,16 +49,16 @@ */ /* group lock should be held when calling this function. */ -static int rvin_group_entity_to_csi_id(struct rvin_group *group, - struct media_entity *entity) +static int rvin_group_entity_to_remote_id(struct rvin_group *group, + struct media_entity *entity) { struct v4l2_subdev *sd; unsigned int i; sd = media_entity_to_v4l2_subdev(entity); - for (i = 0; i < RVIN_CSI_MAX; i++) - if (group->csi[i].subdev == sd) + for (i = 0; i < RVIN_REMOTES_MAX; i++) + if (group->remotes[i].subdev == sd) return i; return -ENODEV; @@ -163,14 +163,14 @@ static int rvin_group_link_notify(struct media_link *link, u32 flags, if (!csi_pad) continue; - csi_id = rvin_group_entity_to_csi_id(group, csi_pad->entity); + csi_id = rvin_group_entity_to_remote_id(group, csi_pad->entity); channel = rvin_group_csi_pad_to_channel(csi_pad->index); mask &= rvin_group_get_mask(group->vin[i], csi_id, channel); } /* Add the new link to the existing mask and check if it works. */ - csi_id = rvin_group_entity_to_csi_id(group, link->source->entity); + csi_id = rvin_group_entity_to_remote_id(group, link->source->entity); if (csi_id == -ENODEV) { struct v4l2_subdev *sd; @@ -766,10 +766,10 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) continue; /* Check that CSI-2 is part of the group. */ - if (!vin->group->csi[route->csi].subdev) + if (!vin->group->remotes[route->csi].subdev) continue; - source = &vin->group->csi[route->csi].subdev->entity; + source = &vin->group->remotes[route->csi].subdev->entity; source_idx = rvin_group_csi_channel_to_pad(route->channel); source_pad = &source->pads[source_idx]; @@ -806,10 +806,10 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, mutex_lock(&vin->group->lock); for (i = 0; i < RVIN_CSI_MAX; i++) { - if (vin->group->csi[i].asd != asd) + if (vin->group->remotes[i].asd != asd) continue; - vin->group->csi[i].subdev = NULL; - vin_dbg(vin, "Unbind CSI-2 %s from slot %u\n", subdev->name, i); + vin->group->remotes[i].subdev = NULL; + vin_dbg(vin, "Unbind %s from slot %u\n", subdev->name, i); break; } @@ -828,10 +828,10 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, mutex_lock(&vin->group->lock); for (i = 0; i < RVIN_CSI_MAX; i++) { - if (vin->group->csi[i].asd != asd) + if (vin->group->remotes[i].asd != asd) continue; - vin->group->csi[i].subdev = subdev; - vin_dbg(vin, "Bound CSI-2 %s to slot %u\n", subdev->name, i); + vin->group->remotes[i].subdev = subdev; + vin_dbg(vin, "Bound %s to slot %u\n", subdev->name, i); break; } @@ -883,7 +883,7 @@ static int rvin_mc_parse_of(struct rvin_dev *vin, unsigned int id) goto out; } - vin->group->csi[vep.base.id].asd = asd; + vin->group->remotes[vep.base.id].asd = asd; vin_dbg(vin, "Add group OF device %pOF to slot %u\n", to_of_node(fwnode), vep.base.id); @@ -928,7 +928,7 @@ static int rvin_mc_parse_of_graph(struct rvin_dev *vin) continue; for (id = 0; id < RVIN_CSI_MAX; id++) { - if (vin->group->csi[id].asd) + if (vin->group->remotes[id].asd) continue; ret = rvin_mc_parse_of(vin->group->vin[i], id); diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index b263ead4db2b..39207aaf39ef 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -48,6 +48,8 @@ enum rvin_csi_id { RVIN_CSI_MAX, }; +#define RVIN_REMOTES_MAX RVIN_CSI_MAX + /** * enum rvin_dma_state - DMA states * @STOPPED: No operation in progress @@ -267,8 +269,8 @@ struct rvin_dev { * @count: number of enabled VIN instances found in DT * @notifier: group notifier for CSI-2 async subdevices * @vin: VIN instances which are part of the group - * @csi: array of pairs of fwnode and subdev pointers - * to all CSI-2 subdevices. + * @remotes: array of pairs of fwnode and subdev pointers + * to all remote subdevices. */ struct rvin_group { struct kref refcount; @@ -283,7 +285,7 @@ struct rvin_group { struct { struct v4l2_async_subdev *asd; struct v4l2_subdev *subdev; - } csi[RVIN_CSI_MAX]; + } remotes[RVIN_REMOTES_MAX]; }; int rvin_dma_register(struct rvin_dev *vin, int irq); -- cgit v1.2.3 From 2070893aed113338f80350bd76e5956c9a8cf07f Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 9 Jul 2021 16:25:55 +0200 Subject: media: rcar-vin: Move group async notifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VIN group notifier code is intertwined with the media graph layout code for R-Car CSI-2 subdevices, this makes it hard to extend the group to also support the R-Car ISP channel selector. Before breaking the two concepts apart and extending it move the group code to its final location. There is no functional change and all functions are moved verbatim. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 460 ++++++++++++++-------------- 1 file changed, 230 insertions(+), 230 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index a44cfa993ec8..3585985e8225 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -383,6 +383,176 @@ out: kref_put(&group->refcount, rvin_group_release); } +static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) +{ + struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); + const struct rvin_group_route *route; + unsigned int i; + int ret; + + ret = media_device_register(&vin->group->mdev); + if (ret) + return ret; + + ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev); + if (ret) { + vin_err(vin, "Failed to register subdev nodes\n"); + return ret; + } + + /* Register all video nodes for the group. */ + for (i = 0; i < RCAR_VIN_NUM; i++) { + if (vin->group->vin[i] && + !video_is_registered(&vin->group->vin[i]->vdev)) { + ret = rvin_v4l2_register(vin->group->vin[i]); + if (ret) + return ret; + } + } + + /* Create all media device links between VINs and CSI-2's. */ + mutex_lock(&vin->group->lock); + for (route = vin->info->routes; route->mask; route++) { + struct media_pad *source_pad, *sink_pad; + struct media_entity *source, *sink; + unsigned int source_idx; + + /* Check that VIN is part of the group. */ + if (!vin->group->vin[route->vin]) + continue; + + /* Check that VIN' master is part of the group. */ + if (!vin->group->vin[rvin_group_id_to_master(route->vin)]) + continue; + + /* Check that CSI-2 is part of the group. */ + if (!vin->group->remotes[route->csi].subdev) + continue; + + source = &vin->group->remotes[route->csi].subdev->entity; + source_idx = rvin_group_csi_channel_to_pad(route->channel); + source_pad = &source->pads[source_idx]; + + sink = &vin->group->vin[route->vin]->vdev.entity; + sink_pad = &sink->pads[0]; + + /* Skip if link already exists. */ + if (media_entity_find_link(source_pad, sink_pad)) + continue; + + ret = media_create_pad_link(source, source_idx, sink, 0, 0); + if (ret) { + vin_err(vin, "Error adding link from %s to %s\n", + source->name, sink->name); + break; + } + } + mutex_unlock(&vin->group->lock); + + return ret; +} + +static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); + unsigned int i; + + for (i = 0; i < RCAR_VIN_NUM; i++) + if (vin->group->vin[i]) + rvin_v4l2_unregister(vin->group->vin[i]); + + mutex_lock(&vin->group->lock); + + for (i = 0; i < RVIN_CSI_MAX; i++) { + if (vin->group->remotes[i].asd != asd) + continue; + vin->group->remotes[i].subdev = NULL; + vin_dbg(vin, "Unbind %s from slot %u\n", subdev->name, i); + break; + } + + mutex_unlock(&vin->group->lock); + + media_device_unregister(&vin->group->mdev); +} + +static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); + unsigned int i; + + mutex_lock(&vin->group->lock); + + for (i = 0; i < RVIN_CSI_MAX; i++) { + if (vin->group->remotes[i].asd != asd) + continue; + vin->group->remotes[i].subdev = subdev; + vin_dbg(vin, "Bound %s to slot %u\n", subdev->name, i); + break; + } + + mutex_unlock(&vin->group->lock); + + return 0; +} + +static const struct v4l2_async_notifier_operations rvin_group_notify_ops = { + .bound = rvin_group_notify_bound, + .unbind = rvin_group_notify_unbind, + .complete = rvin_group_notify_complete, +}; + +static int rvin_mc_parse_of(struct rvin_dev *vin, unsigned int id) +{ + struct fwnode_handle *ep, *fwnode; + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct v4l2_async_subdev *asd; + int ret; + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), 1, id, 0); + if (!ep) + return 0; + + fwnode = fwnode_graph_get_remote_endpoint(ep); + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + fwnode_handle_put(ep); + if (ret) { + vin_err(vin, "Failed to parse %pOF\n", to_of_node(fwnode)); + ret = -EINVAL; + goto out; + } + + if (!of_device_is_available(to_of_node(fwnode))) { + vin_dbg(vin, "OF device %pOF disabled, ignoring\n", + to_of_node(fwnode)); + ret = -ENOTCONN; + goto out; + } + + asd = v4l2_async_notifier_add_fwnode_subdev(&vin->group->notifier, + fwnode, + struct v4l2_async_subdev); + if (IS_ERR(asd)) { + ret = PTR_ERR(asd); + goto out; + } + + vin->group->remotes[vep.base.id].asd = asd; + + vin_dbg(vin, "Add group OF device %pOF to slot %u\n", + to_of_node(fwnode), vep.base.id); +out: + fwnode_handle_put(fwnode); + + return ret; +} + static void rvin_group_notifier_cleanup(struct rvin_dev *vin) { mutex_lock(&vin->group->lock); @@ -393,6 +563,65 @@ static void rvin_group_notifier_cleanup(struct rvin_dev *vin) mutex_unlock(&vin->group->lock); } +static int rvin_mc_parse_of_graph(struct rvin_dev *vin) +{ + unsigned int count = 0, vin_mask = 0; + unsigned int i, id; + int ret; + + mutex_lock(&vin->group->lock); + + /* If not all VIN's are registered don't register the notifier. */ + for (i = 0; i < RCAR_VIN_NUM; i++) { + if (vin->group->vin[i]) { + count++; + vin_mask |= BIT(i); + } + } + + if (vin->group->count != count) { + mutex_unlock(&vin->group->lock); + return 0; + } + + mutex_unlock(&vin->group->lock); + + v4l2_async_notifier_init(&vin->group->notifier); + + /* + * Have all VIN's look for CSI-2 subdevices. Some subdevices will + * overlap but the parser function can handle it, so each subdevice + * will only be registered once with the group notifier. + */ + for (i = 0; i < RCAR_VIN_NUM; i++) { + if (!(vin_mask & BIT(i))) + continue; + + for (id = 0; id < RVIN_CSI_MAX; id++) { + if (vin->group->remotes[id].asd) + continue; + + ret = rvin_mc_parse_of(vin->group->vin[i], id); + if (ret) + return ret; + } + } + + if (list_empty(&vin->group->notifier.asd_list)) + return 0; + + vin->group->notifier.ops = &rvin_group_notify_ops; + ret = v4l2_async_notifier_register(&vin->v4l2_dev, + &vin->group->notifier); + if (ret < 0) { + vin_err(vin, "Notifier registration failed\n"); + v4l2_async_notifier_cleanup(&vin->group->notifier); + return ret; + } + + return 0; +} + /* ----------------------------------------------------------------------------- * Controls */ @@ -720,238 +949,9 @@ static int rvin_parallel_init(struct rvin_dev *vin) } /* ----------------------------------------------------------------------------- - * Group async notifier + * CSI-2 */ -static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) -{ - struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); - const struct rvin_group_route *route; - unsigned int i; - int ret; - - ret = media_device_register(&vin->group->mdev); - if (ret) - return ret; - - ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev); - if (ret) { - vin_err(vin, "Failed to register subdev nodes\n"); - return ret; - } - - /* Register all video nodes for the group. */ - for (i = 0; i < RCAR_VIN_NUM; i++) { - if (vin->group->vin[i] && - !video_is_registered(&vin->group->vin[i]->vdev)) { - ret = rvin_v4l2_register(vin->group->vin[i]); - if (ret) - return ret; - } - } - - /* Create all media device links between VINs and CSI-2's. */ - mutex_lock(&vin->group->lock); - for (route = vin->info->routes; route->mask; route++) { - struct media_pad *source_pad, *sink_pad; - struct media_entity *source, *sink; - unsigned int source_idx; - - /* Check that VIN is part of the group. */ - if (!vin->group->vin[route->vin]) - continue; - - /* Check that VIN' master is part of the group. */ - if (!vin->group->vin[rvin_group_id_to_master(route->vin)]) - continue; - - /* Check that CSI-2 is part of the group. */ - if (!vin->group->remotes[route->csi].subdev) - continue; - - source = &vin->group->remotes[route->csi].subdev->entity; - source_idx = rvin_group_csi_channel_to_pad(route->channel); - source_pad = &source->pads[source_idx]; - - sink = &vin->group->vin[route->vin]->vdev.entity; - sink_pad = &sink->pads[0]; - - /* Skip if link already exists. */ - if (media_entity_find_link(source_pad, sink_pad)) - continue; - - ret = media_create_pad_link(source, source_idx, sink, 0, 0); - if (ret) { - vin_err(vin, "Error adding link from %s to %s\n", - source->name, sink->name); - break; - } - } - mutex_unlock(&vin->group->lock); - - return ret; -} - -static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd) -{ - struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); - unsigned int i; - - for (i = 0; i < RCAR_VIN_NUM; i++) - if (vin->group->vin[i]) - rvin_v4l2_unregister(vin->group->vin[i]); - - mutex_lock(&vin->group->lock); - - for (i = 0; i < RVIN_CSI_MAX; i++) { - if (vin->group->remotes[i].asd != asd) - continue; - vin->group->remotes[i].subdev = NULL; - vin_dbg(vin, "Unbind %s from slot %u\n", subdev->name, i); - break; - } - - mutex_unlock(&vin->group->lock); - - media_device_unregister(&vin->group->mdev); -} - -static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd) -{ - struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); - unsigned int i; - - mutex_lock(&vin->group->lock); - - for (i = 0; i < RVIN_CSI_MAX; i++) { - if (vin->group->remotes[i].asd != asd) - continue; - vin->group->remotes[i].subdev = subdev; - vin_dbg(vin, "Bound %s to slot %u\n", subdev->name, i); - break; - } - - mutex_unlock(&vin->group->lock); - - return 0; -} - -static const struct v4l2_async_notifier_operations rvin_group_notify_ops = { - .bound = rvin_group_notify_bound, - .unbind = rvin_group_notify_unbind, - .complete = rvin_group_notify_complete, -}; - -static int rvin_mc_parse_of(struct rvin_dev *vin, unsigned int id) -{ - struct fwnode_handle *ep, *fwnode; - struct v4l2_fwnode_endpoint vep = { - .bus_type = V4L2_MBUS_CSI2_DPHY, - }; - struct v4l2_async_subdev *asd; - int ret; - - ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), 1, id, 0); - if (!ep) - return 0; - - fwnode = fwnode_graph_get_remote_endpoint(ep); - ret = v4l2_fwnode_endpoint_parse(ep, &vep); - fwnode_handle_put(ep); - if (ret) { - vin_err(vin, "Failed to parse %pOF\n", to_of_node(fwnode)); - ret = -EINVAL; - goto out; - } - - if (!of_device_is_available(to_of_node(fwnode))) { - vin_dbg(vin, "OF device %pOF disabled, ignoring\n", - to_of_node(fwnode)); - ret = -ENOTCONN; - goto out; - } - - asd = v4l2_async_notifier_add_fwnode_subdev(&vin->group->notifier, - fwnode, - struct v4l2_async_subdev); - if (IS_ERR(asd)) { - ret = PTR_ERR(asd); - goto out; - } - - vin->group->remotes[vep.base.id].asd = asd; - - vin_dbg(vin, "Add group OF device %pOF to slot %u\n", - to_of_node(fwnode), vep.base.id); -out: - fwnode_handle_put(fwnode); - - return ret; -} - -static int rvin_mc_parse_of_graph(struct rvin_dev *vin) -{ - unsigned int count = 0, vin_mask = 0; - unsigned int i, id; - int ret; - - mutex_lock(&vin->group->lock); - - /* If not all VIN's are registered don't register the notifier. */ - for (i = 0; i < RCAR_VIN_NUM; i++) { - if (vin->group->vin[i]) { - count++; - vin_mask |= BIT(i); - } - } - - if (vin->group->count != count) { - mutex_unlock(&vin->group->lock); - return 0; - } - - mutex_unlock(&vin->group->lock); - - v4l2_async_notifier_init(&vin->group->notifier); - - /* - * Have all VIN's look for CSI-2 subdevices. Some subdevices will - * overlap but the parser function can handle it, so each subdevice - * will only be registered once with the group notifier. - */ - for (i = 0; i < RCAR_VIN_NUM; i++) { - if (!(vin_mask & BIT(i))) - continue; - - for (id = 0; id < RVIN_CSI_MAX; id++) { - if (vin->group->remotes[id].asd) - continue; - - ret = rvin_mc_parse_of(vin->group->vin[i], id); - if (ret) - return ret; - } - } - - if (list_empty(&vin->group->notifier.asd_list)) - return 0; - - vin->group->notifier.ops = &rvin_group_notify_ops; - ret = v4l2_async_notifier_register(&vin->v4l2_dev, - &vin->group->notifier); - if (ret < 0) { - vin_err(vin, "Notifier registration failed\n"); - v4l2_async_notifier_cleanup(&vin->group->notifier); - return ret; - } - - return 0; -} - static void rvin_csi2_cleanup(struct rvin_dev *vin) { rvin_parallel_cleanup(vin); -- cgit v1.2.3 From 9c83300146b3ef592273ff8b09884d6181be3020 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 9 Jul 2021 16:25:56 +0200 Subject: media: rcar-vin: Extend group notifier DT parser to work with any port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The R-Car VIN group notifier will be extend to support a new group of subdevices, the R-Car ISP channel selector in addition to the existing R-Car CSI-2 receiver subdevices. The existing DT parsing code can be reused if the port and max number of endpoints are provided as parameters instead of being hard-coded. While at it align the group notifier parser function names with the rest of the driver. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 3585985e8225..ae2a145b04f6 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -506,7 +506,8 @@ static const struct v4l2_async_notifier_operations rvin_group_notify_ops = { .complete = rvin_group_notify_complete, }; -static int rvin_mc_parse_of(struct rvin_dev *vin, unsigned int id) +static int rvin_group_parse_of(struct rvin_dev *vin, unsigned int port, + unsigned int id) { struct fwnode_handle *ep, *fwnode; struct v4l2_fwnode_endpoint vep = { @@ -515,7 +516,7 @@ static int rvin_mc_parse_of(struct rvin_dev *vin, unsigned int id) struct v4l2_async_subdev *asd; int ret; - ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), 1, id, 0); + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), port, id, 0); if (!ep) return 0; @@ -563,7 +564,8 @@ static void rvin_group_notifier_cleanup(struct rvin_dev *vin) mutex_unlock(&vin->group->lock); } -static int rvin_mc_parse_of_graph(struct rvin_dev *vin) +static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port, + unsigned int max_id) { unsigned int count = 0, vin_mask = 0; unsigned int i, id; @@ -589,19 +591,18 @@ static int rvin_mc_parse_of_graph(struct rvin_dev *vin) v4l2_async_notifier_init(&vin->group->notifier); /* - * Have all VIN's look for CSI-2 subdevices. Some subdevices will - * overlap but the parser function can handle it, so each subdevice - * will only be registered once with the group notifier. + * Some subdevices may overlap but the parser function can handle it and + * each subdevice will only be registered once with the group notifier. */ for (i = 0; i < RCAR_VIN_NUM; i++) { if (!(vin_mask & BIT(i))) continue; - for (id = 0; id < RVIN_CSI_MAX; id++) { + for (id = 0; id < max_id; id++) { if (vin->group->remotes[id].asd) continue; - ret = rvin_mc_parse_of(vin->group->vin[i], id); + ret = rvin_group_parse_of(vin->group->vin[i], port, id); if (ret) return ret; } @@ -982,7 +983,7 @@ static int rvin_csi2_init(struct rvin_dev *vin) if (ret && ret != -ENODEV) goto err_group; - ret = rvin_mc_parse_of_graph(vin); + ret = rvin_group_notifier_init(vin, 1, RVIN_CSI_MAX); if (ret) goto err_parallel; -- cgit v1.2.3 From cfef0c833a8dddf09d9f7d490a0fadbe81b91793 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 9 Jul 2021 16:25:57 +0200 Subject: media: rcar-vin: Create a callback to setup media links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New IP versions will have different media graphs and require a different link setup. Breakout the specific link setup to a callback that are associated with the group. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 101 +++++++++++++++------------- drivers/media/platform/rcar-vin/rcar-vin.h | 3 + 2 files changed, 59 insertions(+), 45 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index ae2a145b04f6..d04c222702ba 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -247,7 +247,8 @@ static void rvin_group_cleanup(struct rvin_group *group) mutex_destroy(&group->lock); } -static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin) +static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin, + int (*link_setup)(struct rvin_dev *)) { struct media_device *mdev = &group->mdev; const struct of_device_id *match; @@ -263,6 +264,8 @@ static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin) vin_dbg(vin, "found %u enabled VIN's in DT", group->count); + group->link_setup = link_setup; + mdev->dev = vin->dev; mdev->ops = &rvin_media_ops; @@ -295,7 +298,8 @@ static void rvin_group_release(struct kref *kref) mutex_unlock(&rvin_group_lock); } -static int rvin_group_get(struct rvin_dev *vin) +static int rvin_group_get(struct rvin_dev *vin, + int (*link_setup)(struct rvin_dev *)) { struct rvin_group *group; u32 id; @@ -327,7 +331,7 @@ static int rvin_group_get(struct rvin_dev *vin) goto err_group; } - ret = rvin_group_init(group, vin); + ret = rvin_group_init(group, vin, link_setup); if (ret) { kfree(group); vin_err(vin, "Failed to initialize group\n"); @@ -386,7 +390,6 @@ out: static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) { struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); - const struct rvin_group_route *route; unsigned int i; int ret; @@ -410,46 +413,7 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) } } - /* Create all media device links between VINs and CSI-2's. */ - mutex_lock(&vin->group->lock); - for (route = vin->info->routes; route->mask; route++) { - struct media_pad *source_pad, *sink_pad; - struct media_entity *source, *sink; - unsigned int source_idx; - - /* Check that VIN is part of the group. */ - if (!vin->group->vin[route->vin]) - continue; - - /* Check that VIN' master is part of the group. */ - if (!vin->group->vin[rvin_group_id_to_master(route->vin)]) - continue; - - /* Check that CSI-2 is part of the group. */ - if (!vin->group->remotes[route->csi].subdev) - continue; - - source = &vin->group->remotes[route->csi].subdev->entity; - source_idx = rvin_group_csi_channel_to_pad(route->channel); - source_pad = &source->pads[source_idx]; - - sink = &vin->group->vin[route->vin]->vdev.entity; - sink_pad = &sink->pads[0]; - - /* Skip if link already exists. */ - if (media_entity_find_link(source_pad, sink_pad)) - continue; - - ret = media_create_pad_link(source, source_idx, sink, 0, 0); - if (ret) { - vin_err(vin, "Error adding link from %s to %s\n", - source->name, sink->name); - break; - } - } - mutex_unlock(&vin->group->lock); - - return ret; + return vin->group->link_setup(vin); } static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, @@ -953,6 +917,53 @@ static int rvin_parallel_init(struct rvin_dev *vin) * CSI-2 */ +static int rvin_csi2_setup_links(struct rvin_dev *vin) +{ + const struct rvin_group_route *route; + int ret = -EINVAL; + + /* Create all media device links between VINs and CSI-2's. */ + mutex_lock(&vin->group->lock); + for (route = vin->info->routes; route->mask; route++) { + struct media_pad *source_pad, *sink_pad; + struct media_entity *source, *sink; + unsigned int source_idx; + + /* Check that VIN is part of the group. */ + if (!vin->group->vin[route->vin]) + continue; + + /* Check that VIN' master is part of the group. */ + if (!vin->group->vin[rvin_group_id_to_master(route->vin)]) + continue; + + /* Check that CSI-2 is part of the group. */ + if (!vin->group->remotes[route->csi].subdev) + continue; + + source = &vin->group->remotes[route->csi].subdev->entity; + source_idx = rvin_group_csi_channel_to_pad(route->channel); + source_pad = &source->pads[source_idx]; + + sink = &vin->group->vin[route->vin]->vdev.entity; + sink_pad = &sink->pads[0]; + + /* Skip if link already exists. */ + if (media_entity_find_link(source_pad, sink_pad)) + continue; + + ret = media_create_pad_link(source, source_idx, sink, 0, 0); + if (ret) { + vin_err(vin, "Error adding link from %s to %s\n", + source->name, sink->name); + break; + } + } + mutex_unlock(&vin->group->lock); + + return ret; +} + static void rvin_csi2_cleanup(struct rvin_dev *vin) { rvin_parallel_cleanup(vin); @@ -974,7 +985,7 @@ static int rvin_csi2_init(struct rvin_dev *vin) if (ret < 0) return ret; - ret = rvin_group_get(vin); + ret = rvin_group_get(vin, rvin_csi2_setup_links); if (ret) goto err_controls; diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 39207aaf39ef..49c148c40ea5 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -269,6 +269,7 @@ struct rvin_dev { * @count: number of enabled VIN instances found in DT * @notifier: group notifier for CSI-2 async subdevices * @vin: VIN instances which are part of the group + * @link_setup: Callback to create all links for the media graph * @remotes: array of pairs of fwnode and subdev pointers * to all remote subdevices. */ @@ -282,6 +283,8 @@ struct rvin_group { struct v4l2_async_notifier notifier; struct rvin_dev *vin[RCAR_VIN_NUM]; + int (*link_setup)(struct rvin_dev *vin); + struct { struct v4l2_async_subdev *asd; struct v4l2_subdev *subdev; -- cgit v1.2.3 From c370dd7fa8dc8d2cba1d9efe0515a3c808343790 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 9 Jul 2021 16:25:58 +0200 Subject: media: rcar-vin: Specify media device ops at group creation time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The media device operations structure will be different depending on what media graph layout is used. Instead of hard-coding the R-Car CSI-2 layout allow the operations to be passed as an argument. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index d04c222702ba..8c27d9d5ca7e 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -248,7 +248,8 @@ static void rvin_group_cleanup(struct rvin_group *group) } static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin, - int (*link_setup)(struct rvin_dev *)) + int (*link_setup)(struct rvin_dev *), + const struct media_device_ops *ops) { struct media_device *mdev = &group->mdev; const struct of_device_id *match; @@ -267,7 +268,7 @@ static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin, group->link_setup = link_setup; mdev->dev = vin->dev; - mdev->ops = &rvin_media_ops; + mdev->ops = ops; match = of_match_node(vin->dev->driver->of_match_table, vin->dev->of_node); @@ -299,7 +300,8 @@ static void rvin_group_release(struct kref *kref) } static int rvin_group_get(struct rvin_dev *vin, - int (*link_setup)(struct rvin_dev *)) + int (*link_setup)(struct rvin_dev *), + const struct media_device_ops *ops) { struct rvin_group *group; u32 id; @@ -331,7 +333,7 @@ static int rvin_group_get(struct rvin_dev *vin, goto err_group; } - ret = rvin_group_init(group, vin, link_setup); + ret = rvin_group_init(group, vin, link_setup, ops); if (ret) { kfree(group); vin_err(vin, "Failed to initialize group\n"); @@ -985,7 +987,7 @@ static int rvin_csi2_init(struct rvin_dev *vin) if (ret < 0) return ret; - ret = rvin_group_get(vin, rvin_csi2_setup_links); + ret = rvin_group_get(vin, rvin_csi2_setup_links, &rvin_media_ops); if (ret) goto err_controls; -- cgit v1.2.3 From 688565db3f9d84026969afd3f081f26afd12a9cc Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 9 Jul 2021 16:25:59 +0200 Subject: media: rcar-vin: Move and rename CSI-2 link notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CSI-2 link notifications are no longer the only option for the VIN group. Change the symbol prefix to rvin_csi2_ for all CSI-2 specific code and move the link notification code to the correct section not to mix it with the soon to be added R-Car ISP channel selector notification helpers. There is no functional change and apart from the symbol prefix change all functions are moved verbatim. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 362 ++++++++++++++-------------- 1 file changed, 179 insertions(+), 183 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 8c27d9d5ca7e..0653e1ce1448 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -45,188 +45,7 @@ #define v4l2_dev_to_vin(d) container_of(d, struct rvin_dev, v4l2_dev) /* ----------------------------------------------------------------------------- - * Media Controller link notification - */ - -/* group lock should be held when calling this function. */ -static int rvin_group_entity_to_remote_id(struct rvin_group *group, - struct media_entity *entity) -{ - struct v4l2_subdev *sd; - unsigned int i; - - sd = media_entity_to_v4l2_subdev(entity); - - for (i = 0; i < RVIN_REMOTES_MAX; i++) - if (group->remotes[i].subdev == sd) - return i; - - return -ENODEV; -} - -static unsigned int rvin_group_get_mask(struct rvin_dev *vin, - enum rvin_csi_id csi_id, - unsigned char channel) -{ - const struct rvin_group_route *route; - unsigned int mask = 0; - - for (route = vin->info->routes; route->mask; route++) { - if (route->vin == vin->id && - route->csi == csi_id && - route->channel == channel) { - vin_dbg(vin, - "Adding route: vin: %d csi: %d channel: %d\n", - route->vin, route->csi, route->channel); - mask |= route->mask; - } - } - - return mask; -} - -/* - * Link setup for the links between a VIN and a CSI-2 receiver is a bit - * complex. The reason for this is that the register controlling routing - * is not present in each VIN instance. There are special VINs which - * control routing for themselves and other VINs. There are not many - * different possible links combinations that can be enabled at the same - * time, therefor all already enabled links which are controlled by a - * master VIN need to be taken into account when making the decision - * if a new link can be enabled or not. - * - * 1. Find out which VIN the link the user tries to enable is connected to. - * 2. Lookup which master VIN controls the links for this VIN. - * 3. Start with a bitmask with all bits set. - * 4. For each previously enabled link from the master VIN bitwise AND its - * route mask (see documentation for mask in struct rvin_group_route) - * with the bitmask. - * 5. Bitwise AND the mask for the link the user tries to enable to the bitmask. - * 6. If the bitmask is not empty at this point the new link can be enabled - * while keeping all previous links enabled. Update the CHSEL value of the - * master VIN and inform the user that the link could be enabled. - * - * Please note that no link can be enabled if any VIN in the group is - * currently open. - */ -static int rvin_group_link_notify(struct media_link *link, u32 flags, - unsigned int notification) -{ - struct rvin_group *group = container_of(link->graph_obj.mdev, - struct rvin_group, mdev); - unsigned int master_id, channel, mask_new, i; - unsigned int mask = ~0; - struct media_entity *entity; - struct video_device *vdev; - struct media_pad *csi_pad; - struct rvin_dev *vin = NULL; - int csi_id, ret; - - ret = v4l2_pipeline_link_notify(link, flags, notification); - if (ret) - return ret; - - /* Only care about link enablement for VIN nodes. */ - if (!(flags & MEDIA_LNK_FL_ENABLED) || - !is_media_entity_v4l2_video_device(link->sink->entity)) - return 0; - - /* - * Don't allow link changes if any entity in the graph is - * streaming, modifying the CHSEL register fields can disrupt - * running streams. - */ - media_device_for_each_entity(entity, &group->mdev) - if (entity->stream_count) - return -EBUSY; - - mutex_lock(&group->lock); - - /* Find the master VIN that controls the routes. */ - vdev = media_entity_to_video_device(link->sink->entity); - vin = container_of(vdev, struct rvin_dev, vdev); - master_id = rvin_group_id_to_master(vin->id); - - if (WARN_ON(!group->vin[master_id])) { - ret = -ENODEV; - goto out; - } - - /* Build a mask for already enabled links. */ - for (i = master_id; i < master_id + 4; i++) { - if (!group->vin[i]) - continue; - - /* Get remote CSI-2, if any. */ - csi_pad = media_entity_remote_pad( - &group->vin[i]->vdev.entity.pads[0]); - if (!csi_pad) - continue; - - csi_id = rvin_group_entity_to_remote_id(group, csi_pad->entity); - channel = rvin_group_csi_pad_to_channel(csi_pad->index); - - mask &= rvin_group_get_mask(group->vin[i], csi_id, channel); - } - - /* Add the new link to the existing mask and check if it works. */ - csi_id = rvin_group_entity_to_remote_id(group, link->source->entity); - - if (csi_id == -ENODEV) { - struct v4l2_subdev *sd; - - /* - * Make sure the source entity subdevice is registered as - * a parallel input of one of the enabled VINs if it is not - * one of the CSI-2 subdevices. - * - * No hardware configuration required for parallel inputs, - * we can return here. - */ - sd = media_entity_to_v4l2_subdev(link->source->entity); - for (i = 0; i < RCAR_VIN_NUM; i++) { - if (group->vin[i] && - group->vin[i]->parallel.subdev == sd) { - group->vin[i]->is_csi = false; - ret = 0; - goto out; - } - } - - vin_err(vin, "Subdevice %s not registered to any VIN\n", - link->source->entity->name); - ret = -ENODEV; - goto out; - } - - channel = rvin_group_csi_pad_to_channel(link->source->index); - mask_new = mask & rvin_group_get_mask(vin, csi_id, channel); - vin_dbg(vin, "Try link change mask: 0x%x new: 0x%x\n", mask, mask_new); - - if (!mask_new) { - ret = -EMLINK; - goto out; - } - - /* New valid CHSEL found, set the new value. */ - ret = rvin_set_channel_routing(group->vin[master_id], __ffs(mask_new)); - if (ret) - goto out; - - vin->is_csi = true; - -out: - mutex_unlock(&group->lock); - - return ret; -} - -static const struct media_device_ops rvin_media_ops = { - .link_notify = rvin_group_link_notify, -}; - -/* ----------------------------------------------------------------------------- - * Gen3 CSI2 Group Allocator + * Gen3 Group Allocator */ /* FIXME: This should if we find a system that supports more @@ -389,6 +208,22 @@ out: kref_put(&group->refcount, rvin_group_release); } +/* group lock should be held when calling this function. */ +static int rvin_group_entity_to_remote_id(struct rvin_group *group, + struct media_entity *entity) +{ + struct v4l2_subdev *sd; + unsigned int i; + + sd = media_entity_to_v4l2_subdev(entity); + + for (i = 0; i < RVIN_REMOTES_MAX; i++) + if (group->remotes[i].subdev == sd) + return i; + + return -ENODEV; +} + static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) { struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); @@ -919,6 +754,167 @@ static int rvin_parallel_init(struct rvin_dev *vin) * CSI-2 */ +static unsigned int rvin_csi2_get_mask(struct rvin_dev *vin, + enum rvin_csi_id csi_id, + unsigned char channel) +{ + const struct rvin_group_route *route; + unsigned int mask = 0; + + for (route = vin->info->routes; route->mask; route++) { + if (route->vin == vin->id && + route->csi == csi_id && + route->channel == channel) { + vin_dbg(vin, + "Adding route: vin: %d csi: %d channel: %d\n", + route->vin, route->csi, route->channel); + mask |= route->mask; + } + } + + return mask; +} + +/* + * Link setup for the links between a VIN and a CSI-2 receiver is a bit + * complex. The reason for this is that the register controlling routing + * is not present in each VIN instance. There are special VINs which + * control routing for themselves and other VINs. There are not many + * different possible links combinations that can be enabled at the same + * time, therefor all already enabled links which are controlled by a + * master VIN need to be taken into account when making the decision + * if a new link can be enabled or not. + * + * 1. Find out which VIN the link the user tries to enable is connected to. + * 2. Lookup which master VIN controls the links for this VIN. + * 3. Start with a bitmask with all bits set. + * 4. For each previously enabled link from the master VIN bitwise AND its + * route mask (see documentation for mask in struct rvin_group_route) + * with the bitmask. + * 5. Bitwise AND the mask for the link the user tries to enable to the bitmask. + * 6. If the bitmask is not empty at this point the new link can be enabled + * while keeping all previous links enabled. Update the CHSEL value of the + * master VIN and inform the user that the link could be enabled. + * + * Please note that no link can be enabled if any VIN in the group is + * currently open. + */ +static int rvin_csi2_link_notify(struct media_link *link, u32 flags, + unsigned int notification) +{ + struct rvin_group *group = container_of(link->graph_obj.mdev, + struct rvin_group, mdev); + unsigned int master_id, channel, mask_new, i; + unsigned int mask = ~0; + struct media_entity *entity; + struct video_device *vdev; + struct media_pad *csi_pad; + struct rvin_dev *vin = NULL; + int csi_id, ret; + + ret = v4l2_pipeline_link_notify(link, flags, notification); + if (ret) + return ret; + + /* Only care about link enablement for VIN nodes. */ + if (!(flags & MEDIA_LNK_FL_ENABLED) || + !is_media_entity_v4l2_video_device(link->sink->entity)) + return 0; + + /* + * Don't allow link changes if any entity in the graph is + * streaming, modifying the CHSEL register fields can disrupt + * running streams. + */ + media_device_for_each_entity(entity, &group->mdev) + if (entity->stream_count) + return -EBUSY; + + mutex_lock(&group->lock); + + /* Find the master VIN that controls the routes. */ + vdev = media_entity_to_video_device(link->sink->entity); + vin = container_of(vdev, struct rvin_dev, vdev); + master_id = rvin_group_id_to_master(vin->id); + + if (WARN_ON(!group->vin[master_id])) { + ret = -ENODEV; + goto out; + } + + /* Build a mask for already enabled links. */ + for (i = master_id; i < master_id + 4; i++) { + if (!group->vin[i]) + continue; + + /* Get remote CSI-2, if any. */ + csi_pad = media_entity_remote_pad( + &group->vin[i]->vdev.entity.pads[0]); + if (!csi_pad) + continue; + + csi_id = rvin_group_entity_to_remote_id(group, csi_pad->entity); + channel = rvin_group_csi_pad_to_channel(csi_pad->index); + + mask &= rvin_csi2_get_mask(group->vin[i], csi_id, channel); + } + + /* Add the new link to the existing mask and check if it works. */ + csi_id = rvin_group_entity_to_remote_id(group, link->source->entity); + + if (csi_id == -ENODEV) { + struct v4l2_subdev *sd; + + /* + * Make sure the source entity subdevice is registered as + * a parallel input of one of the enabled VINs if it is not + * one of the CSI-2 subdevices. + * + * No hardware configuration required for parallel inputs, + * we can return here. + */ + sd = media_entity_to_v4l2_subdev(link->source->entity); + for (i = 0; i < RCAR_VIN_NUM; i++) { + if (group->vin[i] && + group->vin[i]->parallel.subdev == sd) { + group->vin[i]->is_csi = false; + ret = 0; + goto out; + } + } + + vin_err(vin, "Subdevice %s not registered to any VIN\n", + link->source->entity->name); + ret = -ENODEV; + goto out; + } + + channel = rvin_group_csi_pad_to_channel(link->source->index); + mask_new = mask & rvin_csi2_get_mask(vin, csi_id, channel); + vin_dbg(vin, "Try link change mask: 0x%x new: 0x%x\n", mask, mask_new); + + if (!mask_new) { + ret = -EMLINK; + goto out; + } + + /* New valid CHSEL found, set the new value. */ + ret = rvin_set_channel_routing(group->vin[master_id], __ffs(mask_new)); + if (ret) + goto out; + + vin->is_csi = true; + +out: + mutex_unlock(&group->lock); + + return ret; +} + +static const struct media_device_ops rvin_csi2_media_ops = { + .link_notify = rvin_csi2_link_notify, +}; + static int rvin_csi2_setup_links(struct rvin_dev *vin) { const struct rvin_group_route *route; @@ -987,7 +983,7 @@ static int rvin_csi2_init(struct rvin_dev *vin) if (ret < 0) return ret; - ret = rvin_group_get(vin, rvin_csi2_setup_links, &rvin_media_ops); + ret = rvin_group_get(vin, rvin_csi2_setup_links, &rvin_csi2_media_ops); if (ret) goto err_controls; -- cgit v1.2.3 From 406bb586dec096274b598944033fad220dfc0d00 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 21 Jul 2021 10:53:57 +0200 Subject: media: rcar-vin: Add r8a779a0 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the R-Car V3U (r8a779a0) to the driver. The V3U has the VIN modules connected to a ISP instead of directly to the R-Car CSI-2 receivers. The reason being that the ISP performs channel selection based on CSI-2 VC/DT pairs and routes the video data to different VIN modules. In other SoC versions this filtering is done by the VIN modules themself. While the media graph is very different from other SoCs the only difference in operating the VIN modules is that the VC/DT filtering should be skipped as that is performed by the ISP. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 106 +++++++++++++++++++++++++++- drivers/media/platform/rcar-vin/rcar-dma.c | 22 +++--- drivers/media/platform/rcar-vin/rcar-vin.h | 16 ++++- 3 files changed, 130 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 0653e1ce1448..690e3f7e5a1c 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -1007,6 +1007,91 @@ err_controls: return ret; } +/* ----------------------------------------------------------------------------- + * ISP + */ + +static int rvin_isp_setup_links(struct rvin_dev *vin) +{ + unsigned int i; + int ret = -EINVAL; + + /* Create all media device links between VINs and ISP's. */ + mutex_lock(&vin->group->lock); + for (i = 0; i < RCAR_VIN_NUM; i++) { + struct media_pad *source_pad, *sink_pad; + struct media_entity *source, *sink; + unsigned int source_slot = i / 8; + unsigned int source_idx = i % 8 + 1; + + if (!vin->group->vin[i]) + continue; + + /* Check that ISP is part of the group. */ + if (!vin->group->remotes[source_slot].subdev) + continue; + + source = &vin->group->remotes[source_slot].subdev->entity; + source_pad = &source->pads[source_idx]; + + sink = &vin->group->vin[i]->vdev.entity; + sink_pad = &sink->pads[0]; + + /* Skip if link already exists. */ + if (media_entity_find_link(source_pad, sink_pad)) + continue; + + ret = media_create_pad_link(source, source_idx, sink, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + vin_err(vin, "Error adding link from %s to %s\n", + source->name, sink->name); + break; + } + } + mutex_unlock(&vin->group->lock); + + return ret; +} + +static void rvin_isp_cleanup(struct rvin_dev *vin) +{ + rvin_group_notifier_cleanup(vin); + rvin_group_put(vin); + rvin_free_controls(vin); +} + +static int rvin_isp_init(struct rvin_dev *vin) +{ + int ret; + + vin->pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vin->vdev.entity, 1, &vin->pad); + if (ret) + return ret; + + ret = rvin_create_controls(vin, NULL); + if (ret < 0) + return ret; + + ret = rvin_group_get(vin, rvin_isp_setup_links, NULL); + if (ret) + goto err_controls; + + ret = rvin_group_notifier_init(vin, 2, RVIN_ISP_MAX); + if (ret) + goto err_group; + + return 0; +err_group: + rvin_group_put(vin); +err_controls: + rvin_free_controls(vin); + + return ret; +} + /* ----------------------------------------------------------------------------- * Suspend / Resume */ @@ -1379,6 +1464,15 @@ static const struct rvin_info rcar_info_r8a77995 = { .routes = rcar_info_r8a77995_routes, }; +static const struct rvin_info rcar_info_r8a779a0 = { + .model = RCAR_GEN3, + .use_mc = true, + .use_isp = true, + .nv12 = true, + .max_width = 4096, + .max_height = 4096, +}; + static const struct of_device_id rvin_of_id_table[] = { { .compatible = "renesas,vin-r8a774a1", @@ -1440,6 +1534,10 @@ static const struct of_device_id rvin_of_id_table[] = { .compatible = "renesas,vin-r8a77995", .data = &rcar_info_r8a77995, }, + { + .compatible = "renesas,vin-r8a779a0", + .data = &rcar_info_r8a779a0, + }, { /* Sentinel */ }, }; MODULE_DEVICE_TABLE(of, rvin_of_id_table); @@ -1488,7 +1586,9 @@ static int rcar_vin_probe(struct platform_device *pdev) platform_set_drvdata(pdev, vin); - if (vin->info->use_mc) + if (vin->info->use_isp) + ret = rvin_isp_init(vin); + else if (vin->info->use_mc) ret = rvin_csi2_init(vin); else ret = rvin_parallel_init(vin); @@ -1512,7 +1612,9 @@ static int rcar_vin_remove(struct platform_device *pdev) rvin_v4l2_unregister(vin); - if (vin->info->use_mc) + if (vin->info->use_isp) + rvin_isp_cleanup(vin); + else if (vin->info->use_mc) rvin_csi2_cleanup(vin); else rvin_parallel_cleanup(vin); diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index f5f722ab1d4e..58718e52ae54 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -783,16 +783,18 @@ static int rvin_setup(struct rvin_dev *vin) /* Always update on field change */ vnmc |= VNMC_VUP; - /* If input and output use the same colorspace, use bypass mode */ - if (input_is_yuv == output_is_yuv) - vnmc |= VNMC_BPS; - - if (vin->info->model == RCAR_GEN3) { - /* Select between CSI-2 and parallel input */ - if (vin->is_csi) - vnmc &= ~VNMC_DPINE; - else - vnmc |= VNMC_DPINE; + if (!vin->info->use_isp) { + /* If input and output use the same colorspace, use bypass mode */ + if (input_is_yuv == output_is_yuv) + vnmc |= VNMC_BPS; + + if (vin->info->model == RCAR_GEN3) { + /* Select between CSI-2 and parallel input */ + if (vin->is_csi) + vnmc &= ~VNMC_DPINE; + else + vnmc |= VNMC_DPINE; + } } /* Progressive or interlaced mode */ diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 49c148c40ea5..6c06320174a2 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -29,7 +29,7 @@ #define HW_BUFFER_MASK 0x7f /* Max number on VIN instances that can be in a system */ -#define RCAR_VIN_NUM 8 +#define RCAR_VIN_NUM 32 struct rvin_group; @@ -48,7 +48,17 @@ enum rvin_csi_id { RVIN_CSI_MAX, }; -#define RVIN_REMOTES_MAX RVIN_CSI_MAX +enum rvin_isp_id { + RVIN_ISP0, + RVIN_ISP1, + RVIN_ISP2, + RVIN_ISP4, + RVIN_ISP_MAX, +}; + +#define RVIN_REMOTES_MAX \ + (((unsigned int)RVIN_CSI_MAX) > ((unsigned int)RVIN_ISP_MAX) ? \ + RVIN_CSI_MAX : RVIN_ISP_MAX) /** * enum rvin_dma_state - DMA states @@ -149,6 +159,7 @@ struct rvin_group_route { * struct rvin_info - Information about the particular VIN implementation * @model: VIN model * @use_mc: use media controller instead of controlling subdevice + * @use_isp: the VIN is connected to the ISP and not to the CSI-2 * @nv12: support outputing NV12 pixel format * @max_width: max input width the VIN supports * @max_height: max input height the VIN supports @@ -158,6 +169,7 @@ struct rvin_group_route { struct rvin_info { enum model_id model; bool use_mc; + bool use_isp; bool nv12; unsigned int max_width; -- cgit v1.2.3 From 3c8c153914812a98eaa0b5a6cf09c511a06aafbe Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 5 Mar 2021 18:13:12 +0100 Subject: media: v4l: async: Rename async nf functions, clean up long lines Rename V4L2 async notifier functions, replacing "notifier" with "nf" and removing "_subdev" at the end of the function names adding subdevs as you can only add subdevs to a notifier. Also wrap and otherwise clean up long lines. Signed-off-by: Sakari Ailus Reviewed-by: Jacopo Mondi Reviewed-by: Rui Miguel Silva (imx7) Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/v4l2-subdev.rst | 14 +- drivers/media/i2c/max9286.c | 17 +-- drivers/media/i2c/st-mipid02.c | 22 ++- drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 17 ++- drivers/media/platform/am437x/am437x-vpfe.c | 19 +-- drivers/media/platform/atmel/atmel-isc-base.c | 4 +- drivers/media/platform/atmel/atmel-isi.c | 17 +-- drivers/media/platform/atmel/atmel-sama5d2-isc.c | 15 +- drivers/media/platform/atmel/atmel-sama7g5-isc.c | 15 +- drivers/media/platform/cadence/cdns-csi2rx.c | 14 +- drivers/media/platform/davinci/vpif_capture.c | 21 +-- drivers/media/platform/exynos4-is/media-dev.c | 20 +-- drivers/media/platform/marvell-ccic/cafe-driver.c | 9 +- drivers/media/platform/marvell-ccic/mcam-core.c | 10 +- drivers/media/platform/marvell-ccic/mmp-driver.c | 6 +- drivers/media/platform/omap3isp/isp.c | 21 +-- drivers/media/platform/pxa_camera.c | 26 ++-- drivers/media/platform/qcom/camss/camss.c | 18 +-- drivers/media/platform/rcar-vin/rcar-core.c | 30 ++-- drivers/media/platform/rcar-vin/rcar-csi2.c | 19 ++- drivers/media/platform/rcar_drif.c | 14 +- drivers/media/platform/renesas-ceu.c | 29 ++-- .../media/platform/rockchip/rkisp1/rkisp1-dev.c | 17 ++- drivers/media/platform/stm32/stm32-dcmi.c | 18 +-- drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c | 12 +- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 19 +-- drivers/media/platform/ti-vpe/cal.c | 16 +- drivers/media/platform/video-mux.c | 17 +-- drivers/media/platform/xilinx/xilinx-vipp.c | 17 +-- drivers/media/v4l2-core/v4l2-async.c | 168 ++++++++++----------- drivers/media/v4l2-core/v4l2-fwnode.c | 74 +++++---- drivers/staging/media/imx/imx-media-csi.c | 17 +-- drivers/staging/media/imx/imx-media-dev-common.c | 7 +- drivers/staging/media/imx/imx-media-dev.c | 6 +- drivers/staging/media/imx/imx-media-of.c | 6 +- drivers/staging/media/imx/imx6-mipi-csi2.c | 17 +-- drivers/staging/media/imx/imx7-media-csi.c | 24 +-- drivers/staging/media/imx/imx7-mipi-csis.c | 16 +- drivers/staging/media/imx/imx8mq-mipi-csi2.c | 16 +- drivers/staging/media/tegra-video/vi.c | 17 +-- include/media/v4l2-async.h | 105 +++++++------ include/media/v4l2-fwnode.h | 12 +- 42 files changed, 479 insertions(+), 499 deletions(-) diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst index 7736da077fb8..08ea2673b19e 100644 --- a/Documentation/driver-api/media/v4l2-subdev.rst +++ b/Documentation/driver-api/media/v4l2-subdev.rst @@ -191,21 +191,21 @@ registered this way are stored in a global list of subdevices, ready to be picked up by bridge drivers. Bridge drivers in turn have to register a notifier object. This is -performed using the :c:func:`v4l2_async_notifier_register` call. To +performed using the :c:func:`v4l2_async_nf_register` call. To unregister the notifier the driver has to call -:c:func:`v4l2_async_notifier_unregister`. The former of the two functions +:c:func:`v4l2_async_nf_unregister`. The former of the two functions takes two arguments: a pointer to struct :c:type:`v4l2_device` and a pointer to struct :c:type:`v4l2_async_notifier`. Before registering the notifier, bridge drivers must do two things: first, the -notifier must be initialized using the :c:func:`v4l2_async_notifier_init`. +notifier must be initialized using the :c:func:`v4l2_async_nf_init`. Second, bridge drivers can then begin to form a list of subdevice descriptors that the bridge device needs for its operation. Several functions are available to add subdevice descriptors to a notifier, depending on the type of device and the needs of the driver. -:c:func:`v4l2_async_notifier_add_fwnode_remote_subdev` and -:c:func:`v4l2_async_notifier_add_i2c_subdev` are for bridge and ISP drivers for +:c:func:`v4l2_async_nf_add_fwnode_remote` and +:c:func:`v4l2_async_nf_add_i2c` are for bridge and ISP drivers for registering their async sub-devices with the notifier. :c:func:`v4l2_async_register_subdev_sensor` is a helper function for @@ -230,8 +230,8 @@ These functions allocate an async sub-device descriptor which is of type struct ... - my_asd = v4l2_async_notifier_add_fwnode_remote_subdev(¬ifier, ep, - struct my_async_subdev); + my_asd = v4l2_async_nf_add_fwnode_remote(¬ifier, ep, + struct my_async_subdev); fwnode_handle_put(ep); if (IS_ERR(asd)) diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index 1aa2c58fd38c..7c663fd587bb 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -606,19 +606,18 @@ static int max9286_v4l2_notifier_register(struct max9286_priv *priv) if (!priv->nsources) return 0; - v4l2_async_notifier_init(&priv->notifier); + v4l2_async_nf_init(&priv->notifier); for_each_source(priv, source) { unsigned int i = to_index(priv, source); struct max9286_asd *mas; - mas = v4l2_async_notifier_add_fwnode_subdev(&priv->notifier, - source->fwnode, - struct max9286_asd); + mas = v4l2_async_nf_add_fwnode(&priv->notifier, source->fwnode, + struct max9286_asd); if (IS_ERR(mas)) { dev_err(dev, "Failed to add subdev for source %u: %ld", i, PTR_ERR(mas)); - v4l2_async_notifier_cleanup(&priv->notifier); + v4l2_async_nf_cleanup(&priv->notifier); return PTR_ERR(mas); } @@ -627,10 +626,10 @@ static int max9286_v4l2_notifier_register(struct max9286_priv *priv) priv->notifier.ops = &max9286_notify_ops; - ret = v4l2_async_subdev_notifier_register(&priv->sd, &priv->notifier); + ret = v4l2_async_subdev_nf_register(&priv->sd, &priv->notifier); if (ret) { dev_err(dev, "Failed to register subdev_notifier"); - v4l2_async_notifier_cleanup(&priv->notifier); + v4l2_async_nf_cleanup(&priv->notifier); return ret; } @@ -642,8 +641,8 @@ static void max9286_v4l2_notifier_unregister(struct max9286_priv *priv) if (!priv->nsources) return; - v4l2_async_notifier_unregister(&priv->notifier); - v4l2_async_notifier_cleanup(&priv->notifier); + v4l2_async_nf_unregister(&priv->notifier); + v4l2_async_nf_cleanup(&priv->notifier); } static int max9286_s_stream(struct v4l2_subdev *sd, int enable) diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index f630b88cbfaa..ef976d085d72 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -876,11 +876,10 @@ static int mipid02_parse_rx_ep(struct mipid02_dev *bridge) bridge->rx = ep; /* register async notifier so we get noticed when sensor is connected */ - v4l2_async_notifier_init(&bridge->notifier); - asd = v4l2_async_notifier_add_fwnode_remote_subdev( - &bridge->notifier, - of_fwnode_handle(ep_node), - struct v4l2_async_subdev); + v4l2_async_nf_init(&bridge->notifier); + asd = v4l2_async_nf_add_fwnode_remote(&bridge->notifier, + of_fwnode_handle(ep_node), + struct v4l2_async_subdev); of_node_put(ep_node); if (IS_ERR(asd)) { @@ -890,10 +889,9 @@ static int mipid02_parse_rx_ep(struct mipid02_dev *bridge) } bridge->notifier.ops = &mipid02_notifier_ops; - ret = v4l2_async_subdev_notifier_register(&bridge->sd, - &bridge->notifier); + ret = v4l2_async_subdev_nf_register(&bridge->sd, &bridge->notifier); if (ret) - v4l2_async_notifier_cleanup(&bridge->notifier); + v4l2_async_nf_cleanup(&bridge->notifier); return ret; @@ -1031,8 +1029,8 @@ static int mipid02_probe(struct i2c_client *client) return 0; unregister_notifier: - v4l2_async_notifier_unregister(&bridge->notifier); - v4l2_async_notifier_cleanup(&bridge->notifier); + v4l2_async_nf_unregister(&bridge->notifier); + v4l2_async_nf_cleanup(&bridge->notifier); power_off: mipid02_set_power_off(bridge); entity_cleanup: @@ -1048,8 +1046,8 @@ static int mipid02_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct mipid02_dev *bridge = to_mipid02_dev(sd); - v4l2_async_notifier_unregister(&bridge->notifier); - v4l2_async_notifier_cleanup(&bridge->notifier); + v4l2_async_nf_unregister(&bridge->notifier); + v4l2_async_nf_cleanup(&bridge->notifier); v4l2_async_unregister_subdev(&bridge->sd); mipid02_set_power_off(bridge); media_entity_cleanup(&bridge->sd.entity); diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index 47db0ee0fcbf..e84b8faf76a2 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -1478,8 +1478,9 @@ static int cio2_parse_firmware(struct cio2_device *cio2) if (ret) goto err_parse; - s_asd = v4l2_async_notifier_add_fwnode_remote_subdev( - &cio2->notifier, ep, struct sensor_async_subdev); + s_asd = v4l2_async_nf_add_fwnode_remote(&cio2->notifier, ep, + struct + sensor_async_subdev); if (IS_ERR(s_asd)) { ret = PTR_ERR(s_asd); goto err_parse; @@ -1502,7 +1503,7 @@ err_parse: * suspend. */ cio2->notifier.ops = &cio2_async_ops; - ret = v4l2_async_notifier_register(&cio2->v4l2_dev, &cio2->notifier); + ret = v4l2_async_nf_register(&cio2->v4l2_dev, &cio2->notifier); if (ret) dev_err(&cio2->pci_dev->dev, "failed to register async notifier : %d\n", ret); @@ -1804,7 +1805,7 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, if (r) goto fail_v4l2_device_unregister; - v4l2_async_notifier_init(&cio2->notifier); + v4l2_async_nf_init(&cio2->notifier); /* Register notifier for subdevices we care */ r = cio2_parse_firmware(cio2); @@ -1824,8 +1825,8 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, return 0; fail_clean_notifier: - v4l2_async_notifier_unregister(&cio2->notifier); - v4l2_async_notifier_cleanup(&cio2->notifier); + v4l2_async_nf_unregister(&cio2->notifier); + v4l2_async_nf_cleanup(&cio2->notifier); cio2_queues_exit(cio2); fail_v4l2_device_unregister: v4l2_device_unregister(&cio2->v4l2_dev); @@ -1844,8 +1845,8 @@ static void cio2_pci_remove(struct pci_dev *pci_dev) struct cio2_device *cio2 = pci_get_drvdata(pci_dev); media_device_unregister(&cio2->media_dev); - v4l2_async_notifier_unregister(&cio2->notifier); - v4l2_async_notifier_cleanup(&cio2->notifier); + v4l2_async_nf_unregister(&cio2->notifier); + v4l2_async_nf_cleanup(&cio2->notifier); cio2_queues_exit(cio2); cio2_fbpt_exit_dummy(cio2); v4l2_device_unregister(&cio2->v4l2_dev); diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 1c9cb9e05fdf..48bb0c93729c 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -2297,7 +2297,7 @@ vpfe_get_pdata(struct vpfe_device *vpfe) dev_dbg(dev, "vpfe_get_pdata\n"); - v4l2_async_notifier_init(&vpfe->notifier); + v4l2_async_nf_init(&vpfe->notifier); if (!IS_ENABLED(CONFIG_OF) || !dev->of_node) return dev->platform_data; @@ -2365,9 +2365,10 @@ vpfe_get_pdata(struct vpfe_device *vpfe) goto cleanup; } - pdata->asd[i] = v4l2_async_notifier_add_fwnode_subdev( - &vpfe->notifier, of_fwnode_handle(rem), - struct v4l2_async_subdev); + pdata->asd[i] = v4l2_async_nf_add_fwnode(&vpfe->notifier, + of_fwnode_handle(rem), + struct + v4l2_async_subdev); of_node_put(rem); if (IS_ERR(pdata->asd[i])) goto cleanup; @@ -2377,7 +2378,7 @@ vpfe_get_pdata(struct vpfe_device *vpfe) return pdata; cleanup: - v4l2_async_notifier_cleanup(&vpfe->notifier); + v4l2_async_nf_cleanup(&vpfe->notifier); of_node_put(endpoint); return NULL; } @@ -2465,7 +2466,7 @@ static int vpfe_probe(struct platform_device *pdev) } vpfe->notifier.ops = &vpfe_async_ops; - ret = v4l2_async_notifier_register(&vpfe->v4l2_dev, &vpfe->notifier); + ret = v4l2_async_nf_register(&vpfe->v4l2_dev, &vpfe->notifier); if (ret) { vpfe_err(vpfe, "Error registering async notifier\n"); ret = -EINVAL; @@ -2477,7 +2478,7 @@ static int vpfe_probe(struct platform_device *pdev) probe_out_v4l2_unregister: v4l2_device_unregister(&vpfe->v4l2_dev); probe_out_cleanup: - v4l2_async_notifier_cleanup(&vpfe->notifier); + v4l2_async_nf_cleanup(&vpfe->notifier); return ret; } @@ -2490,8 +2491,8 @@ static int vpfe_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); - v4l2_async_notifier_unregister(&vpfe->notifier); - v4l2_async_notifier_cleanup(&vpfe->notifier); + v4l2_async_nf_unregister(&vpfe->notifier); + v4l2_async_nf_cleanup(&vpfe->notifier); v4l2_device_unregister(&vpfe->v4l2_dev); video_unregister_device(&vpfe->video_dev); diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c index 136ab7cf36ed..3e0a3837d608 100644 --- a/drivers/media/platform/atmel/atmel-isc-base.c +++ b/drivers/media/platform/atmel/atmel-isc-base.c @@ -2222,8 +2222,8 @@ void isc_subdev_cleanup(struct isc_device *isc) struct isc_subdev_entity *subdev_entity; list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { - v4l2_async_notifier_unregister(&subdev_entity->notifier); - v4l2_async_notifier_cleanup(&subdev_entity->notifier); + v4l2_async_nf_unregister(&subdev_entity->notifier); + v4l2_async_nf_cleanup(&subdev_entity->notifier); } INIT_LIST_HEAD(&isc->subdev_entities); diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 095d80c4f59e..4d15814e4481 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -1159,12 +1159,11 @@ static int isi_graph_init(struct atmel_isi *isi) if (!ep) return -EINVAL; - v4l2_async_notifier_init(&isi->notifier); + v4l2_async_nf_init(&isi->notifier); - asd = v4l2_async_notifier_add_fwnode_remote_subdev( - &isi->notifier, - of_fwnode_handle(ep), - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&isi->notifier, + of_fwnode_handle(ep), + struct v4l2_async_subdev); of_node_put(ep); if (IS_ERR(asd)) @@ -1172,10 +1171,10 @@ static int isi_graph_init(struct atmel_isi *isi) isi->notifier.ops = &isi_graph_notify_ops; - ret = v4l2_async_notifier_register(&isi->v4l2_dev, &isi->notifier); + ret = v4l2_async_nf_register(&isi->v4l2_dev, &isi->notifier); if (ret < 0) { dev_err(isi->dev, "Notifier registration failed\n"); - v4l2_async_notifier_cleanup(&isi->notifier); + v4l2_async_nf_cleanup(&isi->notifier); return ret; } @@ -1327,8 +1326,8 @@ static int atmel_isi_remove(struct platform_device *pdev) isi->p_fb_descriptors, isi->fb_descriptors_phys); pm_runtime_disable(&pdev->dev); - v4l2_async_notifier_unregister(&isi->notifier); - v4l2_async_notifier_cleanup(&isi->notifier); + v4l2_async_nf_unregister(&isi->notifier); + v4l2_async_nf_cleanup(&isi->notifier); v4l2_device_unregister(&isi->v4l2_dev); return 0; diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c index b66f1d174e9d..0fa6013560df 100644 --- a/drivers/media/platform/atmel/atmel-sama5d2-isc.c +++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c @@ -512,13 +512,14 @@ static int atmel_isc_probe(struct platform_device *pdev) list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { struct v4l2_async_subdev *asd; + struct fwnode_handle *fwnode = + of_fwnode_handle(subdev_entity->epn); - v4l2_async_notifier_init(&subdev_entity->notifier); + v4l2_async_nf_init(&subdev_entity->notifier); - asd = v4l2_async_notifier_add_fwnode_remote_subdev( - &subdev_entity->notifier, - of_fwnode_handle(subdev_entity->epn), - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier, + fwnode, + struct v4l2_async_subdev); of_node_put(subdev_entity->epn); subdev_entity->epn = NULL; @@ -530,8 +531,8 @@ static int atmel_isc_probe(struct platform_device *pdev) subdev_entity->notifier.ops = &isc_async_ops; - ret = v4l2_async_notifier_register(&isc->v4l2_dev, - &subdev_entity->notifier); + ret = v4l2_async_nf_register(&isc->v4l2_dev, + &subdev_entity->notifier); if (ret) { dev_err(dev, "fail to register async notifier\n"); goto cleanup_subdev; diff --git a/drivers/media/platform/atmel/atmel-sama7g5-isc.c b/drivers/media/platform/atmel/atmel-sama7g5-isc.c index f2785131ff56..ee68cf1f4243 100644 --- a/drivers/media/platform/atmel/atmel-sama7g5-isc.c +++ b/drivers/media/platform/atmel/atmel-sama7g5-isc.c @@ -505,13 +505,14 @@ static int microchip_xisc_probe(struct platform_device *pdev) list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { struct v4l2_async_subdev *asd; + struct fwnode_handle *fwnode = + of_fwnode_handle(subdev_entity->epn); - v4l2_async_notifier_init(&subdev_entity->notifier); + v4l2_async_nf_init(&subdev_entity->notifier); - asd = v4l2_async_notifier_add_fwnode_remote_subdev( - &subdev_entity->notifier, - of_fwnode_handle(subdev_entity->epn), - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier, + fwnode, + struct v4l2_async_subdev); of_node_put(subdev_entity->epn); subdev_entity->epn = NULL; @@ -523,8 +524,8 @@ static int microchip_xisc_probe(struct platform_device *pdev) subdev_entity->notifier.ops = &isc_async_ops; - ret = v4l2_async_notifier_register(&isc->v4l2_dev, - &subdev_entity->notifier); + ret = v4l2_async_nf_register(&isc->v4l2_dev, + &subdev_entity->notifier); if (ret) { dev_err(dev, "fail to register async notifier\n"); goto cleanup_subdev; diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index f2b4ddd31177..7b44ab2b8c9a 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -401,21 +401,19 @@ static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx) return -EINVAL; } - v4l2_async_notifier_init(&csi2rx->notifier); + v4l2_async_nf_init(&csi2rx->notifier); - asd = v4l2_async_notifier_add_fwnode_remote_subdev(&csi2rx->notifier, - fwh, - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&csi2rx->notifier, fwh, + struct v4l2_async_subdev); of_node_put(ep); if (IS_ERR(asd)) return PTR_ERR(asd); csi2rx->notifier.ops = &csi2rx_notifier_ops; - ret = v4l2_async_subdev_notifier_register(&csi2rx->subdev, - &csi2rx->notifier); + ret = v4l2_async_subdev_nf_register(&csi2rx->subdev, &csi2rx->notifier); if (ret) - v4l2_async_notifier_cleanup(&csi2rx->notifier); + v4l2_async_nf_cleanup(&csi2rx->notifier); return ret; } @@ -471,7 +469,7 @@ static int csi2rx_probe(struct platform_device *pdev) return 0; err_cleanup: - v4l2_async_notifier_cleanup(&csi2rx->notifier); + v4l2_async_nf_cleanup(&csi2rx->notifier); err_free_priv: kfree(csi2rx); return ret; diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index c034e25dd9aa..ae92e2c206d0 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1506,7 +1506,7 @@ vpif_capture_get_pdata(struct platform_device *pdev) struct vpif_capture_chan_config *chan; unsigned int i; - v4l2_async_notifier_init(&vpif_obj.notifier); + v4l2_async_nf_init(&vpif_obj.notifier); /* * DT boot: OF node from parent device contains @@ -1582,9 +1582,10 @@ vpif_capture_get_pdata(struct platform_device *pdev) dev_dbg(&pdev->dev, "Remote device %pOF found\n", rem); sdinfo->name = rem->full_name; - pdata->asd[i] = v4l2_async_notifier_add_fwnode_subdev( - &vpif_obj.notifier, of_fwnode_handle(rem), - struct v4l2_async_subdev); + pdata->asd[i] = v4l2_async_nf_add_fwnode(&vpif_obj.notifier, + of_fwnode_handle(rem), + struct + v4l2_async_subdev); if (IS_ERR(pdata->asd[i])) goto err_cleanup; @@ -1602,7 +1603,7 @@ done: err_cleanup: of_node_put(rem); of_node_put(endpoint); - v4l2_async_notifier_cleanup(&vpif_obj.notifier); + v4l2_async_nf_cleanup(&vpif_obj.notifier); return NULL; } @@ -1692,8 +1693,8 @@ static __init int vpif_probe(struct platform_device *pdev) goto probe_subdev_out; } else { vpif_obj.notifier.ops = &vpif_async_ops; - err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev, - &vpif_obj.notifier); + err = v4l2_async_nf_register(&vpif_obj.v4l2_dev, + &vpif_obj.notifier); if (err) { vpif_err("Error registering async notifier\n"); err = -EINVAL; @@ -1711,7 +1712,7 @@ vpif_unregister: vpif_free: free_vpif_objs(); cleanup: - v4l2_async_notifier_cleanup(&vpif_obj.notifier); + v4l2_async_nf_cleanup(&vpif_obj.notifier); return err; } @@ -1727,8 +1728,8 @@ static int vpif_remove(struct platform_device *device) struct channel_obj *ch; int i; - v4l2_async_notifier_unregister(&vpif_obj.notifier); - v4l2_async_notifier_cleanup(&vpif_obj.notifier); + v4l2_async_nf_unregister(&vpif_obj.notifier); + v4l2_async_nf_cleanup(&vpif_obj.notifier); v4l2_device_unregister(&vpif_obj.v4l2_dev); kfree(vpif_obj.sd); diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index fa648721eaab..544b54e428c9 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -464,9 +464,9 @@ static int fimc_md_parse_one_endpoint(struct fimc_md *fmd, return -EINVAL; } - asd = v4l2_async_notifier_add_fwnode_remote_subdev( - &fmd->subdev_notifier, of_fwnode_handle(ep), - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&fmd->subdev_notifier, + of_fwnode_handle(ep), + struct v4l2_async_subdev); of_node_put(ep); @@ -557,7 +557,7 @@ rpm_put: cleanup: of_node_put(ports); - v4l2_async_notifier_cleanup(&fmd->subdev_notifier); + v4l2_async_nf_cleanup(&fmd->subdev_notifier); pm_runtime_put(fmd->pmf); return ret; } @@ -1481,7 +1481,7 @@ static int fimc_md_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fmd); - v4l2_async_notifier_init(&fmd->subdev_notifier); + v4l2_async_nf_init(&fmd->subdev_notifier); ret = fimc_md_register_platform_entities(fmd, dev->of_node); if (ret) @@ -1509,8 +1509,8 @@ static int fimc_md_probe(struct platform_device *pdev) fmd->subdev_notifier.ops = &subdev_notifier_ops; fmd->num_sensors = 0; - ret = v4l2_async_notifier_register(&fmd->v4l2_dev, - &fmd->subdev_notifier); + ret = v4l2_async_nf_register(&fmd->v4l2_dev, + &fmd->subdev_notifier); if (ret) goto err_clk_p; } @@ -1522,7 +1522,7 @@ err_clk_p: err_attr: device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode); err_cleanup: - v4l2_async_notifier_cleanup(&fmd->subdev_notifier); + v4l2_async_nf_cleanup(&fmd->subdev_notifier); err_m_ent: fimc_md_unregister_entities(fmd); err_clk: @@ -1542,8 +1542,8 @@ static int fimc_md_remove(struct platform_device *pdev) return 0; fimc_md_unregister_clk_provider(fmd); - v4l2_async_notifier_unregister(&fmd->subdev_notifier); - v4l2_async_notifier_cleanup(&fmd->subdev_notifier); + v4l2_async_nf_unregister(&fmd->subdev_notifier); + v4l2_async_nf_cleanup(&fmd->subdev_notifier); v4l2_device_unregister(&fmd->v4l2_dev); device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode); diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c index 9aa374fa8b36..b61b9d9551af 100644 --- a/drivers/media/platform/marvell-ccic/cafe-driver.c +++ b/drivers/media/platform/marvell-ccic/cafe-driver.c @@ -544,12 +544,11 @@ static int cafe_pci_probe(struct pci_dev *pdev, if (ret) goto out_pdown; - v4l2_async_notifier_init(&mcam->notifier); + v4l2_async_nf_init(&mcam->notifier); - asd = v4l2_async_notifier_add_i2c_subdev(&mcam->notifier, - i2c_adapter_id(cam->i2c_adapter), - ov7670_info.addr, - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_i2c(&mcam->notifier, + i2c_adapter_id(cam->i2c_adapter), + ov7670_info.addr, struct v4l2_async_subdev); if (IS_ERR(asd)) { ret = PTR_ERR(asd); goto out_smbus_shutdown; diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 58f9463f3b8c..ad4a7922d0d7 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1877,7 +1877,7 @@ int mccic_register(struct mcam_camera *cam) cam->mbus_code = mcam_def_mbus_code; cam->notifier.ops = &mccic_notify_ops; - ret = v4l2_async_notifier_register(&cam->v4l2_dev, &cam->notifier); + ret = v4l2_async_nf_register(&cam->v4l2_dev, &cam->notifier); if (ret < 0) { cam_warn(cam, "failed to register a sensor notifier"); goto out; @@ -1914,9 +1914,9 @@ int mccic_register(struct mcam_camera *cam) return 0; out: - v4l2_async_notifier_unregister(&cam->notifier); + v4l2_async_nf_unregister(&cam->notifier); v4l2_device_unregister(&cam->v4l2_dev); - v4l2_async_notifier_cleanup(&cam->notifier); + v4l2_async_nf_cleanup(&cam->notifier); return ret; } EXPORT_SYMBOL_GPL(mccic_register); @@ -1936,9 +1936,9 @@ void mccic_shutdown(struct mcam_camera *cam) if (cam->buffer_mode == B_vmalloc) mcam_free_dma_bufs(cam); v4l2_ctrl_handler_free(&cam->ctrl_handler); - v4l2_async_notifier_unregister(&cam->notifier); + v4l2_async_nf_unregister(&cam->notifier); v4l2_device_unregister(&cam->v4l2_dev); - v4l2_async_notifier_cleanup(&cam->notifier); + v4l2_async_nf_cleanup(&cam->notifier); } EXPORT_SYMBOL_GPL(mccic_shutdown); diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index f2f09cea751d..343ab4f7d807 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -239,10 +239,10 @@ static int mmpcam_probe(struct platform_device *pdev) if (!ep) return -ENODEV; - v4l2_async_notifier_init(&mcam->notifier); + v4l2_async_nf_init(&mcam->notifier); - asd = v4l2_async_notifier_add_fwnode_remote_subdev(&mcam->notifier, ep, - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&mcam->notifier, ep, + struct v4l2_async_subdev); fwnode_handle_put(ep); if (IS_ERR(asd)) { ret = PTR_ERR(asd); diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 20f59c59ff8a..6de377ce281d 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2003,7 +2003,7 @@ static int isp_remove(struct platform_device *pdev) { struct isp_device *isp = platform_get_drvdata(pdev); - v4l2_async_notifier_unregister(&isp->notifier); + v4l2_async_nf_unregister(&isp->notifier); isp_unregister_entities(isp); isp_cleanup_modules(isp); isp_xclk_cleanup(isp); @@ -2013,7 +2013,7 @@ static int isp_remove(struct platform_device *pdev) __omap3isp_put(isp, false); media_entity_enum_cleanup(&isp->crashed); - v4l2_async_notifier_cleanup(&isp->notifier); + v4l2_async_nf_cleanup(&isp->notifier); kfree(isp); @@ -2172,8 +2172,9 @@ static int isp_parse_of_endpoints(struct isp_device *isp) ret = v4l2_fwnode_endpoint_parse(ep, &vep); if (!ret) { - isd = v4l2_async_notifier_add_fwnode_remote_subdev( - &isp->notifier, ep, struct isp_async_subdev); + isd = v4l2_async_nf_add_fwnode_remote(&isp->notifier, + ep, struct + isp_async_subdev); if (!IS_ERR(isd)) isp_parse_of_parallel_endpoint(isp->dev, &vep, &isd->bus); } @@ -2211,8 +2212,10 @@ static int isp_parse_of_endpoints(struct isp_device *isp) } if (!ret) { - isd = v4l2_async_notifier_add_fwnode_remote_subdev( - &isp->notifier, ep, struct isp_async_subdev); + isd = v4l2_async_nf_add_fwnode_remote(&isp->notifier, + ep, + struct + isp_async_subdev); if (!IS_ERR(isd)) { switch (vep.bus_type) { @@ -2289,7 +2292,7 @@ static int isp_probe(struct platform_device *pdev) mutex_init(&isp->isp_mutex); spin_lock_init(&isp->stat_lock); - v4l2_async_notifier_init(&isp->notifier); + v4l2_async_nf_init(&isp->notifier); isp->dev = &pdev->dev; ret = isp_parse_of_endpoints(isp); @@ -2418,7 +2421,7 @@ static int isp_probe(struct platform_device *pdev) isp->notifier.ops = &isp_subdev_notifier_ops; - ret = v4l2_async_notifier_register(&isp->v4l2_dev, &isp->notifier); + ret = v4l2_async_nf_register(&isp->v4l2_dev, &isp->notifier); if (ret) goto error_register_entities; @@ -2437,7 +2440,7 @@ error_isp: isp_xclk_cleanup(isp); __omap3isp_put(isp, false); error: - v4l2_async_notifier_cleanup(&isp->notifier); + v4l2_async_nf_cleanup(&isp->notifier); mutex_destroy(&isp->isp_mutex); error_release_isp: kfree(isp); diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index ec4c010644ca..3ba00b0f9320 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -2249,10 +2249,9 @@ static int pxa_camera_pdata_from_dt(struct device *dev, if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) pcdev->platform_flags |= PXA_CAMERA_PCLK_EN; - asd = v4l2_async_notifier_add_fwnode_remote_subdev( - &pcdev->notifier, - of_fwnode_handle(np), - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&pcdev->notifier, + of_fwnode_handle(np), + struct v4l2_async_subdev); if (IS_ERR(asd)) err = PTR_ERR(asd); out: @@ -2289,7 +2288,7 @@ static int pxa_camera_probe(struct platform_device *pdev) if (IS_ERR(pcdev->clk)) return PTR_ERR(pcdev->clk); - v4l2_async_notifier_init(&pcdev->notifier); + v4l2_async_nf_init(&pcdev->notifier); pcdev->res = res; pcdev->pdata = pdev->dev.platform_data; if (pcdev->pdata) { @@ -2297,11 +2296,10 @@ static int pxa_camera_probe(struct platform_device *pdev) pcdev->platform_flags = pcdev->pdata->flags; pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; - asd = v4l2_async_notifier_add_i2c_subdev( - &pcdev->notifier, - pcdev->pdata->sensor_i2c_adapter_id, - pcdev->pdata->sensor_i2c_address, - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_i2c(&pcdev->notifier, + pcdev->pdata->sensor_i2c_adapter_id, + pcdev->pdata->sensor_i2c_address, + struct v4l2_async_subdev); if (IS_ERR(asd)) err = PTR_ERR(asd); } else if (pdev->dev.of_node) { @@ -2402,13 +2400,13 @@ static int pxa_camera_probe(struct platform_device *pdev) goto exit_notifier_cleanup; pcdev->notifier.ops = &pxa_camera_sensor_ops; - err = v4l2_async_notifier_register(&pcdev->v4l2_dev, &pcdev->notifier); + err = v4l2_async_nf_register(&pcdev->v4l2_dev, &pcdev->notifier); if (err) goto exit_notifier_cleanup; return 0; exit_notifier_cleanup: - v4l2_async_notifier_cleanup(&pcdev->notifier); + v4l2_async_nf_cleanup(&pcdev->notifier); v4l2_device_unregister(&pcdev->v4l2_dev); exit_deactivate: pxa_camera_deactivate(pcdev); @@ -2432,8 +2430,8 @@ static int pxa_camera_remove(struct platform_device *pdev) dma_release_channel(pcdev->dma_chans[1]); dma_release_channel(pcdev->dma_chans[2]); - v4l2_async_notifier_unregister(&pcdev->notifier); - v4l2_async_notifier_cleanup(&pcdev->notifier); + v4l2_async_nf_unregister(&pcdev->notifier); + v4l2_async_nf_cleanup(&pcdev->notifier); v4l2_device_unregister(&pcdev->v4l2_dev); diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index ef100d5f7763..be091c50a3c0 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -886,9 +886,9 @@ static int camss_of_parse_ports(struct camss *camss) goto err_cleanup; } - csd = v4l2_async_notifier_add_fwnode_subdev( - &camss->notifier, of_fwnode_handle(remote), - struct camss_async_subdev); + csd = v4l2_async_nf_add_fwnode(&camss->notifier, + of_fwnode_handle(remote), + struct camss_async_subdev); of_node_put(remote); if (IS_ERR(csd)) { ret = PTR_ERR(csd); @@ -1361,7 +1361,7 @@ static int camss_probe(struct platform_device *pdev) goto err_free; } - v4l2_async_notifier_init(&camss->notifier); + v4l2_async_nf_init(&camss->notifier); num_subdevs = camss_of_parse_ports(camss); if (num_subdevs < 0) { @@ -1397,8 +1397,8 @@ static int camss_probe(struct platform_device *pdev) if (num_subdevs) { camss->notifier.ops = &camss_subdev_notifier_ops; - ret = v4l2_async_notifier_register(&camss->v4l2_dev, - &camss->notifier); + ret = v4l2_async_nf_register(&camss->v4l2_dev, + &camss->notifier); if (ret) { dev_err(dev, "Failed to register async subdev nodes: %d\n", @@ -1436,7 +1436,7 @@ err_register_subdevs: err_register_entities: v4l2_device_unregister(&camss->v4l2_dev); err_cleanup: - v4l2_async_notifier_cleanup(&camss->notifier); + v4l2_async_nf_cleanup(&camss->notifier); err_free: kfree(camss); @@ -1478,8 +1478,8 @@ static int camss_remove(struct platform_device *pdev) { struct camss *camss = platform_get_drvdata(pdev); - v4l2_async_notifier_unregister(&camss->notifier); - v4l2_async_notifier_cleanup(&camss->notifier); + v4l2_async_nf_unregister(&camss->notifier); + v4l2_async_nf_cleanup(&camss->notifier); camss_unregister_entities(camss); if (atomic_read(&camss->ref_count) == 0) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 690e3f7e5a1c..8cb27c143187 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -337,9 +337,8 @@ static int rvin_group_parse_of(struct rvin_dev *vin, unsigned int port, goto out; } - asd = v4l2_async_notifier_add_fwnode_subdev(&vin->group->notifier, - fwnode, - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode(&vin->group->notifier, fwnode, + struct v4l2_async_subdev); if (IS_ERR(asd)) { ret = PTR_ERR(asd); goto out; @@ -359,8 +358,8 @@ static void rvin_group_notifier_cleanup(struct rvin_dev *vin) { mutex_lock(&vin->group->lock); if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) { - v4l2_async_notifier_unregister(&vin->group->notifier); - v4l2_async_notifier_cleanup(&vin->group->notifier); + v4l2_async_nf_unregister(&vin->group->notifier); + v4l2_async_nf_cleanup(&vin->group->notifier); } mutex_unlock(&vin->group->lock); } @@ -389,7 +388,7 @@ static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port, mutex_unlock(&vin->group->lock); - v4l2_async_notifier_init(&vin->group->notifier); + v4l2_async_nf_init(&vin->group->notifier); /* * Some subdevices may overlap but the parser function can handle it and @@ -413,11 +412,10 @@ static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port, return 0; vin->group->notifier.ops = &rvin_group_notify_ops; - ret = v4l2_async_notifier_register(&vin->v4l2_dev, - &vin->group->notifier); + ret = v4l2_async_nf_register(&vin->v4l2_dev, &vin->group->notifier); if (ret < 0) { vin_err(vin, "Notifier registration failed\n"); - v4l2_async_notifier_cleanup(&vin->group->notifier); + v4l2_async_nf_cleanup(&vin->group->notifier); return ret; } @@ -701,8 +699,8 @@ static int rvin_parallel_parse_of(struct rvin_dev *vin) goto out; } - asd = v4l2_async_notifier_add_fwnode_subdev(&vin->notifier, fwnode, - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode(&vin->notifier, fwnode, + struct v4l2_async_subdev); if (IS_ERR(asd)) { ret = PTR_ERR(asd); goto out; @@ -719,15 +717,15 @@ out: static void rvin_parallel_cleanup(struct rvin_dev *vin) { - v4l2_async_notifier_unregister(&vin->notifier); - v4l2_async_notifier_cleanup(&vin->notifier); + v4l2_async_nf_unregister(&vin->notifier); + v4l2_async_nf_cleanup(&vin->notifier); } static int rvin_parallel_init(struct rvin_dev *vin) { int ret; - v4l2_async_notifier_init(&vin->notifier); + v4l2_async_nf_init(&vin->notifier); ret = rvin_parallel_parse_of(vin); if (ret) @@ -740,10 +738,10 @@ static int rvin_parallel_init(struct rvin_dev *vin) to_of_node(vin->parallel.asd->match.fwnode)); vin->notifier.ops = &rvin_parallel_notify_ops; - ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier); + ret = v4l2_async_nf_register(&vin->v4l2_dev, &vin->notifier); if (ret < 0) { vin_err(vin, "Notifier registration failed\n"); - v4l2_async_notifier_cleanup(&vin->notifier); + v4l2_async_nf_cleanup(&vin->notifier); return ret; } diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index f5ec7cc1c90c..711b52ba42b5 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -1026,19 +1026,18 @@ static int rcsi2_parse_dt(struct rcar_csi2 *priv) dev_dbg(priv->dev, "Found '%pOF'\n", to_of_node(fwnode)); - v4l2_async_notifier_init(&priv->notifier); + v4l2_async_nf_init(&priv->notifier); priv->notifier.ops = &rcar_csi2_notify_ops; - asd = v4l2_async_notifier_add_fwnode_subdev(&priv->notifier, fwnode, - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode(&priv->notifier, fwnode, + struct v4l2_async_subdev); fwnode_handle_put(fwnode); if (IS_ERR(asd)) return PTR_ERR(asd); - ret = v4l2_async_subdev_notifier_register(&priv->subdev, - &priv->notifier); + ret = v4l2_async_subdev_nf_register(&priv->subdev, &priv->notifier); if (ret) - v4l2_async_notifier_cleanup(&priv->notifier); + v4l2_async_nf_cleanup(&priv->notifier); return ret; } @@ -1464,8 +1463,8 @@ static int rcsi2_probe(struct platform_device *pdev) return 0; error: - v4l2_async_notifier_unregister(&priv->notifier); - v4l2_async_notifier_cleanup(&priv->notifier); + v4l2_async_nf_unregister(&priv->notifier); + v4l2_async_nf_cleanup(&priv->notifier); return ret; } @@ -1474,8 +1473,8 @@ static int rcsi2_remove(struct platform_device *pdev) { struct rcar_csi2 *priv = platform_get_drvdata(pdev); - v4l2_async_notifier_unregister(&priv->notifier); - v4l2_async_notifier_cleanup(&priv->notifier); + v4l2_async_nf_unregister(&priv->notifier); + v4l2_async_nf_cleanup(&priv->notifier); v4l2_async_unregister_subdev(&priv->subdev); pm_runtime_disable(&pdev->dev); diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index 1e3b68a8743a..a505d991548b 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -1212,7 +1212,7 @@ static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr) struct fwnode_handle *fwnode, *ep; struct v4l2_async_subdev *asd; - v4l2_async_notifier_init(notifier); + v4l2_async_nf_init(notifier); ep = fwnode_graph_get_next_endpoint(of_fwnode_handle(sdr->dev->of_node), NULL); @@ -1229,8 +1229,8 @@ static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr) return -EINVAL; } - asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode, - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode(notifier, fwnode, + struct v4l2_async_subdev); fwnode_handle_put(fwnode); if (IS_ERR(asd)) return PTR_ERR(asd); @@ -1346,7 +1346,7 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr) sdr->notifier.ops = &rcar_drif_notify_ops; /* Register notifier */ - ret = v4l2_async_notifier_register(&sdr->v4l2_dev, &sdr->notifier); + ret = v4l2_async_nf_register(&sdr->v4l2_dev, &sdr->notifier); if (ret < 0) { dev_err(sdr->dev, "failed: notifier register ret %d\n", ret); goto cleanup; @@ -1355,7 +1355,7 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr) return ret; cleanup: - v4l2_async_notifier_cleanup(&sdr->notifier); + v4l2_async_nf_cleanup(&sdr->notifier); error: v4l2_device_unregister(&sdr->v4l2_dev); @@ -1365,8 +1365,8 @@ error: /* V4L2 SDR device remove */ static void rcar_drif_sdr_remove(struct rcar_drif_sdr *sdr) { - v4l2_async_notifier_unregister(&sdr->notifier); - v4l2_async_notifier_cleanup(&sdr->notifier); + v4l2_async_nf_unregister(&sdr->notifier); + v4l2_async_nf_cleanup(&sdr->notifier); v4l2_device_unregister(&sdr->v4l2_dev); } diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c index f432032c7084..9376eb363748 100644 --- a/drivers/media/platform/renesas-ceu.c +++ b/drivers/media/platform/renesas-ceu.c @@ -1513,12 +1513,12 @@ static int ceu_parse_platform_data(struct ceu_device *ceudev, /* Setup the ceu subdevice and the async subdevice. */ async_sd = &pdata->subdevs[i]; - ceu_sd = v4l2_async_notifier_add_i2c_subdev(&ceudev->notifier, - async_sd->i2c_adapter_id, - async_sd->i2c_address, - struct ceu_subdev); + ceu_sd = v4l2_async_nf_add_i2c(&ceudev->notifier, + async_sd->i2c_adapter_id, + async_sd->i2c_address, + struct ceu_subdev); if (IS_ERR(ceu_sd)) { - v4l2_async_notifier_cleanup(&ceudev->notifier); + v4l2_async_nf_cleanup(&ceudev->notifier); return PTR_ERR(ceu_sd); } ceu_sd->mbus_flags = async_sd->flags; @@ -1576,9 +1576,9 @@ static int ceu_parse_dt(struct ceu_device *ceudev) } /* Setup the ceu subdevice and the async subdevice. */ - ceu_sd = v4l2_async_notifier_add_fwnode_remote_subdev( - &ceudev->notifier, of_fwnode_handle(ep), - struct ceu_subdev); + ceu_sd = v4l2_async_nf_add_fwnode_remote(&ceudev->notifier, + of_fwnode_handle(ep), + struct ceu_subdev); if (IS_ERR(ceu_sd)) { ret = PTR_ERR(ceu_sd); goto error_cleanup; @@ -1592,7 +1592,7 @@ static int ceu_parse_dt(struct ceu_device *ceudev) return num_ep; error_cleanup: - v4l2_async_notifier_cleanup(&ceudev->notifier); + v4l2_async_nf_cleanup(&ceudev->notifier); of_node_put(ep); return ret; } @@ -1669,7 +1669,7 @@ static int ceu_probe(struct platform_device *pdev) if (ret) goto error_pm_disable; - v4l2_async_notifier_init(&ceudev->notifier); + v4l2_async_nf_init(&ceudev->notifier); if (IS_ENABLED(CONFIG_OF) && dev->of_node) { ceu_data = of_device_get_match_data(dev); @@ -1691,8 +1691,7 @@ static int ceu_probe(struct platform_device *pdev) ceudev->notifier.v4l2_dev = &ceudev->v4l2_dev; ceudev->notifier.ops = &ceu_notify_ops; - ret = v4l2_async_notifier_register(&ceudev->v4l2_dev, - &ceudev->notifier); + ret = v4l2_async_nf_register(&ceudev->v4l2_dev, &ceudev->notifier); if (ret) goto error_cleanup; @@ -1701,7 +1700,7 @@ static int ceu_probe(struct platform_device *pdev) return 0; error_cleanup: - v4l2_async_notifier_cleanup(&ceudev->notifier); + v4l2_async_nf_cleanup(&ceudev->notifier); error_v4l2_unregister: v4l2_device_unregister(&ceudev->v4l2_dev); error_pm_disable: @@ -1718,9 +1717,9 @@ static int ceu_remove(struct platform_device *pdev) pm_runtime_disable(ceudev->dev); - v4l2_async_notifier_unregister(&ceudev->notifier); + v4l2_async_nf_unregister(&ceudev->notifier); - v4l2_async_notifier_cleanup(&ceudev->notifier); + v4l2_async_nf_cleanup(&ceudev->notifier); v4l2_device_unregister(&ceudev->v4l2_dev); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index 7474150b94ed..1f2a503ea130 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -246,7 +246,7 @@ static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1) unsigned int next_id = 0; int ret; - v4l2_async_notifier_init(ntf); + v4l2_async_nf_init(ntf); while (1) { struct v4l2_fwnode_endpoint vep = { @@ -265,8 +265,9 @@ static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1) if (ret) goto err_parse; - rk_asd = v4l2_async_notifier_add_fwnode_remote_subdev(ntf, ep, - struct rkisp1_sensor_async); + rk_asd = v4l2_async_nf_add_fwnode_remote(ntf, ep, + struct + rkisp1_sensor_async); if (IS_ERR(rk_asd)) { ret = PTR_ERR(rk_asd); goto err_parse; @@ -286,16 +287,16 @@ static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1) continue; err_parse: fwnode_handle_put(ep); - v4l2_async_notifier_cleanup(ntf); + v4l2_async_nf_cleanup(ntf); return ret; } if (next_id == 0) dev_dbg(rkisp1->dev, "no remote subdevice found\n"); ntf->ops = &rkisp1_subdev_notifier_ops; - ret = v4l2_async_notifier_register(&rkisp1->v4l2_dev, ntf); + ret = v4l2_async_nf_register(&rkisp1->v4l2_dev, ntf); if (ret) { - v4l2_async_notifier_cleanup(ntf); + v4l2_async_nf_cleanup(ntf); return ret; } return 0; @@ -542,8 +543,8 @@ static int rkisp1_remove(struct platform_device *pdev) { struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev); - v4l2_async_notifier_unregister(&rkisp1->notifier); - v4l2_async_notifier_cleanup(&rkisp1->notifier); + v4l2_async_nf_unregister(&rkisp1->notifier); + v4l2_async_nf_cleanup(&rkisp1->notifier); rkisp1_params_unregister(rkisp1); rkisp1_stats_unregister(rkisp1); diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index d914ccef9831..e499841d76f0 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -1824,11 +1824,11 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) return -EINVAL; } - v4l2_async_notifier_init(&dcmi->notifier); + v4l2_async_nf_init(&dcmi->notifier); - asd = v4l2_async_notifier_add_fwnode_remote_subdev( - &dcmi->notifier, of_fwnode_handle(ep), - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&dcmi->notifier, + of_fwnode_handle(ep), + struct v4l2_async_subdev); of_node_put(ep); @@ -1839,10 +1839,10 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) dcmi->notifier.ops = &dcmi_graph_notify_ops; - ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier); + ret = v4l2_async_nf_register(&dcmi->v4l2_dev, &dcmi->notifier); if (ret < 0) { dev_err(dcmi->dev, "Failed to register notifier\n"); - v4l2_async_notifier_cleanup(&dcmi->notifier); + v4l2_async_nf_cleanup(&dcmi->notifier); return ret; } @@ -2060,7 +2060,7 @@ static int dcmi_probe(struct platform_device *pdev) return 0; err_cleanup: - v4l2_async_notifier_cleanup(&dcmi->notifier); + v4l2_async_nf_cleanup(&dcmi->notifier); err_media_entity_cleanup: media_entity_cleanup(&dcmi->vdev->entity); err_device_release: @@ -2080,8 +2080,8 @@ static int dcmi_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); - v4l2_async_notifier_unregister(&dcmi->notifier); - v4l2_async_notifier_cleanup(&dcmi->notifier); + v4l2_async_nf_unregister(&dcmi->notifier); + v4l2_async_nf_cleanup(&dcmi->notifier); media_entity_cleanup(&dcmi->vdev->entity); v4l2_device_unregister(&dcmi->v4l2_dev); media_device_cleanup(&dcmi->mdev); diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c index 8d40a7acba9c..94e98e470aff 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c @@ -122,7 +122,7 @@ static int sun4i_csi_notifier_init(struct sun4i_csi *csi) struct fwnode_handle *ep; int ret; - v4l2_async_notifier_init(&csi->notifier); + v4l2_async_nf_init(&csi->notifier); ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0, FWNODE_GRAPH_ENDPOINT_NEXT); @@ -135,8 +135,8 @@ static int sun4i_csi_notifier_init(struct sun4i_csi *csi) csi->bus = vep.bus.parallel; - asd = v4l2_async_notifier_add_fwnode_remote_subdev(&csi->notifier, ep, - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, ep, + struct v4l2_async_subdev); if (IS_ERR(asd)) { ret = PTR_ERR(asd); goto out; @@ -244,7 +244,7 @@ static int sun4i_csi_probe(struct platform_device *pdev) if (ret) goto err_unregister_media; - ret = v4l2_async_notifier_register(&csi->v4l, &csi->notifier); + ret = v4l2_async_nf_register(&csi->v4l, &csi->notifier); if (ret) { dev_err(csi->dev, "Couldn't register our notifier.\n"); goto err_unregister_media; @@ -268,8 +268,8 @@ static int sun4i_csi_remove(struct platform_device *pdev) { struct sun4i_csi *csi = platform_get_drvdata(pdev); - v4l2_async_notifier_unregister(&csi->notifier); - v4l2_async_notifier_cleanup(&csi->notifier); + v4l2_async_nf_unregister(&csi->notifier); + v4l2_async_nf_cleanup(&csi->notifier); vb2_video_unregister_device(&csi->vdev); media_device_unregister(&csi->mdev); sun4i_csi_dma_unregister(csi); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 27935f1e9555..08df0c833423 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -717,8 +717,8 @@ static int sun6i_csi_fwnode_parse(struct device *dev, static void sun6i_csi_v4l2_cleanup(struct sun6i_csi *csi) { media_device_unregister(&csi->media_dev); - v4l2_async_notifier_unregister(&csi->notifier); - v4l2_async_notifier_cleanup(&csi->notifier); + v4l2_async_nf_unregister(&csi->notifier); + v4l2_async_nf_cleanup(&csi->notifier); sun6i_video_cleanup(&csi->video); v4l2_device_unregister(&csi->v4l2_dev); v4l2_ctrl_handler_free(&csi->ctrl_handler); @@ -737,7 +737,7 @@ static int sun6i_csi_v4l2_init(struct sun6i_csi *csi) "platform:%s", dev_name(csi->dev)); media_device_init(&csi->media_dev); - v4l2_async_notifier_init(&csi->notifier); + v4l2_async_nf_init(&csi->notifier); ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 0); if (ret) { @@ -759,16 +759,17 @@ static int sun6i_csi_v4l2_init(struct sun6i_csi *csi) if (ret) goto unreg_v4l2; - ret = v4l2_async_notifier_parse_fwnode_endpoints(csi->dev, - &csi->notifier, - sizeof(struct v4l2_async_subdev), - sun6i_csi_fwnode_parse); + ret = v4l2_async_nf_parse_fwnode_endpoints(csi->dev, + &csi->notifier, + sizeof(struct + v4l2_async_subdev), + sun6i_csi_fwnode_parse); if (ret) goto clean_video; csi->notifier.ops = &sun6i_csi_async_ops; - ret = v4l2_async_notifier_register(&csi->v4l2_dev, &csi->notifier); + ret = v4l2_async_nf_register(&csi->v4l2_dev, &csi->notifier); if (ret) { dev_err(csi->dev, "notifier registration failed\n"); goto clean_video; @@ -783,7 +784,7 @@ unreg_v4l2: free_ctrl: v4l2_ctrl_handler_free(&csi->ctrl_handler); clean_media: - v4l2_async_notifier_cleanup(&csi->notifier); + v4l2_async_nf_cleanup(&csi->notifier); media_device_cleanup(&csi->media_dev); return ret; diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 8e469d518a74..4a4a6c5983f7 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -781,7 +781,7 @@ static int cal_async_notifier_register(struct cal_dev *cal) unsigned int i; int ret; - v4l2_async_notifier_init(&cal->notifier); + v4l2_async_nf_init(&cal->notifier); cal->notifier.ops = &cal_async_notifier_ops; for (i = 0; i < cal->data->num_csi2_phy; ++i) { @@ -793,9 +793,9 @@ static int cal_async_notifier_register(struct cal_dev *cal) continue; fwnode = of_fwnode_handle(phy->source_node); - casd = v4l2_async_notifier_add_fwnode_subdev(&cal->notifier, - fwnode, - struct cal_v4l2_async_subdev); + casd = v4l2_async_nf_add_fwnode(&cal->notifier, + fwnode, + struct cal_v4l2_async_subdev); if (IS_ERR(casd)) { phy_err(phy, "Failed to add subdev to notifier\n"); ret = PTR_ERR(casd); @@ -805,7 +805,7 @@ static int cal_async_notifier_register(struct cal_dev *cal) casd->phy = phy; } - ret = v4l2_async_notifier_register(&cal->v4l2_dev, &cal->notifier); + ret = v4l2_async_nf_register(&cal->v4l2_dev, &cal->notifier); if (ret) { cal_err(cal, "Error registering async notifier\n"); goto error; @@ -814,14 +814,14 @@ static int cal_async_notifier_register(struct cal_dev *cal) return 0; error: - v4l2_async_notifier_cleanup(&cal->notifier); + v4l2_async_nf_cleanup(&cal->notifier); return ret; } static void cal_async_notifier_unregister(struct cal_dev *cal) { - v4l2_async_notifier_unregister(&cal->notifier); - v4l2_async_notifier_cleanup(&cal->notifier); + v4l2_async_nf_unregister(&cal->notifier); + v4l2_async_nf_cleanup(&cal->notifier); } /* ------------------------------------------------------------------ diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index 905005e271ca..fda8fc0e4814 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -360,7 +360,7 @@ static int video_mux_async_register(struct video_mux *vmux, unsigned int i; int ret; - v4l2_async_notifier_init(&vmux->notifier); + v4l2_async_nf_init(&vmux->notifier); for (i = 0; i < num_input_pads; i++) { struct v4l2_async_subdev *asd; @@ -380,8 +380,8 @@ static int video_mux_async_register(struct video_mux *vmux, } fwnode_handle_put(remote_ep); - asd = v4l2_async_notifier_add_fwnode_remote_subdev( - &vmux->notifier, ep, struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&vmux->notifier, ep, + struct v4l2_async_subdev); fwnode_handle_put(ep); @@ -395,8 +395,7 @@ static int video_mux_async_register(struct video_mux *vmux, vmux->notifier.ops = &video_mux_notify_ops; - ret = v4l2_async_subdev_notifier_register(&vmux->subdev, - &vmux->notifier); + ret = v4l2_async_subdev_nf_register(&vmux->subdev, &vmux->notifier); if (ret) return ret; @@ -477,8 +476,8 @@ static int video_mux_probe(struct platform_device *pdev) ret = video_mux_async_register(vmux, num_pads - 1); if (ret) { - v4l2_async_notifier_unregister(&vmux->notifier); - v4l2_async_notifier_cleanup(&vmux->notifier); + v4l2_async_nf_unregister(&vmux->notifier); + v4l2_async_nf_cleanup(&vmux->notifier); } return ret; @@ -489,8 +488,8 @@ static int video_mux_remove(struct platform_device *pdev) struct video_mux *vmux = platform_get_drvdata(pdev); struct v4l2_subdev *sd = &vmux->subdev; - v4l2_async_notifier_unregister(&vmux->notifier); - v4l2_async_notifier_cleanup(&vmux->notifier); + v4l2_async_nf_unregister(&vmux->notifier); + v4l2_async_nf_cleanup(&vmux->notifier); v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index 2ce31d7ce1a6..f34f8b077e03 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -382,9 +382,8 @@ static int xvip_graph_parse_one(struct xvip_composite_device *xdev, continue; } - xge = v4l2_async_notifier_add_fwnode_subdev( - &xdev->notifier, remote, - struct xvip_graph_entity); + xge = v4l2_async_nf_add_fwnode(&xdev->notifier, remote, + struct xvip_graph_entity); fwnode_handle_put(remote); if (IS_ERR(xge)) { ret = PTR_ERR(xge); @@ -395,7 +394,7 @@ static int xvip_graph_parse_one(struct xvip_composite_device *xdev, return 0; err_notifier_cleanup: - v4l2_async_notifier_cleanup(&xdev->notifier); + v4l2_async_nf_cleanup(&xdev->notifier); fwnode_handle_put(ep); return ret; } @@ -420,7 +419,7 @@ static int xvip_graph_parse(struct xvip_composite_device *xdev) entity = to_xvip_entity(asd); ret = xvip_graph_parse_one(xdev, entity->asd.match.fwnode); if (ret < 0) { - v4l2_async_notifier_cleanup(&xdev->notifier); + v4l2_async_nf_cleanup(&xdev->notifier); break; } } @@ -496,8 +495,8 @@ static void xvip_graph_cleanup(struct xvip_composite_device *xdev) struct xvip_dma *dmap; struct xvip_dma *dma; - v4l2_async_notifier_unregister(&xdev->notifier); - v4l2_async_notifier_cleanup(&xdev->notifier); + v4l2_async_nf_unregister(&xdev->notifier); + v4l2_async_nf_cleanup(&xdev->notifier); list_for_each_entry_safe(dma, dmap, &xdev->dmas, list) { xvip_dma_cleanup(dma); @@ -532,7 +531,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev) /* Register the subdevices notifier. */ xdev->notifier.ops = &xvip_graph_notify_ops; - ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier); + ret = v4l2_async_nf_register(&xdev->v4l2_dev, &xdev->notifier); if (ret < 0) { dev_err(xdev->dev, "notifier registration failed\n"); goto done; @@ -596,7 +595,7 @@ static int xvip_composite_probe(struct platform_device *pdev) xdev->dev = &pdev->dev; INIT_LIST_HEAD(&xdev->dmas); - v4l2_async_notifier_init(&xdev->notifier); + v4l2_async_nf_init(&xdev->notifier); ret = xvip_composite_v4l2_init(xdev); if (ret < 0) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index cd9e78c63791..0404267f1ae4 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -24,9 +24,9 @@ #include #include -static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd) +static int v4l2_async_nf_call_bound(struct v4l2_async_notifier *n, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) { if (!n->ops || !n->ops->bound) return 0; @@ -34,9 +34,9 @@ static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n, return n->ops->bound(n, subdev, asd); } -static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd) +static void v4l2_async_nf_call_unbind(struct v4l2_async_notifier *n, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) { if (!n->ops || !n->ops->unbind) return; @@ -44,7 +44,7 @@ static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n, n->ops->unbind(n, subdev, asd); } -static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n) +static int v4l2_async_nf_call_complete(struct v4l2_async_notifier *n) { if (!n->ops || !n->ops->complete) return 0; @@ -215,7 +215,7 @@ v4l2_async_find_subdev_notifier(struct v4l2_subdev *sd) /* Get v4l2_device related to the notifier if one can be found. */ static struct v4l2_device * -v4l2_async_notifier_find_v4l2_dev(struct v4l2_async_notifier *notifier) +v4l2_async_nf_find_v4l2_dev(struct v4l2_async_notifier *notifier) { while (notifier->parent) notifier = notifier->parent; @@ -227,7 +227,7 @@ v4l2_async_notifier_find_v4l2_dev(struct v4l2_async_notifier *notifier) * Return true if all child sub-device notifiers are complete, false otherwise. */ static bool -v4l2_async_notifier_can_complete(struct v4l2_async_notifier *notifier) +v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier) { struct v4l2_subdev *sd; @@ -239,7 +239,7 @@ v4l2_async_notifier_can_complete(struct v4l2_async_notifier *notifier) v4l2_async_find_subdev_notifier(sd); if (subdev_notifier && - !v4l2_async_notifier_can_complete(subdev_notifier)) + !v4l2_async_nf_can_complete(subdev_notifier)) return false; } @@ -251,7 +251,7 @@ v4l2_async_notifier_can_complete(struct v4l2_async_notifier *notifier) * sub-devices have been bound; v4l2_device is also available then. */ static int -v4l2_async_notifier_try_complete(struct v4l2_async_notifier *notifier) +v4l2_async_nf_try_complete(struct v4l2_async_notifier *notifier) { /* Quick check whether there are still more sub-devices here. */ if (!list_empty(¬ifier->waiting)) @@ -266,14 +266,14 @@ v4l2_async_notifier_try_complete(struct v4l2_async_notifier *notifier) return 0; /* Is everything ready? */ - if (!v4l2_async_notifier_can_complete(notifier)) + if (!v4l2_async_nf_can_complete(notifier)) return 0; - return v4l2_async_notifier_call_complete(notifier); + return v4l2_async_nf_call_complete(notifier); } static int -v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier); +v4l2_async_nf_try_all_subdevs(struct v4l2_async_notifier *notifier); static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, struct v4l2_device *v4l2_dev, @@ -287,7 +287,7 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, if (ret < 0) return ret; - ret = v4l2_async_notifier_call_bound(notifier, sd, asd); + ret = v4l2_async_nf_call_bound(notifier, sd, asd); if (ret < 0) { v4l2_device_unregister_subdev(sd); return ret; @@ -315,15 +315,15 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, */ subdev_notifier->parent = notifier; - return v4l2_async_notifier_try_all_subdevs(subdev_notifier); + return v4l2_async_nf_try_all_subdevs(subdev_notifier); } /* Test all async sub-devices in a notifier for a match. */ static int -v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier) +v4l2_async_nf_try_all_subdevs(struct v4l2_async_notifier *notifier) { struct v4l2_device *v4l2_dev = - v4l2_async_notifier_find_v4l2_dev(notifier); + v4l2_async_nf_find_v4l2_dev(notifier); struct v4l2_subdev *sd; if (!v4l2_dev) @@ -367,7 +367,7 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) /* Unbind all sub-devices in the notifier tree. */ static void -v4l2_async_notifier_unbind_all_subdevs(struct v4l2_async_notifier *notifier) +v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier) { struct v4l2_subdev *sd, *tmp; @@ -376,9 +376,9 @@ v4l2_async_notifier_unbind_all_subdevs(struct v4l2_async_notifier *notifier) v4l2_async_find_subdev_notifier(sd); if (subdev_notifier) - v4l2_async_notifier_unbind_all_subdevs(subdev_notifier); + v4l2_async_nf_unbind_all_subdevs(subdev_notifier); - v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); + v4l2_async_nf_call_unbind(notifier, sd, sd->asd); v4l2_async_cleanup(sd); list_move(&sd->async_list, &subdev_list); @@ -389,8 +389,8 @@ v4l2_async_notifier_unbind_all_subdevs(struct v4l2_async_notifier *notifier) /* See if an async sub-device can be found in a notifier's lists. */ static bool -__v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier, - struct v4l2_async_subdev *asd) +__v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier, + struct v4l2_async_subdev *asd) { struct v4l2_async_subdev *asd_y; struct v4l2_subdev *sd; @@ -416,9 +416,8 @@ __v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier, * If @this_index < 0, search the notifier's entire @asd_list. */ static bool -v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier, - struct v4l2_async_subdev *asd, - int this_index) +v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier, + struct v4l2_async_subdev *asd, int this_index) { struct v4l2_async_subdev *asd_y; int j = 0; @@ -435,15 +434,15 @@ v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier, /* Check that an asd does not exist in other notifiers. */ list_for_each_entry(notifier, ¬ifier_list, list) - if (__v4l2_async_notifier_has_async_subdev(notifier, asd)) + if (__v4l2_async_nf_has_async_subdev(notifier, asd)) return true; return false; } -static int v4l2_async_notifier_asd_valid(struct v4l2_async_notifier *notifier, - struct v4l2_async_subdev *asd, - int this_index) +static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier, + struct v4l2_async_subdev *asd, + int this_index) { struct device *dev = notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL; @@ -454,8 +453,7 @@ static int v4l2_async_notifier_asd_valid(struct v4l2_async_notifier *notifier, switch (asd->match_type) { case V4L2_ASYNC_MATCH_I2C: case V4L2_ASYNC_MATCH_FWNODE: - if (v4l2_async_notifier_has_async_subdev(notifier, asd, - this_index)) { + if (v4l2_async_nf_has_async_subdev(notifier, asd, this_index)) { dev_dbg(dev, "subdev descriptor already listed in this or other notifiers\n"); return -EEXIST; } @@ -469,13 +467,13 @@ static int v4l2_async_notifier_asd_valid(struct v4l2_async_notifier *notifier, return 0; } -void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier) +void v4l2_async_nf_init(struct v4l2_async_notifier *notifier) { INIT_LIST_HEAD(¬ifier->asd_list); } -EXPORT_SYMBOL(v4l2_async_notifier_init); +EXPORT_SYMBOL(v4l2_async_nf_init); -static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier) +static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier) { struct v4l2_async_subdev *asd; int ret, i = 0; @@ -486,18 +484,18 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier) mutex_lock(&list_lock); list_for_each_entry(asd, ¬ifier->asd_list, asd_list) { - ret = v4l2_async_notifier_asd_valid(notifier, asd, i++); + ret = v4l2_async_nf_asd_valid(notifier, asd, i++); if (ret) goto err_unlock; list_add_tail(&asd->list, ¬ifier->waiting); } - ret = v4l2_async_notifier_try_all_subdevs(notifier); + ret = v4l2_async_nf_try_all_subdevs(notifier); if (ret < 0) goto err_unbind; - ret = v4l2_async_notifier_try_complete(notifier); + ret = v4l2_async_nf_try_complete(notifier); if (ret < 0) goto err_unbind; @@ -512,7 +510,7 @@ err_unbind: /* * On failure, unbind all sub-devices registered through this notifier. */ - v4l2_async_notifier_unbind_all_subdevs(notifier); + v4l2_async_nf_unbind_all_subdevs(notifier); err_unlock: mutex_unlock(&list_lock); @@ -520,8 +518,8 @@ err_unlock: return ret; } -int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, - struct v4l2_async_notifier *notifier) +int v4l2_async_nf_register(struct v4l2_device *v4l2_dev, + struct v4l2_async_notifier *notifier) { int ret; @@ -530,16 +528,16 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, notifier->v4l2_dev = v4l2_dev; - ret = __v4l2_async_notifier_register(notifier); + ret = __v4l2_async_nf_register(notifier); if (ret) notifier->v4l2_dev = NULL; return ret; } -EXPORT_SYMBOL(v4l2_async_notifier_register); +EXPORT_SYMBOL(v4l2_async_nf_register); -int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd, - struct v4l2_async_notifier *notifier) +int v4l2_async_subdev_nf_register(struct v4l2_subdev *sd, + struct v4l2_async_notifier *notifier) { int ret; @@ -548,21 +546,21 @@ int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd, notifier->sd = sd; - ret = __v4l2_async_notifier_register(notifier); + ret = __v4l2_async_nf_register(notifier); if (ret) notifier->sd = NULL; return ret; } -EXPORT_SYMBOL(v4l2_async_subdev_notifier_register); +EXPORT_SYMBOL(v4l2_async_subdev_nf_register); static void -__v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) +__v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier) { if (!notifier || (!notifier->v4l2_dev && !notifier->sd)) return; - v4l2_async_notifier_unbind_all_subdevs(notifier); + v4l2_async_nf_unbind_all_subdevs(notifier); notifier->sd = NULL; notifier->v4l2_dev = NULL; @@ -570,17 +568,17 @@ __v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) list_del(¬ifier->list); } -void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) +void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier) { mutex_lock(&list_lock); - __v4l2_async_notifier_unregister(notifier); + __v4l2_async_nf_unregister(notifier); mutex_unlock(&list_lock); } -EXPORT_SYMBOL(v4l2_async_notifier_unregister); +EXPORT_SYMBOL(v4l2_async_nf_unregister); -static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier) +static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier) { struct v4l2_async_subdev *asd, *tmp; @@ -601,24 +599,24 @@ static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier) } } -void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier) +void v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier) { mutex_lock(&list_lock); - __v4l2_async_notifier_cleanup(notifier); + __v4l2_async_nf_cleanup(notifier); mutex_unlock(&list_lock); } -EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup); +EXPORT_SYMBOL_GPL(v4l2_async_nf_cleanup); -int __v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier, - struct v4l2_async_subdev *asd) +int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier, + struct v4l2_async_subdev *asd) { int ret; mutex_lock(&list_lock); - ret = v4l2_async_notifier_asd_valid(notifier, asd, -1); + ret = v4l2_async_nf_asd_valid(notifier, asd, -1); if (ret) goto unlock; @@ -628,12 +626,12 @@ unlock: mutex_unlock(&list_lock); return ret; } -EXPORT_SYMBOL_GPL(__v4l2_async_notifier_add_subdev); +EXPORT_SYMBOL_GPL(__v4l2_async_nf_add_subdev); struct v4l2_async_subdev * -__v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier, - struct fwnode_handle *fwnode, - unsigned int asd_struct_size) +__v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier, + struct fwnode_handle *fwnode, + unsigned int asd_struct_size) { struct v4l2_async_subdev *asd; int ret; @@ -645,7 +643,7 @@ __v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier, asd->match_type = V4L2_ASYNC_MATCH_FWNODE; asd->match.fwnode = fwnode_handle_get(fwnode); - ret = __v4l2_async_notifier_add_subdev(notifier, asd); + ret = __v4l2_async_nf_add_subdev(notifier, asd); if (ret) { fwnode_handle_put(fwnode); kfree(asd); @@ -654,12 +652,12 @@ __v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier, return asd; } -EXPORT_SYMBOL_GPL(__v4l2_async_notifier_add_fwnode_subdev); +EXPORT_SYMBOL_GPL(__v4l2_async_nf_add_fwnode); struct v4l2_async_subdev * -__v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif, - struct fwnode_handle *endpoint, - unsigned int asd_struct_size) +__v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif, + struct fwnode_handle *endpoint, + unsigned int asd_struct_size) { struct v4l2_async_subdev *asd; struct fwnode_handle *remote; @@ -668,21 +666,19 @@ __v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif if (!remote) return ERR_PTR(-ENOTCONN); - asd = __v4l2_async_notifier_add_fwnode_subdev(notif, remote, - asd_struct_size); + asd = __v4l2_async_nf_add_fwnode(notif, remote, asd_struct_size); /* - * Calling __v4l2_async_notifier_add_fwnode_subdev grabs a refcount, + * Calling __v4l2_async_nf_add_fwnode grabs a refcount, * so drop the one we got in fwnode_graph_get_remote_port_parent. */ fwnode_handle_put(remote); return asd; } -EXPORT_SYMBOL_GPL(__v4l2_async_notifier_add_fwnode_remote_subdev); +EXPORT_SYMBOL_GPL(__v4l2_async_nf_add_fwnode_remote); struct v4l2_async_subdev * -__v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier, - int adapter_id, unsigned short address, - unsigned int asd_struct_size) +__v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier, int adapter_id, + unsigned short address, unsigned int asd_struct_size) { struct v4l2_async_subdev *asd; int ret; @@ -695,7 +691,7 @@ __v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier, asd->match.i2c.adapter_id = adapter_id; asd->match.i2c.address = address; - ret = __v4l2_async_notifier_add_subdev(notifier, asd); + ret = __v4l2_async_nf_add_subdev(notifier, asd); if (ret) { kfree(asd); return ERR_PTR(ret); @@ -703,7 +699,7 @@ __v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier, return asd; } -EXPORT_SYMBOL_GPL(__v4l2_async_notifier_add_i2c_subdev); +EXPORT_SYMBOL_GPL(__v4l2_async_nf_add_i2c); int v4l2_async_register_subdev(struct v4l2_subdev *sd) { @@ -725,7 +721,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) list_for_each_entry(notifier, ¬ifier_list, list) { struct v4l2_device *v4l2_dev = - v4l2_async_notifier_find_v4l2_dev(notifier); + v4l2_async_nf_find_v4l2_dev(notifier); struct v4l2_async_subdev *asd; if (!v4l2_dev) @@ -739,7 +735,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) if (ret) goto err_unbind; - ret = v4l2_async_notifier_try_complete(notifier); + ret = v4l2_async_nf_try_complete(notifier); if (ret) goto err_unbind; @@ -761,10 +757,10 @@ err_unbind: */ subdev_notifier = v4l2_async_find_subdev_notifier(sd); if (subdev_notifier) - v4l2_async_notifier_unbind_all_subdevs(subdev_notifier); + v4l2_async_nf_unbind_all_subdevs(subdev_notifier); if (sd->asd) - v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); + v4l2_async_nf_call_unbind(notifier, sd, sd->asd); v4l2_async_cleanup(sd); mutex_unlock(&list_lock); @@ -780,8 +776,8 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) mutex_lock(&list_lock); - __v4l2_async_notifier_unregister(sd->subdev_notifier); - __v4l2_async_notifier_cleanup(sd->subdev_notifier); + __v4l2_async_nf_unregister(sd->subdev_notifier); + __v4l2_async_nf_cleanup(sd->subdev_notifier); kfree(sd->subdev_notifier); sd->subdev_notifier = NULL; @@ -790,7 +786,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) list_add(&sd->asd->list, ¬ifier->waiting); - v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); + v4l2_async_nf_call_unbind(notifier, sd, sd->asd); } v4l2_async_cleanup(sd); @@ -825,7 +821,7 @@ static void print_waiting_subdev(struct seq_file *s, } static const char * -v4l2_async_notifier_name(struct v4l2_async_notifier *notifier) +v4l2_async_nf_name(struct v4l2_async_notifier *notifier) { if (notifier->v4l2_dev) return notifier->v4l2_dev->name; @@ -843,7 +839,7 @@ static int pending_subdevs_show(struct seq_file *s, void *data) mutex_lock(&list_lock); list_for_each_entry(notif, ¬ifier_list, list) { - seq_printf(s, "%s:\n", v4l2_async_notifier_name(notif)); + seq_printf(s, "%s:\n", v4l2_async_nf_name(notif)); list_for_each_entry(asd, ¬if->waiting, list) print_waiting_subdev(s, asd); } diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 843259c304bb..e5507501b0f3 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -780,11 +780,11 @@ int v4l2_fwnode_device_parse(struct device *dev, EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse); static int -v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev, - struct v4l2_async_notifier *notifier, - struct fwnode_handle *endpoint, - unsigned int asd_struct_size, - parse_endpoint_func parse_endpoint) +v4l2_async_nf_fwnode_parse_endpoint(struct device *dev, + struct v4l2_async_notifier *notifier, + struct fwnode_handle *endpoint, + unsigned int asd_struct_size, + parse_endpoint_func parse_endpoint) { struct v4l2_fwnode_endpoint vep = { .bus_type = 0 }; struct v4l2_async_subdev *asd; @@ -822,7 +822,7 @@ v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev, if (ret < 0) goto out_err; - ret = __v4l2_async_notifier_add_subdev(notifier, asd); + ret = __v4l2_async_nf_add_subdev(notifier, asd); if (ret < 0) { /* not an error if asd already exists */ if (ret == -EEXIST) @@ -840,12 +840,11 @@ out_err: } static int -__v4l2_async_notifier_parse_fwnode_ep(struct device *dev, - struct v4l2_async_notifier *notifier, - size_t asd_struct_size, - unsigned int port, - bool has_port, - parse_endpoint_func parse_endpoint) +__v4l2_async_nf_parse_fwnode_ep(struct device *dev, + struct v4l2_async_notifier *notifier, + size_t asd_struct_size, unsigned int port, + bool has_port, + parse_endpoint_func parse_endpoint) { struct fwnode_handle *fwnode; int ret = 0; @@ -874,11 +873,10 @@ __v4l2_async_notifier_parse_fwnode_ep(struct device *dev, continue; } - ret = v4l2_async_notifier_fwnode_parse_endpoint(dev, - notifier, - fwnode, - asd_struct_size, - parse_endpoint); + ret = v4l2_async_nf_fwnode_parse_endpoint(dev, notifier, + fwnode, + asd_struct_size, + parse_endpoint); if (ret < 0) break; } @@ -889,16 +887,15 @@ __v4l2_async_notifier_parse_fwnode_ep(struct device *dev, } int -v4l2_async_notifier_parse_fwnode_endpoints(struct device *dev, - struct v4l2_async_notifier *notifier, - size_t asd_struct_size, - parse_endpoint_func parse_endpoint) +v4l2_async_nf_parse_fwnode_endpoints(struct device *dev, + struct v4l2_async_notifier *notifier, + size_t asd_struct_size, + parse_endpoint_func parse_endpoint) { - return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier, - asd_struct_size, 0, - false, parse_endpoint); + return __v4l2_async_nf_parse_fwnode_ep(dev, notifier, asd_struct_size, + 0, false, parse_endpoint); } -EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints); +EXPORT_SYMBOL_GPL(v4l2_async_nf_parse_fwnode_endpoints); /* * v4l2_fwnode_reference_parse - parse references for async sub-devices @@ -942,9 +939,8 @@ static int v4l2_fwnode_reference_parse(struct device *dev, index++) { struct v4l2_async_subdev *asd; - asd = v4l2_async_notifier_add_fwnode_subdev(notifier, - args.fwnode, - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode(notifier, args.fwnode, + struct v4l2_async_subdev); fwnode_handle_put(args.fwnode); if (IS_ERR(asd)) { /* not an error if asd already exists */ @@ -1243,8 +1239,8 @@ v4l2_fwnode_reference_parse_int_props(struct device *dev, index++) { struct v4l2_async_subdev *asd; - asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode, - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode(notifier, fwnode, + struct v4l2_async_subdev); fwnode_handle_put(fwnode); if (IS_ERR(asd)) { ret = PTR_ERR(asd); @@ -1260,7 +1256,7 @@ v4l2_fwnode_reference_parse_int_props(struct device *dev, } /** - * v4l2_async_notifier_parse_fwnode_sensor - parse common references on + * v4l2_async_nf_parse_fwnode_sensor - parse common references on * sensors for async sub-devices * @dev: the device node the properties of which are parsed for references * @notifier: the async notifier where the async subdevs will be added @@ -1269,7 +1265,7 @@ v4l2_fwnode_reference_parse_int_props(struct device *dev, * sensor and set up async sub-devices for them. * * Any notifier populated using this function must be released with a call to - * v4l2_async_notifier_release() after it has been unregistered and the async + * v4l2_async_nf_release() after it has been unregistered and the async * sub-devices are no longer in use, even in the case the function returned an * error. * @@ -1278,8 +1274,8 @@ v4l2_fwnode_reference_parse_int_props(struct device *dev, * -EINVAL if property parsing failed */ static int -v4l2_async_notifier_parse_fwnode_sensor(struct device *dev, - struct v4l2_async_notifier *notifier) +v4l2_async_nf_parse_fwnode_sensor(struct device *dev, + struct v4l2_async_notifier *notifier) { static const char * const led_props[] = { "led" }; static const struct v4l2_fwnode_int_props props[] = { @@ -1320,13 +1316,13 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) if (!notifier) return -ENOMEM; - v4l2_async_notifier_init(notifier); + v4l2_async_nf_init(notifier); - ret = v4l2_async_notifier_parse_fwnode_sensor(sd->dev, notifier); + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); if (ret < 0) goto out_cleanup; - ret = v4l2_async_subdev_notifier_register(sd, notifier); + ret = v4l2_async_subdev_nf_register(sd, notifier); if (ret < 0) goto out_cleanup; @@ -1339,10 +1335,10 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) return 0; out_unregister: - v4l2_async_notifier_unregister(notifier); + v4l2_async_nf_unregister(notifier); out_cleanup: - v4l2_async_notifier_cleanup(notifier); + v4l2_async_nf_cleanup(notifier); kfree(notifier); return ret; diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index bb1305c9daaf..45f9d797b9da 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -1924,7 +1924,7 @@ static int imx_csi_async_register(struct csi_priv *priv) unsigned int port; int ret; - v4l2_async_notifier_init(&priv->notifier); + v4l2_async_nf_init(&priv->notifier); /* get this CSI's port id */ ret = fwnode_property_read_u32(dev_fwnode(priv->dev), "reg", &port); @@ -1935,8 +1935,8 @@ static int imx_csi_async_register(struct csi_priv *priv) port, 0, FWNODE_GRAPH_ENDPOINT_NEXT); if (ep) { - asd = v4l2_async_notifier_add_fwnode_remote_subdev( - &priv->notifier, ep, struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&priv->notifier, ep, + struct v4l2_async_subdev); fwnode_handle_put(ep); @@ -1950,8 +1950,7 @@ static int imx_csi_async_register(struct csi_priv *priv) priv->notifier.ops = &csi_notify_ops; - ret = v4l2_async_subdev_notifier_register(&priv->sd, - &priv->notifier); + ret = v4l2_async_subdev_nf_register(&priv->sd, &priv->notifier); if (ret) return ret; @@ -2040,8 +2039,8 @@ static int imx_csi_probe(struct platform_device *pdev) return 0; cleanup: - v4l2_async_notifier_unregister(&priv->notifier); - v4l2_async_notifier_cleanup(&priv->notifier); + v4l2_async_nf_unregister(&priv->notifier); + v4l2_async_nf_cleanup(&priv->notifier); free: v4l2_ctrl_handler_free(&priv->ctrl_hdlr); mutex_destroy(&priv->lock); @@ -2055,8 +2054,8 @@ static int imx_csi_remove(struct platform_device *pdev) v4l2_ctrl_handler_free(&priv->ctrl_hdlr); mutex_destroy(&priv->lock); - v4l2_async_notifier_unregister(&priv->notifier); - v4l2_async_notifier_cleanup(&priv->notifier); + v4l2_async_nf_unregister(&priv->notifier); + v4l2_async_nf_cleanup(&priv->notifier); v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); diff --git a/drivers/staging/media/imx/imx-media-dev-common.c b/drivers/staging/media/imx/imx-media-dev-common.c index d186179388d0..d006e961d8f4 100644 --- a/drivers/staging/media/imx/imx-media-dev-common.c +++ b/drivers/staging/media/imx/imx-media-dev-common.c @@ -379,7 +379,7 @@ struct imx_media_dev *imx_media_dev_init(struct device *dev, INIT_LIST_HEAD(&imxmd->vdev_list); - v4l2_async_notifier_init(&imxmd->notifier); + v4l2_async_nf_init(&imxmd->notifier); return imxmd; @@ -403,11 +403,10 @@ int imx_media_dev_notifier_register(struct imx_media_dev *imxmd, /* prepare the async subdev notifier and register it */ imxmd->notifier.ops = ops ? ops : &imx_media_notifier_ops; - ret = v4l2_async_notifier_register(&imxmd->v4l2_dev, - &imxmd->notifier); + ret = v4l2_async_nf_register(&imxmd->v4l2_dev, &imxmd->notifier); if (ret) { v4l2_err(&imxmd->v4l2_dev, - "v4l2_async_notifier_register failed with %d\n", ret); + "v4l2_async_nf_register failed with %d\n", ret); return ret; } diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c index 338b8bd0bb07..f85462214e22 100644 --- a/drivers/staging/media/imx/imx-media-dev.c +++ b/drivers/staging/media/imx/imx-media-dev.c @@ -94,7 +94,7 @@ static int imx_media_probe(struct platform_device *pdev) return 0; cleanup: - v4l2_async_notifier_cleanup(&imxmd->notifier); + v4l2_async_nf_cleanup(&imxmd->notifier); v4l2_device_unregister(&imxmd->v4l2_dev); media_device_cleanup(&imxmd->md); @@ -113,9 +113,9 @@ static int imx_media_remove(struct platform_device *pdev) imxmd->m2m_vdev = NULL; } - v4l2_async_notifier_unregister(&imxmd->notifier); + v4l2_async_nf_unregister(&imxmd->notifier); imx_media_unregister_ipu_internal_subdevs(imxmd); - v4l2_async_notifier_cleanup(&imxmd->notifier); + v4l2_async_nf_cleanup(&imxmd->notifier); media_device_unregister(&imxmd->md); v4l2_device_unregister(&imxmd->v4l2_dev); media_device_cleanup(&imxmd->md); diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c index b677cf0e0c84..59f1eb7b62bc 100644 --- a/drivers/staging/media/imx/imx-media-of.c +++ b/drivers/staging/media/imx/imx-media-of.c @@ -29,9 +29,9 @@ int imx_media_of_add_csi(struct imx_media_dev *imxmd, } /* add CSI fwnode to async notifier */ - asd = v4l2_async_notifier_add_fwnode_subdev(&imxmd->notifier, - of_fwnode_handle(csi_np), - struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode(&imxmd->notifier, + of_fwnode_handle(csi_np), + struct v4l2_async_subdev); if (IS_ERR(asd)) { ret = PTR_ERR(asd); if (ret == -EEXIST) diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c index 9de0ebd439dc..a0941fc2907b 100644 --- a/drivers/staging/media/imx/imx6-mipi-csi2.c +++ b/drivers/staging/media/imx/imx6-mipi-csi2.c @@ -647,7 +647,7 @@ static int csi2_async_register(struct csi2_dev *csi2) struct fwnode_handle *ep; int ret; - v4l2_async_notifier_init(&csi2->notifier); + v4l2_async_nf_init(&csi2->notifier); ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi2->dev), 0, 0, FWNODE_GRAPH_ENDPOINT_NEXT); @@ -663,8 +663,8 @@ static int csi2_async_register(struct csi2_dev *csi2) dev_dbg(csi2->dev, "data lanes: %d\n", vep.bus.mipi_csi2.num_data_lanes); dev_dbg(csi2->dev, "flags: 0x%08x\n", vep.bus.mipi_csi2.flags); - asd = v4l2_async_notifier_add_fwnode_remote_subdev( - &csi2->notifier, ep, struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&csi2->notifier, ep, + struct v4l2_async_subdev); fwnode_handle_put(ep); if (IS_ERR(asd)) @@ -672,8 +672,7 @@ static int csi2_async_register(struct csi2_dev *csi2) csi2->notifier.ops = &csi2_notify_ops; - ret = v4l2_async_subdev_notifier_register(&csi2->sd, - &csi2->notifier); + ret = v4l2_async_subdev_nf_register(&csi2->sd, &csi2->notifier); if (ret) return ret; @@ -768,8 +767,8 @@ static int csi2_probe(struct platform_device *pdev) return 0; clean_notifier: - v4l2_async_notifier_unregister(&csi2->notifier); - v4l2_async_notifier_cleanup(&csi2->notifier); + v4l2_async_nf_unregister(&csi2->notifier); + v4l2_async_nf_cleanup(&csi2->notifier); clk_disable_unprepare(csi2->dphy_clk); pllref_off: clk_disable_unprepare(csi2->pllref_clk); @@ -783,8 +782,8 @@ static int csi2_remove(struct platform_device *pdev) struct v4l2_subdev *sd = platform_get_drvdata(pdev); struct csi2_dev *csi2 = sd_to_dev(sd); - v4l2_async_notifier_unregister(&csi2->notifier); - v4l2_async_notifier_cleanup(&csi2->notifier); + v4l2_async_nf_unregister(&csi2->notifier); + v4l2_async_nf_cleanup(&csi2->notifier); v4l2_async_unregister_subdev(sd); clk_disable_unprepare(csi2->dphy_clk); clk_disable_unprepare(csi2->pllref_clk); diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index 127183732912..2288dadb2683 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -1099,13 +1099,13 @@ static int imx7_csi_async_register(struct imx7_csi *csi) struct fwnode_handle *ep; int ret; - v4l2_async_notifier_init(&csi->notifier); + v4l2_async_nf_init(&csi->notifier); ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0, FWNODE_GRAPH_ENDPOINT_NEXT); if (ep) { - asd = v4l2_async_notifier_add_fwnode_remote_subdev( - &csi->notifier, ep, struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, ep, + struct v4l2_async_subdev); fwnode_handle_put(ep); @@ -1119,7 +1119,7 @@ static int imx7_csi_async_register(struct imx7_csi *csi) csi->notifier.ops = &imx7_csi_notify_ops; - ret = v4l2_async_subdev_notifier_register(&csi->sd, &csi->notifier); + ret = v4l2_async_subdev_nf_register(&csi->sd, &csi->notifier); if (ret) return ret; @@ -1210,12 +1210,12 @@ static int imx7_csi_probe(struct platform_device *pdev) return 0; subdev_notifier_cleanup: - v4l2_async_notifier_unregister(&csi->notifier); - v4l2_async_notifier_cleanup(&csi->notifier); + v4l2_async_nf_unregister(&csi->notifier); + v4l2_async_nf_cleanup(&csi->notifier); cleanup: - v4l2_async_notifier_unregister(&imxmd->notifier); - v4l2_async_notifier_cleanup(&imxmd->notifier); + v4l2_async_nf_unregister(&imxmd->notifier); + v4l2_async_nf_cleanup(&imxmd->notifier); v4l2_device_unregister(&imxmd->v4l2_dev); media_device_unregister(&imxmd->md); media_device_cleanup(&imxmd->md); @@ -1232,15 +1232,15 @@ static int imx7_csi_remove(struct platform_device *pdev) struct imx7_csi *csi = v4l2_get_subdevdata(sd); struct imx_media_dev *imxmd = csi->imxmd; - v4l2_async_notifier_unregister(&imxmd->notifier); - v4l2_async_notifier_cleanup(&imxmd->notifier); + v4l2_async_nf_unregister(&imxmd->notifier); + v4l2_async_nf_cleanup(&imxmd->notifier); media_device_unregister(&imxmd->md); v4l2_device_unregister(&imxmd->v4l2_dev); media_device_cleanup(&imxmd->md); - v4l2_async_notifier_unregister(&csi->notifier); - v4l2_async_notifier_cleanup(&csi->notifier); + v4l2_async_nf_unregister(&csi->notifier); + v4l2_async_nf_cleanup(&csi->notifier); v4l2_async_unregister_subdev(sd); mutex_destroy(&csi->lock); diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c index 41e33535de55..2b73fa55c938 100644 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ b/drivers/staging/media/imx/imx7-mipi-csis.c @@ -1162,7 +1162,7 @@ static int mipi_csis_async_register(struct csi_state *state) unsigned int i; int ret; - v4l2_async_notifier_init(&state->notifier); + v4l2_async_nf_init(&state->notifier); ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0, FWNODE_GRAPH_ENDPOINT_NEXT); @@ -1187,8 +1187,8 @@ static int mipi_csis_async_register(struct csi_state *state) dev_dbg(state->dev, "data lanes: %d\n", state->bus.num_data_lanes); dev_dbg(state->dev, "flags: 0x%08x\n", state->bus.flags); - asd = v4l2_async_notifier_add_fwnode_remote_subdev( - &state->notifier, ep, struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&state->notifier, ep, + struct v4l2_async_subdev); if (IS_ERR(asd)) { ret = PTR_ERR(asd); goto err_parse; @@ -1198,7 +1198,7 @@ static int mipi_csis_async_register(struct csi_state *state) state->notifier.ops = &mipi_csis_notify_ops; - ret = v4l2_async_subdev_notifier_register(&state->sd, &state->notifier); + ret = v4l2_async_subdev_nf_register(&state->sd, &state->notifier); if (ret) return ret; @@ -1429,8 +1429,8 @@ unregister_all: mipi_csis_debugfs_exit(state); cleanup: media_entity_cleanup(&state->sd.entity); - v4l2_async_notifier_unregister(&state->notifier); - v4l2_async_notifier_cleanup(&state->notifier); + v4l2_async_nf_unregister(&state->notifier); + v4l2_async_nf_cleanup(&state->notifier); v4l2_async_unregister_subdev(&state->sd); disable_clock: mipi_csis_clk_disable(state); @@ -1445,8 +1445,8 @@ static int mipi_csis_remove(struct platform_device *pdev) struct csi_state *state = mipi_sd_to_csis_state(sd); mipi_csis_debugfs_exit(state); - v4l2_async_notifier_unregister(&state->notifier); - v4l2_async_notifier_cleanup(&state->notifier); + v4l2_async_nf_unregister(&state->notifier); + v4l2_async_nf_cleanup(&state->notifier); v4l2_async_unregister_subdev(&state->sd); pm_runtime_disable(&pdev->dev); diff --git a/drivers/staging/media/imx/imx8mq-mipi-csi2.c b/drivers/staging/media/imx/imx8mq-mipi-csi2.c index a6f562009b9a..7adbdd14daa9 100644 --- a/drivers/staging/media/imx/imx8mq-mipi-csi2.c +++ b/drivers/staging/media/imx/imx8mq-mipi-csi2.c @@ -643,7 +643,7 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state) unsigned int i; int ret; - v4l2_async_notifier_init(&state->notifier); + v4l2_async_nf_init(&state->notifier); ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0, FWNODE_GRAPH_ENDPOINT_NEXT); @@ -669,8 +669,8 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state) state->bus.num_data_lanes, state->bus.flags); - asd = v4l2_async_notifier_add_fwnode_remote_subdev(&state->notifier, - ep, struct v4l2_async_subdev); + asd = v4l2_async_nf_add_fwnode_remote(&state->notifier, ep, + struct v4l2_async_subdev); if (IS_ERR(asd)) { ret = PTR_ERR(asd); goto err_parse; @@ -680,7 +680,7 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state) state->notifier.ops = &imx8mq_mipi_csi_notify_ops; - ret = v4l2_async_subdev_notifier_register(&state->sd, &state->notifier); + ret = v4l2_async_subdev_nf_register(&state->sd, &state->notifier); if (ret) return ret; @@ -937,8 +937,8 @@ cleanup: imx8mq_mipi_csi_pm_suspend(&pdev->dev, true); media_entity_cleanup(&state->sd.entity); - v4l2_async_notifier_unregister(&state->notifier); - v4l2_async_notifier_cleanup(&state->notifier); + v4l2_async_nf_unregister(&state->notifier); + v4l2_async_nf_cleanup(&state->notifier); v4l2_async_unregister_subdev(&state->sd); icc: imx8mq_mipi_csi_release_icc(pdev); @@ -953,8 +953,8 @@ static int imx8mq_mipi_csi_remove(struct platform_device *pdev) struct v4l2_subdev *sd = platform_get_drvdata(pdev); struct csi_state *state = mipi_sd_to_csi2_state(sd); - v4l2_async_notifier_unregister(&state->notifier); - v4l2_async_notifier_cleanup(&state->notifier); + v4l2_async_nf_unregister(&state->notifier); + v4l2_async_nf_cleanup(&state->notifier); v4l2_async_unregister_subdev(&state->sd); pm_runtime_disable(&pdev->dev); diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c index d321790b07d9..69d9787d5338 100644 --- a/drivers/staging/media/tegra-video/vi.c +++ b/drivers/staging/media/tegra-video/vi.c @@ -1272,7 +1272,7 @@ static int tegra_channel_init(struct tegra_vi_channel *chan) } if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG)) - v4l2_async_notifier_init(&chan->notifier); + v4l2_async_nf_init(&chan->notifier); return 0; @@ -1811,8 +1811,8 @@ static int tegra_vi_graph_parse_one(struct tegra_vi_channel *chan, continue; } - tvge = v4l2_async_notifier_add_fwnode_subdev(&chan->notifier, remote, - struct tegra_vi_graph_entity); + tvge = v4l2_async_nf_add_fwnode(&chan->notifier, remote, + struct tegra_vi_graph_entity); if (IS_ERR(tvge)) { ret = PTR_ERR(tvge); dev_err(vi->dev, @@ -1834,7 +1834,7 @@ static int tegra_vi_graph_parse_one(struct tegra_vi_channel *chan, cleanup: dev_err(vi->dev, "failed parsing the graph: %d\n", ret); - v4l2_async_notifier_cleanup(&chan->notifier); + v4l2_async_nf_cleanup(&chan->notifier); of_node_put(node); return ret; } @@ -1868,13 +1868,12 @@ static int tegra_vi_graph_init(struct tegra_vi *vi) continue; chan->notifier.ops = &tegra_vi_async_ops; - ret = v4l2_async_notifier_register(&vid->v4l2_dev, - &chan->notifier); + ret = v4l2_async_nf_register(&vid->v4l2_dev, &chan->notifier); if (ret < 0) { dev_err(vi->dev, "failed to register channel %d notifier: %d\n", chan->portnos[0], ret); - v4l2_async_notifier_cleanup(&chan->notifier); + v4l2_async_nf_cleanup(&chan->notifier); } } @@ -1887,8 +1886,8 @@ static void tegra_vi_graph_cleanup(struct tegra_vi *vi) list_for_each_entry(chan, &vi->vi_chans, list) { vb2_video_unregister_device(&chan->video); - v4l2_async_notifier_unregister(&chan->notifier); - v4l2_async_notifier_cleanup(&chan->notifier); + v4l2_async_nf_unregister(&chan->notifier); + v4l2_async_nf_cleanup(&chan->notifier); } } diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h index fa4901162663..13ff3ad948f4 100644 --- a/include/media/v4l2-async.h +++ b/include/media/v4l2-async.h @@ -123,45 +123,45 @@ struct v4l2_async_notifier { void v4l2_async_debug_init(struct dentry *debugfs_dir); /** - * v4l2_async_notifier_init - Initialize a notifier. + * v4l2_async_nf_init - Initialize a notifier. * * @notifier: pointer to &struct v4l2_async_notifier * * This function initializes the notifier @asd_list. It must be called * before adding a subdevice to a notifier, using one of: - * v4l2_async_notifier_add_fwnode_remote_subdev(), - * v4l2_async_notifier_add_fwnode_subdev(), - * v4l2_async_notifier_add_i2c_subdev(), - * __v4l2_async_notifier_add_subdev() or - * v4l2_async_notifier_parse_fwnode_endpoints(). + * v4l2_async_nf_add_fwnode_remote(), + * v4l2_async_nf_add_fwnode(), + * v4l2_async_nf_add_i2c(), + * __v4l2_async_nf_add_subdev() or + * v4l2_async_nf_parse_fwnode_endpoints(). */ -void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier); +void v4l2_async_nf_init(struct v4l2_async_notifier *notifier); /** - * __v4l2_async_notifier_add_subdev - Add an async subdev to the + * __v4l2_async_nf_add_subdev - Add an async subdev to the * notifier's master asd list. * * @notifier: pointer to &struct v4l2_async_notifier * @asd: pointer to &struct v4l2_async_subdev * * \warning: Drivers should avoid using this function and instead use one of: - * v4l2_async_notifier_add_fwnode_subdev(), - * v4l2_async_notifier_add_fwnode_remote_subdev() or - * v4l2_async_notifier_add_i2c_subdev(). + * v4l2_async_nf_add_fwnode(), + * v4l2_async_nf_add_fwnode_remote() or + * v4l2_async_nf_add_i2c(). * * Call this function before registering a notifier to link the provided @asd to * the notifiers master @asd_list. The @asd must be allocated with k*alloc() as * it will be freed by the framework when the notifier is destroyed. */ -int __v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier, - struct v4l2_async_subdev *asd); +int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier, + struct v4l2_async_subdev *asd); struct v4l2_async_subdev * -__v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier, - struct fwnode_handle *fwnode, - unsigned int asd_struct_size); +__v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier, + struct fwnode_handle *fwnode, + unsigned int asd_struct_size); /** - * v4l2_async_notifier_add_fwnode_subdev - Allocate and add a fwnode async + * v4l2_async_nf_add_fwnode - Allocate and add a fwnode async * subdev to the notifier's master asd_list. * * @notifier: pointer to &struct v4l2_async_notifier @@ -175,16 +175,15 @@ __v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier, * notifiers @asd_list. The function also gets a reference of the fwnode which * is released later at notifier cleanup time. */ -#define v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode, type) \ - ((type *)__v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode, \ - sizeof(type))) +#define v4l2_async_nf_add_fwnode(notifier, fwnode, type) \ + ((type *)__v4l2_async_nf_add_fwnode(notifier, fwnode, sizeof(type))) struct v4l2_async_subdev * -__v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif, - struct fwnode_handle *endpoint, - unsigned int asd_struct_size); +__v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif, + struct fwnode_handle *endpoint, + unsigned int asd_struct_size); /** - * v4l2_async_notifier_add_fwnode_remote_subdev - Allocate and add a fwnode + * v4l2_async_nf_add_fwnode_remote - Allocate and add a fwnode * remote async subdev to the * notifier's master asd_list. * @@ -200,20 +199,18 @@ __v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif * function also gets a reference of the fwnode which is released later at * notifier cleanup time. * - * This is just like v4l2_async_notifier_add_fwnode_subdev(), but with the + * This is just like v4l2_async_nf_add_fwnode(), but with the * exception that the fwnode refers to a local endpoint, not the remote one. */ -#define v4l2_async_notifier_add_fwnode_remote_subdev(notifier, ep, type) \ - ((type *) \ - __v4l2_async_notifier_add_fwnode_remote_subdev(notifier, ep, \ - sizeof(type))) +#define v4l2_async_nf_add_fwnode_remote(notifier, ep, type) \ + ((type *)__v4l2_async_nf_add_fwnode_remote(notifier, ep, sizeof(type))) struct v4l2_async_subdev * -__v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier, - int adapter_id, unsigned short address, - unsigned int asd_struct_size); +__v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier, + int adapter_id, unsigned short address, + unsigned int asd_struct_size); /** - * v4l2_async_notifier_add_i2c_subdev - Allocate and add an i2c async + * v4l2_async_nf_add_i2c - Allocate and add an i2c async * subdev to the notifier's master asd_list. * * @notifier: pointer to &struct v4l2_async_notifier @@ -223,59 +220,59 @@ __v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier, * v4l2_async_subdev shall be the first member of the driver's async * sub-device struct, i.e. both begin at the same memory address. * - * Same as v4l2_async_notifier_add_fwnode_subdev() but for I2C matched + * Same as v4l2_async_nf_add_fwnode() but for I2C matched * sub-devices. */ -#define v4l2_async_notifier_add_i2c_subdev(notifier, adapter, address, type) \ - ((type *)__v4l2_async_notifier_add_i2c_subdev(notifier, adapter, \ - address, sizeof(type))) +#define v4l2_async_nf_add_i2c(notifier, adapter, address, type) \ + ((type *)__v4l2_async_nf_add_i2c(notifier, adapter, address, \ + sizeof(type))) /** - * v4l2_async_notifier_register - registers a subdevice asynchronous notifier + * v4l2_async_nf_register - registers a subdevice asynchronous notifier * * @v4l2_dev: pointer to &struct v4l2_device * @notifier: pointer to &struct v4l2_async_notifier */ -int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, - struct v4l2_async_notifier *notifier); +int v4l2_async_nf_register(struct v4l2_device *v4l2_dev, + struct v4l2_async_notifier *notifier); /** - * v4l2_async_subdev_notifier_register - registers a subdevice asynchronous + * v4l2_async_subdev_nf_register - registers a subdevice asynchronous * notifier for a sub-device * * @sd: pointer to &struct v4l2_subdev * @notifier: pointer to &struct v4l2_async_notifier */ -int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd, - struct v4l2_async_notifier *notifier); +int v4l2_async_subdev_nf_register(struct v4l2_subdev *sd, + struct v4l2_async_notifier *notifier); /** - * v4l2_async_notifier_unregister - unregisters a subdevice + * v4l2_async_nf_unregister - unregisters a subdevice * asynchronous notifier * * @notifier: pointer to &struct v4l2_async_notifier */ -void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier); +void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier); /** - * v4l2_async_notifier_cleanup - clean up notifier resources + * v4l2_async_nf_cleanup - clean up notifier resources * @notifier: the notifier the resources of which are to be cleaned up * * Release memory resources related to a notifier, including the async * sub-devices allocated for the purposes of the notifier but not the notifier * itself. The user is responsible for calling this function to clean up the * notifier after calling - * v4l2_async_notifier_add_fwnode_remote_subdev(), - * v4l2_async_notifier_add_fwnode_subdev(), - * v4l2_async_notifier_add_i2c_subdev(), - * __v4l2_async_notifier_add_subdev() or - * v4l2_async_notifier_parse_fwnode_endpoints(). + * v4l2_async_nf_add_fwnode_remote(), + * v4l2_async_nf_add_fwnode(), + * v4l2_async_nf_add_i2c(), + * __v4l2_async_nf_add_subdev() or + * v4l2_async_nf_parse_fwnode_endpoints(). * - * There is no harm from calling v4l2_async_notifier_cleanup() in other + * There is no harm from calling v4l2_async_nf_cleanup() in other * cases as long as its memory has been zeroed after it has been * allocated. */ -void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier); +void v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier); /** * v4l2_async_register_subdev - registers a sub-device to the asynchronous @@ -295,7 +292,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd); * * This function is just like v4l2_async_register_subdev() with the exception * that calling it will also parse firmware interfaces for remote references - * using v4l2_async_notifier_parse_fwnode_sensor() and registers the + * using v4l2_async_nf_parse_fwnode_sensor() and registers the * async sub-devices. The sub-device is similarly unregistered by calling * v4l2_async_unregister_subdev(). * diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index 7ab033b819eb..9c97f1dbd1c6 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -463,7 +463,7 @@ typedef int (*parse_endpoint_func)(struct device *dev, struct v4l2_async_subdev *asd); /** - * v4l2_async_notifier_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a + * v4l2_async_nf_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a * device node * @dev: the device the endpoints of which are to be parsed * @notifier: notifier for @dev @@ -496,7 +496,7 @@ typedef int (*parse_endpoint_func)(struct device *dev, * to retain that configuration, the user needs to allocate memory for it. * * Any notifier populated using this function must be released with a call to - * v4l2_async_notifier_cleanup() after it has been unregistered and the async + * v4l2_async_nf_cleanup() after it has been unregistered and the async * sub-devices are no longer in use, even if the function returned an error. * * Return: %0 on success, including when no async sub-devices are found @@ -505,10 +505,10 @@ typedef int (*parse_endpoint_func)(struct device *dev, * Other error codes as returned by @parse_endpoint */ int -v4l2_async_notifier_parse_fwnode_endpoints(struct device *dev, - struct v4l2_async_notifier *notifier, - size_t asd_struct_size, - parse_endpoint_func parse_endpoint); +v4l2_async_nf_parse_fwnode_endpoints(struct device *dev, + struct v4l2_async_notifier *notifier, + size_t asd_struct_size, + parse_endpoint_func parse_endpoint); /* Helper macros to access the connector links. */ -- cgit v1.2.3 From 12f6517f9726cd9778ef957a111df102eb1629a3 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Thu, 24 Jun 2021 10:40:45 +0200 Subject: media: rcar-vin: Remove explicit device availability check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fwnode is retrieved using fwnode_graph_get_endpoint_by_id() without the FWNODE_GRAPH_DEVICE_DISABLED flag set. So there is no need to explicitly check if the fwnode is available as it always will be when the check is performed, remove it. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 8cb27c143187..1d92cc8ede8f 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -330,13 +330,6 @@ static int rvin_group_parse_of(struct rvin_dev *vin, unsigned int port, goto out; } - if (!of_device_is_available(to_of_node(fwnode))) { - vin_dbg(vin, "OF device %pOF disabled, ignoring\n", - to_of_node(fwnode)); - ret = -ENOTCONN; - goto out; - } - asd = v4l2_async_nf_add_fwnode(&vin->group->notifier, fwnode, struct v4l2_async_subdev); if (IS_ERR(asd)) { -- cgit v1.2.3 From 10aacfecee366b7a8fc1f70e19a711ab444ee370 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 12 Mar 2021 15:34:27 +0100 Subject: media: v4l2-fwnode: Simplify v4l2_async_nf_parse_fwnode_endpoints() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are only one user left of __v4l2_async_nf_parse_fwnode_ep() since [1], v4l2_async_nf_parse_fwnode_endpoints(). The two functions can be merged. The merge of the two highlights a dead code block conditioned by the argument 'has_port' that always is false and can therefor be removed. 1. commit 0ae426ebd0dcef81 ("media: v4l2-fwnode: Remove v4l2_async_notifier_parse_fwnode_endpoints_by_port()") [Sakari Ailus: Aligned some lines to opening parentheses.] Signed-off-by: Niklas Söderlund Signed-off-by: Sakari Ailus Reviewed-by: Jacopo Mondi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-fwnode.c | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index e5507501b0f3..00457e1e93f6 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -839,12 +839,11 @@ out_err: return ret == -ENOTCONN ? 0 : ret; } -static int -__v4l2_async_nf_parse_fwnode_ep(struct device *dev, - struct v4l2_async_notifier *notifier, - size_t asd_struct_size, unsigned int port, - bool has_port, - parse_endpoint_func parse_endpoint) +int +v4l2_async_nf_parse_fwnode_endpoints(struct device *dev, + struct v4l2_async_notifier *notifier, + size_t asd_struct_size, + parse_endpoint_func parse_endpoint) { struct fwnode_handle *fwnode; int ret = 0; @@ -862,16 +861,6 @@ __v4l2_async_nf_parse_fwnode_ep(struct device *dev, if (!is_available) continue; - if (has_port) { - struct fwnode_endpoint ep; - - ret = fwnode_graph_parse_endpoint(fwnode, &ep); - if (ret) - break; - - if (ep.port != port) - continue; - } ret = v4l2_async_nf_fwnode_parse_endpoint(dev, notifier, fwnode, @@ -885,16 +874,6 @@ __v4l2_async_nf_parse_fwnode_ep(struct device *dev, return ret; } - -int -v4l2_async_nf_parse_fwnode_endpoints(struct device *dev, - struct v4l2_async_notifier *notifier, - size_t asd_struct_size, - parse_endpoint_func parse_endpoint) -{ - return __v4l2_async_nf_parse_fwnode_ep(dev, notifier, asd_struct_size, - 0, false, parse_endpoint); -} EXPORT_SYMBOL_GPL(v4l2_async_nf_parse_fwnode_endpoints); /* -- cgit v1.2.3 From b9c18096f5948aae9c792aee9f355bfd64452569 Mon Sep 17 00:00:00 2001 From: Enrico Scholz Date: Mon, 26 Jul 2021 09:35:13 +0200 Subject: media: mt9p031: Read back the real clock rate The real and requested clock can differ and because it is used to calculate PLL values, the real clock rate should be read. Signed-off-by: Enrico Scholz Signed-off-by: Stefan Riedmueller Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9p031.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 6eb88ef99783..9dea7c813852 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -229,6 +229,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); struct mt9p031_platform_data *pdata = mt9p031->pdata; + unsigned long ext_freq; int ret; mt9p031->clk = devm_clk_get(&client->dev, NULL); @@ -239,13 +240,15 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) if (ret < 0) return ret; + ext_freq = clk_get_rate(mt9p031->clk); + /* If the external clock frequency is out of bounds for the PLL use the * pixel clock divider only and disable the PLL. */ - if (pdata->ext_freq > limits.ext_clock_max) { + if (ext_freq > limits.ext_clock_max) { unsigned int div; - div = DIV_ROUND_UP(pdata->ext_freq, pdata->target_freq); + div = DIV_ROUND_UP(ext_freq, pdata->target_freq); div = roundup_pow_of_two(div) / 2; mt9p031->clk_div = min_t(unsigned int, div, 64); @@ -254,7 +257,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) return 0; } - mt9p031->pll.ext_clock = pdata->ext_freq; + mt9p031->pll.ext_clock = ext_freq; mt9p031->pll.pix_clock = pdata->target_freq; mt9p031->use_pll = true; -- cgit v1.2.3 From ae47ee5fc4703bb55278c4185f76c81f980f91eb Mon Sep 17 00:00:00 2001 From: Christian Hemp Date: Mon, 26 Jul 2021 09:35:14 +0200 Subject: media: mt9p031: Make pixel clock polarity configurable by DT Evaluate the desired pixel clock polarity from the device tree. Signed-off-by: Christian Hemp Signed-off-by: Stefan Riedmueller Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 1 + drivers/media/i2c/mt9p031.c | 20 +++++++++++++++++++- include/media/i2c/mt9p031.h | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 08feb3e8c1bf..c26b05ed1f72 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -1229,6 +1229,7 @@ config VIDEO_MT9P031 select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEO_APTINA_PLL + select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the Aptina (Micron) mt9p031 5 Mpixel camera. diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 9dea7c813852..ea90aff576ba 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "aptina-pll.h" @@ -372,6 +373,14 @@ static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on) return ret; } + /* Configure the pixel clock polarity */ + if (mt9p031->pdata && mt9p031->pdata->pixclk_pol) { + ret = mt9p031_write(client, MT9P031_PIXEL_CLOCK_CONTROL, + MT9P031_PIXEL_CLOCK_INVERT); + if (ret < 0) + return ret; + } + return v4l2_ctrl_handler_setup(&mt9p031->ctrls); } @@ -1014,8 +1023,11 @@ static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = { static struct mt9p031_platform_data * mt9p031_get_pdata(struct i2c_client *client) { - struct mt9p031_platform_data *pdata; + struct mt9p031_platform_data *pdata = NULL; struct device_node *np; + struct v4l2_fwnode_endpoint endpoint = { + .bus_type = V4L2_MBUS_PARALLEL + }; if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; @@ -1024,6 +1036,9 @@ mt9p031_get_pdata(struct i2c_client *client) if (!np) return NULL; + if (v4l2_fwnode_endpoint_parse(of_fwnode_handle(np), &endpoint) < 0) + goto done; + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) goto done; @@ -1031,6 +1046,9 @@ mt9p031_get_pdata(struct i2c_client *client) of_property_read_u32(np, "input-clock-frequency", &pdata->ext_freq); of_property_read_u32(np, "pixel-clock-frequency", &pdata->target_freq); + pdata->pixclk_pol = !!(endpoint.bus.parallel.flags & + V4L2_MBUS_PCLK_SAMPLE_RISING); + done: of_node_put(np); return pdata; diff --git a/include/media/i2c/mt9p031.h b/include/media/i2c/mt9p031.h index 7c29c53aa988..f933cd0be8e5 100644 --- a/include/media/i2c/mt9p031.h +++ b/include/media/i2c/mt9p031.h @@ -10,6 +10,7 @@ struct v4l2_subdev; * @target_freq: Pixel clock frequency */ struct mt9p031_platform_data { + unsigned int pixclk_pol:1; int ext_freq; int target_freq; }; -- cgit v1.2.3 From 0961ba6dd211a4a52d1dd4c2d59be60ac2dc08c7 Mon Sep 17 00:00:00 2001 From: Dirk Bender Date: Mon, 26 Jul 2021 09:35:15 +0200 Subject: media: mt9p031: Fix corrupted frame after restarting stream To prevent corrupted frames after starting and stopping the sensor its datasheet specifies a specific pause sequence to follow: Stopping: Set Pause_Restart Bit -> Set Restart Bit -> Set Chip_Enable Off Restarting: Set Chip_Enable On -> Clear Pause_Restart Bit The Restart Bit is cleared automatically and must not be cleared manually as this would cause undefined behavior. Signed-off-by: Dirk Bender Signed-off-by: Stefan Riedmueller Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9p031.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index ea90aff576ba..ee2777059682 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -79,7 +79,9 @@ #define MT9P031_PIXEL_CLOCK_INVERT (1 << 15) #define MT9P031_PIXEL_CLOCK_SHIFT(n) ((n) << 8) #define MT9P031_PIXEL_CLOCK_DIVIDE(n) ((n) << 0) -#define MT9P031_FRAME_RESTART 0x0b +#define MT9P031_RESTART 0x0b +#define MT9P031_FRAME_PAUSE_RESTART (1 << 1) +#define MT9P031_FRAME_RESTART (1 << 0) #define MT9P031_SHUTTER_DELAY 0x0c #define MT9P031_RST 0x0d #define MT9P031_RST_ENABLE 1 @@ -456,9 +458,23 @@ static int mt9p031_set_params(struct mt9p031 *mt9p031) static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); + struct i2c_client *client = v4l2_get_subdevdata(subdev); + int val; int ret; if (!enable) { + /* enable pause restart */ + val = MT9P031_FRAME_PAUSE_RESTART; + ret = mt9p031_write(client, MT9P031_RESTART, val); + if (ret < 0) + return ret; + + /* enable restart + keep pause restart set */ + val |= MT9P031_FRAME_RESTART; + ret = mt9p031_write(client, MT9P031_RESTART, val); + if (ret < 0) + return ret; + /* Stop sensor readout */ ret = mt9p031_set_output_control(mt9p031, MT9P031_OUTPUT_CONTROL_CEN, 0); @@ -478,6 +494,16 @@ static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable) if (ret < 0) return ret; + /* + * - clear pause restart + * - don't clear restart as clearing restart manually can cause + * undefined behavior + */ + val = MT9P031_FRAME_RESTART; + ret = mt9p031_write(client, MT9P031_RESTART, val); + if (ret < 0) + return ret; + return mt9p031_pll_enable(mt9p031); } -- cgit v1.2.3 From 0a0e78d13a42fcb9c6d82293a5f4a6f8f2677268 Mon Sep 17 00:00:00 2001 From: Stefan Riedmueller Date: Mon, 26 Jul 2021 09:35:16 +0200 Subject: media: mt9p031: Use BIT macro Make use of the BIT macro for setting individual bits. This improves readability and safety with respect to shifts. When on it also remove two zero value disable defines. Signed-off-by: Stefan Riedmueller Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9p031.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index ee2777059682..cbce8b88dbcf 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -76,40 +76,38 @@ #define MT9P031_PLL_CONFIG_1 0x11 #define MT9P031_PLL_CONFIG_2 0x12 #define MT9P031_PIXEL_CLOCK_CONTROL 0x0a -#define MT9P031_PIXEL_CLOCK_INVERT (1 << 15) +#define MT9P031_PIXEL_CLOCK_INVERT BIT(15) #define MT9P031_PIXEL_CLOCK_SHIFT(n) ((n) << 8) #define MT9P031_PIXEL_CLOCK_DIVIDE(n) ((n) << 0) #define MT9P031_RESTART 0x0b -#define MT9P031_FRAME_PAUSE_RESTART (1 << 1) -#define MT9P031_FRAME_RESTART (1 << 0) +#define MT9P031_FRAME_PAUSE_RESTART BIT(1) +#define MT9P031_FRAME_RESTART BIT(0) #define MT9P031_SHUTTER_DELAY 0x0c #define MT9P031_RST 0x0d -#define MT9P031_RST_ENABLE 1 -#define MT9P031_RST_DISABLE 0 +#define MT9P031_RST_ENABLE BIT(0) #define MT9P031_READ_MODE_1 0x1e #define MT9P031_READ_MODE_2 0x20 -#define MT9P031_READ_MODE_2_ROW_MIR (1 << 15) -#define MT9P031_READ_MODE_2_COL_MIR (1 << 14) -#define MT9P031_READ_MODE_2_ROW_BLC (1 << 6) +#define MT9P031_READ_MODE_2_ROW_MIR BIT(15) +#define MT9P031_READ_MODE_2_COL_MIR BIT(14) +#define MT9P031_READ_MODE_2_ROW_BLC BIT(6) #define MT9P031_ROW_ADDRESS_MODE 0x22 #define MT9P031_COLUMN_ADDRESS_MODE 0x23 #define MT9P031_GLOBAL_GAIN 0x35 #define MT9P031_GLOBAL_GAIN_MIN 8 #define MT9P031_GLOBAL_GAIN_MAX 1024 #define MT9P031_GLOBAL_GAIN_DEF 8 -#define MT9P031_GLOBAL_GAIN_MULT (1 << 6) +#define MT9P031_GLOBAL_GAIN_MULT BIT(6) #define MT9P031_ROW_BLACK_TARGET 0x49 #define MT9P031_ROW_BLACK_DEF_OFFSET 0x4b #define MT9P031_GREEN1_OFFSET 0x60 #define MT9P031_GREEN2_OFFSET 0x61 #define MT9P031_BLACK_LEVEL_CALIBRATION 0x62 -#define MT9P031_BLC_MANUAL_BLC (1 << 0) +#define MT9P031_BLC_MANUAL_BLC BIT(0) #define MT9P031_RED_OFFSET 0x63 #define MT9P031_BLUE_OFFSET 0x64 #define MT9P031_TEST_PATTERN 0xa0 #define MT9P031_TEST_PATTERN_SHIFT 3 -#define MT9P031_TEST_PATTERN_ENABLE (1 << 0) -#define MT9P031_TEST_PATTERN_DISABLE (0 << 0) +#define MT9P031_TEST_PATTERN_ENABLE BIT(0) #define MT9P031_TEST_PATTERN_GREEN 0xa1 #define MT9P031_TEST_PATTERN_RED 0xa2 #define MT9P031_TEST_PATTERN_BLUE 0xa3 @@ -199,7 +197,7 @@ static int mt9p031_reset(struct mt9p031 *mt9p031) ret = mt9p031_write(client, MT9P031_RST, MT9P031_RST_ENABLE); if (ret < 0) return ret; - ret = mt9p031_write(client, MT9P031_RST, MT9P031_RST_DISABLE); + ret = mt9p031_write(client, MT9P031_RST, 0); if (ret < 0) return ret; @@ -794,8 +792,7 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl) if (ret < 0) return ret; - return mt9p031_write(client, MT9P031_TEST_PATTERN, - MT9P031_TEST_PATTERN_DISABLE); + return mt9p031_write(client, MT9P031_TEST_PATTERN, 0); } ret = mt9p031_write(client, MT9P031_TEST_PATTERN_GREEN, 0x05a0); -- cgit v1.2.3 From e5879baf0310fb9bfab954801a359d2f12d97941 Mon Sep 17 00:00:00 2001 From: Stefan Riedmueller Date: Mon, 26 Jul 2021 09:35:17 +0200 Subject: media: dt-bindings: mt9p031: Convert bindings to yaml Convert mt9p031 sensor bindings to yaml schema. Also update the MAINTAINERS entry. Although input-clock-frequency and pixel-clock-frequency have not been definded as endpoint propierties in the textual bindings, the sensor does parse them from the endpoint. Thus move these properties to the endpoint in the new yaml bindings. Signed-off-by: Stefan Riedmueller Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/aptina,mt9p031.yaml | 86 ++++++++++++++++++++++ .../devicetree/bindings/media/i2c/mt9p031.txt | 40 ---------- MAINTAINERS | 1 + 3 files changed, 87 insertions(+), 40 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/i2c/aptina,mt9p031.yaml delete mode 100644 Documentation/devicetree/bindings/media/i2c/mt9p031.txt diff --git a/Documentation/devicetree/bindings/media/i2c/aptina,mt9p031.yaml b/Documentation/devicetree/bindings/media/i2c/aptina,mt9p031.yaml new file mode 100644 index 000000000000..bc0e8e5194e8 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/aptina,mt9p031.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/aptina,mt9p031.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Aptina 1/2.5-Inch 5Mp CMOS Digital Image Sensor + +maintainers: + - Laurent Pinchart + +description: | + The Aptina MT9P031 is a 1/2.5-inch CMOS active pixel digital image sensor + with an active array size of 2592H x 1944V. It is programmable through a + simple two-wire serial interface. + +properties: + compatible: + enum: + - aptina,mt9p031 + - aptina,mt9p031m + + reg: + description: I2C device address + maxItems: 1 + + reset-gpios: + maxItems: 1 + description: Chip reset GPIO + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + input-clock-frequency: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 6000000 + maximum: 96000000 + description: Input clock frequency + + pixel-clock-frequency: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 96000000 + description: Target pixel clock frequency + + pclk-sample: + default: 0 + + required: + - input-clock-frequency + - pixel-clock-frequency + +required: + - compatible + - reg + - port + +additionalProperties: false + +examples: + - | + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + mt9p031@5d { + compatible = "aptina,mt9p031"; + reg = <0x5d>; + reset-gpios = <&gpio_sensor 0 0>; + + port { + mt9p031_1: endpoint { + input-clock-frequency = <6000000>; + pixel-clock-frequency = <96000000>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/i2c/mt9p031.txt b/Documentation/devicetree/bindings/media/i2c/mt9p031.txt deleted file mode 100644 index cb60443ff78f..000000000000 --- a/Documentation/devicetree/bindings/media/i2c/mt9p031.txt +++ /dev/null @@ -1,40 +0,0 @@ -* Aptina 1/2.5-Inch 5Mp CMOS Digital Image Sensor - -The Aptina MT9P031 is a 1/2.5-inch CMOS active pixel digital image sensor with -an active array size of 2592H x 1944V. It is programmable through a simple -two-wire serial interface. - -Required Properties: -- compatible: value should be either one among the following - (a) "aptina,mt9p031" for mt9p031 sensor - (b) "aptina,mt9p031m" for mt9p031m sensor - -- input-clock-frequency: Input clock frequency. - -- pixel-clock-frequency: Pixel clock frequency. - -Optional Properties: -- reset-gpios: Chip reset GPIO - -For further reading on port node refer to -Documentation/devicetree/bindings/media/video-interfaces.txt. - -Example: - - i2c0@1c22000 { - ... - ... - mt9p031@5d { - compatible = "aptina,mt9p031"; - reg = <0x5d>; - reset-gpios = <&gpio3 30 0>; - - port { - mt9p031_1: endpoint { - input-clock-frequency = <6000000>; - pixel-clock-frequency = <96000000>; - }; - }; - }; - ... - }; diff --git a/MAINTAINERS b/MAINTAINERS index 5b33791bb8e9..943b7bc93c93 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12747,6 +12747,7 @@ M: Laurent Pinchart L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/aptina,mt9p031.yaml F: drivers/media/i2c/mt9p031.c F: include/media/i2c/mt9p031.h -- cgit v1.2.3 From 187980e0ab6cf88a4d27948d3c825a52e6367182 Mon Sep 17 00:00:00 2001 From: Stefan Riedmueller Date: Mon, 26 Jul 2021 09:35:18 +0200 Subject: media: dt-bindings: mt9p031: Add missing required properties Add missing required clocks and supply regulator properties for the sensor input clock and vdd, vdd_io and vaa supply regulators. Signed-off-by: Stefan Riedmueller Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/aptina,mt9p031.yaml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Documentation/devicetree/bindings/media/i2c/aptina,mt9p031.yaml b/Documentation/devicetree/bindings/media/i2c/aptina,mt9p031.yaml index bc0e8e5194e8..c2ba78116dbb 100644 --- a/Documentation/devicetree/bindings/media/i2c/aptina,mt9p031.yaml +++ b/Documentation/devicetree/bindings/media/i2c/aptina,mt9p031.yaml @@ -24,6 +24,18 @@ properties: description: I2C device address maxItems: 1 + clocks: + maxItems: 1 + + vdd-supply: + description: Digital supply voltage, 1.8 V + + vdd_io-supply: + description: I/O supply voltage, 1.8 or 2.8 V + + vaa-supply: + description: Analog supply voltage, 2.8 V + reset-gpios: maxItems: 1 description: Chip reset GPIO @@ -59,6 +71,10 @@ properties: required: - compatible - reg + - clocks + - vdd-supply + - vdd_io-supply + - vaa-supply - port additionalProperties: false @@ -74,6 +90,12 @@ examples: reg = <0x5d>; reset-gpios = <&gpio_sensor 0 0>; + clocks = <&sensor_clk>; + + vdd-supply = <®_vdd>; + vdd_io-supply = <®_vdd_io>; + vaa-supply = <®_vaa>; + port { mt9p031_1: endpoint { input-clock-frequency = <6000000>; -- cgit v1.2.3 From c57476aba3deed47248e904d1ffec67f41c659c5 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 23 Jul 2021 09:32:12 +0200 Subject: media: rockchip: rkisp1: remove unused irq variable The irq variable in struct rkisp1 is unused as it is only used to request the irq during probe, so remove it. Signed-off-by: Heiko Stuebner Reviewed-by: Dafna Hirschfeld Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-common.h | 1 - drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index bb73f4e17b66..785e916184bb 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -348,7 +348,6 @@ struct rkisp1_debug { */ struct rkisp1_device { void __iomem *base_addr; - int irq; struct device *dev; unsigned int clk_size; struct clk_bulk_data clks[RKISP1_MAX_BUS_CLK]; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index 1f2a503ea130..5d9641777c50 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -490,8 +490,6 @@ static int rkisp1_probe(struct platform_device *pdev) return ret; } - rkisp1->irq = irq; - for (i = 0; i < match_data->size; i++) rkisp1->clks[i].id = match_data->clks[i]; ret = devm_clk_bulk_get(dev, match_data->size, rkisp1->clks); -- cgit v1.2.3 From 76c4c5697f5ac546ff7706a13b86825b38d631dc Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 23 Jul 2021 09:32:13 +0200 Subject: media: dt-bindings: media: rkisp1: fix pclk clock-name Having a clock name as "pclk_isp" suggests really hard a remnant from the vendor kernel. Right now no driver _and_ no devicetree actually uses this clock name so there is still time to fix that naming. Therefore drop the "_isp" suffix and only name it pclk. Signed-off-by: Heiko Stuebner Acked-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/rockchip-isp1.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml index a6b1eff879ed..2f8f0625d22e 100644 --- a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml +++ b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml @@ -41,7 +41,7 @@ properties: - const: aclk - const: hclk # only for isp1 - - const: pclk_isp + - const: pclk iommus: maxItems: 1 -- cgit v1.2.3 From 098d9cdfdf82413f7334ef02c588255889cf0e44 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 23 Jul 2021 09:32:14 +0200 Subject: media: dt-bindings: media: rkisp1: document different irq possibilities Some variants have one irq signaling all of MI, MIPI and ISP events while some rkisp1 variants use separate irqs for each. Adapt the binding to handle both cases. Signed-off-by: Heiko Stuebner Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/rockchip-isp1.yaml | 45 +++++++++++++++------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml index 2f8f0625d22e..14ac5730b377 100644 --- a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml +++ b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml @@ -21,7 +21,14 @@ properties: maxItems: 1 interrupts: - maxItems: 1 + minItems: 1 + maxItems: 3 + + interrupt-names: + items: + - const: isp + - const: mi + - const: mipi clocks: minItems: 3 @@ -90,19 +97,29 @@ required: - power-domains - ports -if: - properties: - compatible: - contains: - const: rockchip,rk3399-cif-isp -then: - properties: - clocks: - minItems: 3 - maxItems: 4 - clock-names: - minItems: 3 - maxItems: 4 +allOf: + - if: + properties: + compatible: + contains: + const: rockchip,rk3399-cif-isp + then: + properties: + clocks: + minItems: 3 + maxItems: 4 + clock-names: + minItems: 3 + maxItems: 4 + + - if: + properties: + compatible: + contains: + const: rockchip,px30-cif-isp + then: + required: + - interrupt-names additionalProperties: false -- cgit v1.2.3 From 08818e6a1d11b39731246c72b39f2ed978e0c4c6 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 23 Jul 2021 09:32:15 +0200 Subject: media: rockchip: rkisp1: allow separate interrupts Depending on the per-soc implementation there can be one interrupt for isp, mipi and capture events or separate per-event interrupts. So simply check for the presence of a named "mi" interrupt to differentiate between the two cases. Signed-off-by: Heiko Stuebner Reviewed-by: Dafna Hirschfeld Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../platform/rockchip/rkisp1/rkisp1-capture.c | 9 +++- .../media/platform/rockchip/rkisp1/rkisp1-common.h | 7 +-- .../media/platform/rockchip/rkisp1/rkisp1-dev.c | 54 ++++++++++++++-------- .../media/platform/rockchip/rkisp1/rkisp1-isp.c | 16 +++++-- 4 files changed, 58 insertions(+), 28 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index 41988eb0ec0a..768987d5f2dd 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -685,12 +685,17 @@ static void rkisp1_handle_buffer(struct rkisp1_capture *cap) spin_unlock(&cap->buf.lock); } -void rkisp1_capture_isr(struct rkisp1_device *rkisp1) +irqreturn_t rkisp1_capture_isr(int irq, void *ctx) { + struct device *dev = ctx; + struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); unsigned int i; u32 status; status = rkisp1_read(rkisp1, RKISP1_CIF_MI_MIS); + if (!status) + return IRQ_NONE; + rkisp1_write(rkisp1, status, RKISP1_CIF_MI_ICR); for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); ++i) { @@ -718,6 +723,8 @@ void rkisp1_capture_isr(struct rkisp1_device *rkisp1) cap->is_streaming = false; wake_up(&cap->done); } + + return IRQ_HANDLED; } /* ---------------------------------------------------------------------------- diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index 785e916184bb..36ce4a0b25cf 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -12,6 +12,7 @@ #define _RKISP1_COMMON_H #include +#include #include #include #include @@ -455,9 +456,9 @@ void rkisp1_params_configure(struct rkisp1_params *params, void rkisp1_params_disable(struct rkisp1_params *params); /* irq handlers */ -void rkisp1_isp_isr(struct rkisp1_device *rkisp1); -void rkisp1_mipi_isr(struct rkisp1_device *rkisp1); -void rkisp1_capture_isr(struct rkisp1_device *rkisp1); +irqreturn_t rkisp1_isp_isr(int irq, void *ctx); +irqreturn_t rkisp1_mipi_isr(int irq, void *ctx); +irqreturn_t rkisp1_capture_isr(int irq, void *ctx); void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris); void rkisp1_params_isr(struct rkisp1_device *rkisp1); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index 5d9641777c50..b5e35b1287ac 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -101,9 +101,16 @@ * +-----------+ +-----------+ */ +struct rkisp1_isr_data { + const char *name; + irqreturn_t (*isr)(int irq, void *ctx); +}; + struct rkisp1_match_data { const char * const *clks; - unsigned int size; + unsigned int clk_size; + const struct rkisp1_isr_data *isrs; + unsigned int isr_size; enum rkisp1_cif_isp_version isp_ver; }; @@ -386,18 +393,15 @@ err_unreg_isp_subdev: static irqreturn_t rkisp1_isr(int irq, void *ctx) { - struct device *dev = ctx; - struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); - /* * Call rkisp1_capture_isr() first to handle the frame that * potentially completed using the current frame_sequence number before * it is potentially incremented by rkisp1_isp_isr() in the vertical * sync. */ - rkisp1_capture_isr(rkisp1); - rkisp1_isp_isr(rkisp1); - rkisp1_mipi_isr(rkisp1); + rkisp1_capture_isr(irq, ctx); + rkisp1_isp_isr(irq, ctx); + rkisp1_mipi_isr(irq, ctx); return IRQ_HANDLED; } @@ -408,9 +412,15 @@ static const char * const rk3399_isp_clks[] = { "hclk", }; +static const struct rkisp1_isr_data rk3399_isp_isrs[] = { + { NULL, rkisp1_isr }, +}; + static const struct rkisp1_match_data rk3399_isp_match_data = { .clks = rk3399_isp_clks, - .size = ARRAY_SIZE(rk3399_isp_clks), + .clk_size = ARRAY_SIZE(rk3399_isp_clks), + .isrs = rk3399_isp_isrs, + .isr_size = ARRAY_SIZE(rk3399_isp_isrs), .isp_ver = RKISP1_V10, }; @@ -479,23 +489,27 @@ static int rkisp1_probe(struct platform_device *pdev) if (IS_ERR(rkisp1->base_addr)) return PTR_ERR(rkisp1->base_addr); - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - ret = devm_request_irq(dev, irq, rkisp1_isr, IRQF_SHARED, - dev_driver_string(dev), dev); - if (ret) { - dev_err(dev, "request irq failed: %d\n", ret); - return ret; + for (i = 0; i < match_data->isr_size; i++) { + irq = (match_data->isrs[i].name) ? + platform_get_irq_byname(pdev, match_data->isrs[i].name) : + platform_get_irq(pdev, i); + if (irq < 0) + return irq; + + ret = devm_request_irq(dev, irq, match_data->isrs[i].isr, IRQF_SHARED, + dev_driver_string(dev), dev); + if (ret) { + dev_err(dev, "request irq failed: %d\n", ret); + return ret; + } } - for (i = 0; i < match_data->size; i++) + for (i = 0; i < match_data->clk_size; i++) rkisp1->clks[i].id = match_data->clks[i]; - ret = devm_clk_bulk_get(dev, match_data->size, rkisp1->clks); + ret = devm_clk_bulk_get(dev, match_data->clk_size, rkisp1->clks); if (ret) return ret; - rkisp1->clk_size = match_data->size; + rkisp1->clk_size = match_data->clk_size; pm_runtime_enable(&pdev->dev); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index d596bc040005..d7c422cb3276 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -1106,13 +1106,15 @@ void rkisp1_isp_unregister(struct rkisp1_device *rkisp1) * Interrupt handlers */ -void rkisp1_mipi_isr(struct rkisp1_device *rkisp1) +irqreturn_t rkisp1_mipi_isr(int irq, void *ctx) { + struct device *dev = ctx; + struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); u32 val, status; status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS); if (!status) - return; + return IRQ_NONE; rkisp1_write(rkisp1, status, RKISP1_CIF_MIPI_ICR); @@ -1147,6 +1149,8 @@ void rkisp1_mipi_isr(struct rkisp1_device *rkisp1) } else { rkisp1->debug.mipi_error++; } + + return IRQ_HANDLED; } static void rkisp1_isp_queue_event_sof(struct rkisp1_isp *isp) @@ -1159,13 +1163,15 @@ static void rkisp1_isp_queue_event_sof(struct rkisp1_isp *isp) v4l2_event_queue(isp->sd.devnode, &event); } -void rkisp1_isp_isr(struct rkisp1_device *rkisp1) +irqreturn_t rkisp1_isp_isr(int irq, void *ctx) { + struct device *dev = ctx; + struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); u32 status, isp_err; status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS); if (!status) - return; + return IRQ_NONE; rkisp1_write(rkisp1, status, RKISP1_CIF_ISP_ICR); @@ -1207,4 +1213,6 @@ void rkisp1_isp_isr(struct rkisp1_device *rkisp1) */ rkisp1_params_isr(rkisp1); } + + return IRQ_HANDLED; } -- cgit v1.2.3 From 5e8d9d72936a321d687356be072e0f367850d012 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 23 Jul 2021 09:32:16 +0200 Subject: media: rockchip: rkisp1: make some isp-param functions variable The isp block evolved in subsequent socs, so some functions will behave differently on newer variants. Therefore make it possible to override the needed params functions. Signed-off-by: Heiko Stuebner Reviewed-by: Dafna Hirschfeld Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/rockchip/rkisp1/rkisp1-common.h | 25 ++++++++ .../media/platform/rockchip/rkisp1/rkisp1-params.c | 67 +++++++++++++--------- 2 files changed, 65 insertions(+), 27 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index 36ce4a0b25cf..d91565ec23d0 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -250,11 +250,35 @@ struct rkisp1_stats { struct v4l2_format vdev_fmt; }; +struct rkisp1_params; +struct rkisp1_params_ops { + void (*lsc_matrix_config)(struct rkisp1_params *params, + const struct rkisp1_cif_isp_lsc_config *pconfig); + void (*goc_config)(struct rkisp1_params *params, + const struct rkisp1_cif_isp_goc_config *arg); + void (*awb_meas_config)(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_meas_config *arg); + void (*awb_meas_enable)(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_meas_config *arg, + bool en); + void (*awb_gain_config)(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_gain_config *arg); + void (*aec_config)(struct rkisp1_params *params, + const struct rkisp1_cif_isp_aec_config *arg); + void (*hst_config)(struct rkisp1_params *params, + const struct rkisp1_cif_isp_hst_config *arg); + void (*hst_enable)(struct rkisp1_params *params, + const struct rkisp1_cif_isp_hst_config *arg, bool en); + void (*afm_config)(struct rkisp1_params *params, + const struct rkisp1_cif_isp_afc_config *arg); +}; + /* * struct rkisp1_params - ISP input parameters device * * @vnode: video node * @rkisp1: pointer to the rkisp1 device + * @ops: pointer to the variant-specific operations * @config_lock: locks the buffer list 'params' * @params: queue of rkisp1_buffer * @vdev_fmt: v4l2_format of the metadata format @@ -264,6 +288,7 @@ struct rkisp1_stats { struct rkisp1_params { struct rkisp1_vdev_node vnode; struct rkisp1_device *rkisp1; + const struct rkisp1_params_ops *ops; spinlock_t config_lock; /* locks the buffers list 'params' */ struct list_head params; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 8fa5b0abf1f9..4cdd1448c750 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -185,8 +185,8 @@ static void rkisp1_bls_config(struct rkisp1_params *params, /* ISP LS correction interface function */ static void -rkisp1_lsc_correct_matrix_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_lsc_config *pconfig) +rkisp1_lsc_matrix_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_lsc_config *pconfig) { unsigned int isp_lsc_status, sram_addr, isp_lsc_table_sel, i, j, data; @@ -265,7 +265,7 @@ static void rkisp1_lsc_config(struct rkisp1_params *params, lsc_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_CTRL); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, RKISP1_CIF_ISP_LSC_CTRL_ENA); - rkisp1_lsc_correct_matrix_config(params, arg); + params->ops->lsc_matrix_config(params, arg); for (i = 0; i < RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE / 2; i++) { /* program x size tables */ @@ -955,7 +955,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, /* update awb gains */ if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) - rkisp1_awb_gain_config(params, &new_params->others.awb_gain_config); + params->ops->awb_gain_config(params, &new_params->others.awb_gain_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) { if (module_ens & RKISP1_CIF_ISP_MODULE_AWB_GAIN) @@ -1010,8 +1010,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, /* update goc config */ if (module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC) - rkisp1_goc_config(params, - &new_params->others.goc_config); + params->ops->goc_config(params, &new_params->others.goc_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_GOC) { if (module_ens & RKISP1_CIF_ISP_MODULE_GOC) @@ -1081,17 +1080,17 @@ static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, /* update awb config */ if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB) - rkisp1_awb_meas_config(params, &new_params->meas.awb_meas_config); + params->ops->awb_meas_config(params, &new_params->meas.awb_meas_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB) - rkisp1_awb_meas_enable(params, - &new_params->meas.awb_meas_config, - !!(module_ens & RKISP1_CIF_ISP_MODULE_AWB)); + params->ops->awb_meas_enable(params, + &new_params->meas.awb_meas_config, + !!(module_ens & RKISP1_CIF_ISP_MODULE_AWB)); /* update afc config */ if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC) - rkisp1_afm_config(params, - &new_params->meas.afc_config); + params->ops->afm_config(params, + &new_params->meas.afc_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_AFC) { if (module_ens & RKISP1_CIF_ISP_MODULE_AFC) @@ -1106,18 +1105,18 @@ static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, /* update hst config */ if (module_cfg_update & RKISP1_CIF_ISP_MODULE_HST) - rkisp1_hst_config(params, - &new_params->meas.hst_config); + params->ops->hst_config(params, + &new_params->meas.hst_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_HST) - rkisp1_hst_enable(params, - &new_params->meas.hst_config, - !!(module_ens & RKISP1_CIF_ISP_MODULE_HST)); + params->ops->hst_enable(params, + &new_params->meas.hst_config, + !!(module_ens & RKISP1_CIF_ISP_MODULE_HST)); /* update aec config */ if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC) - rkisp1_aec_config(params, - &new_params->meas.aec_config); + params->ops->aec_config(params, + &new_params->meas.aec_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_AEC) { if (module_ens & RKISP1_CIF_ISP_MODULE_AEC) @@ -1218,20 +1217,20 @@ static void rkisp1_params_config_parameter(struct rkisp1_params *params) { struct rkisp1_cif_isp_hst_config hst = rkisp1_hst_params_default_config; - rkisp1_awb_meas_config(params, &rkisp1_awb_params_default_config); - rkisp1_awb_meas_enable(params, &rkisp1_awb_params_default_config, - true); + params->ops->awb_meas_config(params, &rkisp1_awb_params_default_config); + params->ops->awb_meas_enable(params, &rkisp1_awb_params_default_config, + true); - rkisp1_aec_config(params, &rkisp1_aec_params_default_config); + params->ops->aec_config(params, &rkisp1_aec_params_default_config); rkisp1_param_set_bits(params, RKISP1_CIF_ISP_EXP_CTRL, RKISP1_CIF_ISP_EXP_ENA); - rkisp1_afm_config(params, &rkisp1_afc_params_default_config); + params->ops->afm_config(params, &rkisp1_afc_params_default_config); rkisp1_param_set_bits(params, RKISP1_CIF_ISP_AFM_CTRL, RKISP1_CIF_ISP_AFM_ENA); memset(hst.hist_weight, 0x01, sizeof(hst.hist_weight)); - rkisp1_hst_config(params, &hst); + params->ops->hst_config(params, &hst); rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP, rkisp1_hst_params_default_config.mode); @@ -1278,7 +1277,7 @@ void rkisp1_params_disable(struct rkisp1_params *params) RKISP1_CIF_ISP_DEMOSAIC_BYPASS); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_FILT_MODE, RKISP1_CIF_ISP_FLT_ENA); - rkisp1_awb_meas_enable(params, NULL, false); + params->ops->awb_meas_enable(params, NULL, false); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_EXP_CTRL, @@ -1286,7 +1285,7 @@ void rkisp1_params_disable(struct rkisp1_params *params) rkisp1_ctk_enable(params, false); rkisp1_param_clear_bits(params, RKISP1_CIF_C_PROC_CTRL, RKISP1_CIF_C_PROC_CTR_ENABLE); - rkisp1_hst_enable(params, NULL, false); + params->ops->hst_enable(params, NULL, false); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_AFM_CTRL, RKISP1_CIF_ISP_AFM_ENA); rkisp1_ie_enable(params, false); @@ -1294,6 +1293,18 @@ void rkisp1_params_disable(struct rkisp1_params *params) RKISP1_CIF_ISP_DPF_MODE_EN); } +static const struct rkisp1_params_ops rkisp1_params_ops = { + .lsc_matrix_config = rkisp1_lsc_matrix_config, + .goc_config = rkisp1_goc_config, + .awb_meas_config = rkisp1_awb_meas_config, + .awb_meas_enable = rkisp1_awb_meas_enable, + .awb_gain_config = rkisp1_awb_gain_config, + .aec_config = rkisp1_aec_config, + .hst_config = rkisp1_hst_config, + .hst_enable = rkisp1_hst_enable, + .afm_config = rkisp1_afm_config, +}; + static int rkisp1_params_enum_fmt_meta_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { @@ -1459,6 +1470,8 @@ static void rkisp1_init_params(struct rkisp1_params *params) V4L2_META_FMT_RK_ISP1_PARAMS; params->vdev_fmt.fmt.meta.buffersize = sizeof(struct rkisp1_params_cfg); + + params->ops = &rkisp1_params_ops; } int rkisp1_params_register(struct rkisp1_device *rkisp1) -- cgit v1.2.3 From 962fb14068c182c8e813465884677bea85968405 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 23 Jul 2021 09:32:17 +0200 Subject: media: rockchip: rkisp1: make some isp-stats functions variable The isp block evolved in subsequent socs, so some functions will behave differently on newer variants. Therefore make it possible to override the needed stats functions. Signed-off-by: Heiko Stuebner Reviewed-by: Dafna Hirschfeld Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-common.h | 11 +++++++++++ drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c | 14 +++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index d91565ec23d0..d8fa3f1a5a85 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -232,6 +232,16 @@ struct rkisp1_capture { } pix; }; +struct rkisp1_stats; +struct rkisp1_stats_ops { + void (*get_awb_meas)(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf); + void (*get_aec_meas)(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf); + void (*get_hst_meas)(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf); +}; + /* * struct rkisp1_stats - ISP Statistics device * @@ -244,6 +254,7 @@ struct rkisp1_capture { struct rkisp1_stats { struct rkisp1_vdev_node vnode; struct rkisp1_device *rkisp1; + const struct rkisp1_stats_ops *ops; spinlock_t lock; /* locks the buffers list 'stats' */ struct list_head stat; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c index e88bdd612d71..a61fba28f529 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c @@ -286,6 +286,12 @@ static void rkisp1_stats_get_bls_meas(struct rkisp1_stats *stats, } } +static const struct rkisp1_stats_ops rkisp1_stats_ops = { + .get_awb_meas = rkisp1_stats_get_awb_meas, + .get_aec_meas = rkisp1_stats_get_aec_meas, + .get_hst_meas = rkisp1_stats_get_hst_meas, +}; + static void rkisp1_stats_send_measurement(struct rkisp1_stats *stats, u32 isp_ris) { @@ -307,18 +313,18 @@ rkisp1_stats_send_measurement(struct rkisp1_stats *stats, u32 isp_ris) cur_stat_buf = (struct rkisp1_stat_buffer *) vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0); if (isp_ris & RKISP1_CIF_ISP_AWB_DONE) - rkisp1_stats_get_awb_meas(stats, cur_stat_buf); + stats->ops->get_awb_meas(stats, cur_stat_buf); if (isp_ris & RKISP1_CIF_ISP_AFM_FIN) rkisp1_stats_get_afc_meas(stats, cur_stat_buf); if (isp_ris & RKISP1_CIF_ISP_EXP_END) { - rkisp1_stats_get_aec_meas(stats, cur_stat_buf); + stats->ops->get_aec_meas(stats, cur_stat_buf); rkisp1_stats_get_bls_meas(stats, cur_stat_buf); } if (isp_ris & RKISP1_CIF_ISP_HIST_MEASURE_RDY) - rkisp1_stats_get_hst_meas(stats, cur_stat_buf); + stats->ops->get_hst_meas(stats, cur_stat_buf); vb2_set_plane_payload(&cur_buf->vb.vb2_buf, 0, sizeof(struct rkisp1_stat_buffer)); @@ -352,6 +358,8 @@ static void rkisp1_init_stats(struct rkisp1_stats *stats) V4L2_META_FMT_RK_ISP1_STAT_3A; stats->vdev_fmt.fmt.meta.buffersize = sizeof(struct rkisp1_stat_buffer); + + stats->ops = &rkisp1_stats_ops; } int rkisp1_stats_register(struct rkisp1_device *rkisp1) -- cgit v1.2.3 From dce8ccb2322e1d2f54c695c7283ab40608247ef2 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 23 Jul 2021 09:32:18 +0200 Subject: media: rockchip: rkisp1: add prefixes for v10 specific parts The rkisp1 evolved over soc generations and the rk3326/px30 introduced the so called v12 - probably meaning v1.2. In a first step adapt the affected v10 parts to give them a matching suffix to enable us to add v12 variants later on. Signed-off-by: Heiko Stuebner Reviewed-by: Dafna Hirschfeld Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/rockchip/rkisp1/rkisp1-params.c | 180 +++++++------- .../media/platform/rockchip/rkisp1/rkisp1-regs.h | 263 ++++++++++----------- .../media/platform/rockchip/rkisp1/rkisp1-stats.c | 32 +-- 3 files changed, 237 insertions(+), 238 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 4cdd1448c750..9807ce1d4c7d 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -185,8 +185,8 @@ static void rkisp1_bls_config(struct rkisp1_params *params, /* ISP LS correction interface function */ static void -rkisp1_lsc_matrix_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_lsc_config *pconfig) +rkisp1_lsc_matrix_config_v10(struct rkisp1_params *params, + const struct rkisp1_cif_isp_lsc_config *pconfig) { unsigned int isp_lsc_status, sram_addr, isp_lsc_table_sel, i, j, data; @@ -212,39 +212,39 @@ rkisp1_lsc_matrix_config(struct rkisp1_params *params, * DWORDs (2nd value of last DWORD unused) */ for (j = 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX - 1; j += 2) { - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->r_data_tbl[i][j], - pconfig->r_data_tbl[i][j + 1]); + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->r_data_tbl[i][j], + pconfig->r_data_tbl[i][j + 1]); rkisp1_write(params->rkisp1, data, RKISP1_CIF_ISP_LSC_R_TABLE_DATA); - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gr_data_tbl[i][j], - pconfig->gr_data_tbl[i][j + 1]); + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j], + pconfig->gr_data_tbl[i][j + 1]); rkisp1_write(params->rkisp1, data, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gb_data_tbl[i][j], - pconfig->gb_data_tbl[i][j + 1]); + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j], + pconfig->gb_data_tbl[i][j + 1]); rkisp1_write(params->rkisp1, data, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->b_data_tbl[i][j], - pconfig->b_data_tbl[i][j + 1]); + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j], + pconfig->b_data_tbl[i][j + 1]); rkisp1_write(params->rkisp1, data, RKISP1_CIF_ISP_LSC_B_TABLE_DATA); } - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->r_data_tbl[i][j], 0); + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->r_data_tbl[i][j], 0); rkisp1_write(params->rkisp1, data, RKISP1_CIF_ISP_LSC_R_TABLE_DATA); - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gr_data_tbl[i][j], 0); + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j], 0); rkisp1_write(params->rkisp1, data, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gb_data_tbl[i][j], 0); + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j], 0); rkisp1_write(params->rkisp1, data, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->b_data_tbl[i][j], 0); + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j], 0); rkisp1_write(params->rkisp1, data, RKISP1_CIF_ISP_LSC_B_TABLE_DATA); } @@ -382,18 +382,18 @@ static void rkisp1_sdg_config(struct rkisp1_params *params, } /* ISP GAMMA correction interface function */ -static void rkisp1_goc_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_goc_config *arg) +static void rkisp1_goc_config_v10(struct rkisp1_params *params, + const struct rkisp1_cif_isp_goc_config *arg) { unsigned int i; rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); - rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE); + rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V10); for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10; i++) rkisp1_write(params->rkisp1, arg->gamma_y[i], - RKISP1_CIF_ISP_GAMMA_OUT_Y_0 + i * 4); + RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 + i * 4); } /* ISP Cross Talk */ @@ -433,8 +433,8 @@ static void rkisp1_ctk_enable(struct rkisp1_params *params, bool en) } /* ISP White Balance Mode */ -static void rkisp1_awb_meas_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_awb_meas_config *arg) +static void rkisp1_awb_meas_config_v10(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_meas_config *arg) { u32 reg_val = 0; /* based on the mode,configure the awb module */ @@ -442,43 +442,43 @@ static void rkisp1_awb_meas_config(struct rkisp1_params *params, /* Reference Cb and Cr */ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) | - arg->awb_ref_cb, RKISP1_CIF_ISP_AWB_REF); + arg->awb_ref_cb, RKISP1_CIF_ISP_AWB_REF_V10); /* Yc Threshold */ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_MAX_Y_SET(arg->max_y) | RKISP1_CIF_ISP_AWB_MIN_Y_SET(arg->min_y) | RKISP1_CIF_ISP_AWB_MAX_CS_SET(arg->max_csum) | - arg->min_c, RKISP1_CIF_ISP_AWB_THRESH); + arg->min_c, RKISP1_CIF_ISP_AWB_THRESH_V10); } - reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP); + reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10); if (arg->enable_ymax_cmp) reg_val |= RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; else reg_val &= ~RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; - rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP); + rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V10); /* window offset */ rkisp1_write(params->rkisp1, - arg->awb_wnd.v_offs, RKISP1_CIF_ISP_AWB_WND_V_OFFS); + arg->awb_wnd.v_offs, RKISP1_CIF_ISP_AWB_WND_V_OFFS_V10); rkisp1_write(params->rkisp1, - arg->awb_wnd.h_offs, RKISP1_CIF_ISP_AWB_WND_H_OFFS); + arg->awb_wnd.h_offs, RKISP1_CIF_ISP_AWB_WND_H_OFFS_V10); /* AWB window size */ rkisp1_write(params->rkisp1, - arg->awb_wnd.v_size, RKISP1_CIF_ISP_AWB_WND_V_SIZE); + arg->awb_wnd.v_size, RKISP1_CIF_ISP_AWB_WND_V_SIZE_V10); rkisp1_write(params->rkisp1, - arg->awb_wnd.h_size, RKISP1_CIF_ISP_AWB_WND_H_SIZE); + arg->awb_wnd.h_size, RKISP1_CIF_ISP_AWB_WND_H_SIZE_V10); /* Number of frames */ rkisp1_write(params->rkisp1, - arg->frames, RKISP1_CIF_ISP_AWB_FRAMES); + arg->frames, RKISP1_CIF_ISP_AWB_FRAMES_V10); } static void -rkisp1_awb_meas_enable(struct rkisp1_params *params, - const struct rkisp1_cif_isp_awb_meas_config *arg, - bool en) +rkisp1_awb_meas_enable_v10(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_meas_config *arg, + bool en) { - u32 reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP); + u32 reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10); /* switch off */ reg_val &= RKISP1_CIF_ISP_AWB_MODE_MASK_NONE; @@ -489,34 +489,34 @@ rkisp1_awb_meas_enable(struct rkisp1_params *params, else reg_val |= RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN; - rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP); + rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V10); /* Measurements require AWB block be active. */ rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); } else { rkisp1_write(params->rkisp1, - reg_val, RKISP1_CIF_ISP_AWB_PROP); + reg_val, RKISP1_CIF_ISP_AWB_PROP_V10); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); } } static void -rkisp1_awb_gain_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_awb_gain_config *arg) +rkisp1_awb_gain_config_v10(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_gain_config *arg) { rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) | - arg->gain_green_b, RKISP1_CIF_ISP_AWB_GAIN_G); + arg->gain_green_b, RKISP1_CIF_ISP_AWB_GAIN_G_V10); rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) | - arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB); + arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB_V10); } -static void rkisp1_aec_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_aec_config *arg) +static void rkisp1_aec_config_v10(struct rkisp1_params *params, + const struct rkisp1_cif_isp_aec_config *arg) { unsigned int block_hsize, block_vsize; u32 exp_ctrl; @@ -531,21 +531,21 @@ static void rkisp1_aec_config(struct rkisp1_params *params, rkisp1_write(params->rkisp1, exp_ctrl, RKISP1_CIF_ISP_EXP_CTRL); rkisp1_write(params->rkisp1, - arg->meas_window.h_offs, RKISP1_CIF_ISP_EXP_H_OFFSET); + arg->meas_window.h_offs, RKISP1_CIF_ISP_EXP_H_OFFSET_V10); rkisp1_write(params->rkisp1, - arg->meas_window.v_offs, RKISP1_CIF_ISP_EXP_V_OFFSET); + arg->meas_window.v_offs, RKISP1_CIF_ISP_EXP_V_OFFSET_V10); block_hsize = arg->meas_window.h_size / - RKISP1_CIF_ISP_EXP_COLUMN_NUM - 1; + RKISP1_CIF_ISP_EXP_COLUMN_NUM_V10 - 1; block_vsize = arg->meas_window.v_size / - RKISP1_CIF_ISP_EXP_ROW_NUM - 1; + RKISP1_CIF_ISP_EXP_ROW_NUM_V10 - 1; rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_EXP_H_SIZE_SET(block_hsize), - RKISP1_CIF_ISP_EXP_H_SIZE); + RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(block_hsize), + RKISP1_CIF_ISP_EXP_H_SIZE_V10); rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_EXP_V_SIZE_SET(block_vsize), - RKISP1_CIF_ISP_EXP_V_SIZE); + RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(block_vsize), + RKISP1_CIF_ISP_EXP_V_SIZE_V10); } static void rkisp1_cproc_config(struct rkisp1_params *params, @@ -578,73 +578,73 @@ static void rkisp1_cproc_config(struct rkisp1_params *params, } } -static void rkisp1_hst_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_hst_config *arg) +static void rkisp1_hst_config_v10(struct rkisp1_params *params, + const struct rkisp1_cif_isp_hst_config *arg) { unsigned int block_hsize, block_vsize; static const u32 hist_weight_regs[] = { - RKISP1_CIF_ISP_HIST_WEIGHT_00TO30, - RKISP1_CIF_ISP_HIST_WEIGHT_40TO21, - RKISP1_CIF_ISP_HIST_WEIGHT_31TO12, - RKISP1_CIF_ISP_HIST_WEIGHT_22TO03, - RKISP1_CIF_ISP_HIST_WEIGHT_13TO43, - RKISP1_CIF_ISP_HIST_WEIGHT_04TO34, + RKISP1_CIF_ISP_HIST_WEIGHT_00TO30_V10, + RKISP1_CIF_ISP_HIST_WEIGHT_40TO21_V10, + RKISP1_CIF_ISP_HIST_WEIGHT_31TO12_V10, + RKISP1_CIF_ISP_HIST_WEIGHT_22TO03_V10, + RKISP1_CIF_ISP_HIST_WEIGHT_13TO43_V10, + RKISP1_CIF_ISP_HIST_WEIGHT_04TO34_V10, }; const u8 *weight; unsigned int i; u32 hist_prop; /* avoid to override the old enable value */ - hist_prop = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_HIST_PROP); - hist_prop &= RKISP1_CIF_ISP_HIST_PROP_MODE_MASK; - hist_prop |= RKISP1_CIF_ISP_HIST_PREDIV_SET(arg->histogram_predivider); - rkisp1_write(params->rkisp1, hist_prop, RKISP1_CIF_ISP_HIST_PROP); + hist_prop = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_HIST_PROP_V10); + hist_prop &= RKISP1_CIF_ISP_HIST_PROP_MODE_MASK_V10; + hist_prop |= RKISP1_CIF_ISP_HIST_PREDIV_SET_V10(arg->histogram_predivider); + rkisp1_write(params->rkisp1, hist_prop, RKISP1_CIF_ISP_HIST_PROP_V10); rkisp1_write(params->rkisp1, arg->meas_window.h_offs, - RKISP1_CIF_ISP_HIST_H_OFFS); + RKISP1_CIF_ISP_HIST_H_OFFS_V10); rkisp1_write(params->rkisp1, arg->meas_window.v_offs, - RKISP1_CIF_ISP_HIST_V_OFFS); + RKISP1_CIF_ISP_HIST_V_OFFS_V10); block_hsize = arg->meas_window.h_size / - RKISP1_CIF_ISP_HIST_COLUMN_NUM - 1; - block_vsize = arg->meas_window.v_size / RKISP1_CIF_ISP_HIST_ROW_NUM - 1; + RKISP1_CIF_ISP_HIST_COLUMN_NUM_V10 - 1; + block_vsize = arg->meas_window.v_size / RKISP1_CIF_ISP_HIST_ROW_NUM_V10 - 1; - rkisp1_write(params->rkisp1, block_hsize, RKISP1_CIF_ISP_HIST_H_SIZE); - rkisp1_write(params->rkisp1, block_vsize, RKISP1_CIF_ISP_HIST_V_SIZE); + rkisp1_write(params->rkisp1, block_hsize, RKISP1_CIF_ISP_HIST_H_SIZE_V10); + rkisp1_write(params->rkisp1, block_vsize, RKISP1_CIF_ISP_HIST_V_SIZE_V10); weight = arg->hist_weight; for (i = 0; i < ARRAY_SIZE(hist_weight_regs); ++i, weight += 4) rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_HIST_WEIGHT_SET(weight[0], + RKISP1_CIF_ISP_HIST_WEIGHT_SET_V10(weight[0], weight[1], weight[2], weight[3]), hist_weight_regs[i]); - rkisp1_write(params->rkisp1, weight[0] & 0x1F, RKISP1_CIF_ISP_HIST_WEIGHT_44); + rkisp1_write(params->rkisp1, weight[0] & 0x1F, RKISP1_CIF_ISP_HIST_WEIGHT_44_V10); } static void -rkisp1_hst_enable(struct rkisp1_params *params, - const struct rkisp1_cif_isp_hst_config *arg, bool en) +rkisp1_hst_enable_v10(struct rkisp1_params *params, + const struct rkisp1_cif_isp_hst_config *arg, bool en) { if (en) { u32 hist_prop = rkisp1_read(params->rkisp1, - RKISP1_CIF_ISP_HIST_PROP); + RKISP1_CIF_ISP_HIST_PROP_V10); - hist_prop &= ~RKISP1_CIF_ISP_HIST_PROP_MODE_MASK; + hist_prop &= ~RKISP1_CIF_ISP_HIST_PROP_MODE_MASK_V10; hist_prop |= arg->mode; - rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP, + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP_V10, hist_prop); } else { - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_HIST_PROP, - RKISP1_CIF_ISP_HIST_PROP_MODE_MASK); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_HIST_PROP_V10, + RKISP1_CIF_ISP_HIST_PROP_MODE_MASK_V10); } } -static void rkisp1_afm_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_afc_config *arg) +static void rkisp1_afm_config_v10(struct rkisp1_params *params, + const struct rkisp1_cif_isp_afc_config *arg) { size_t num_of_win = min_t(size_t, ARRAY_SIZE(arg->afm_win), arg->num_afm_win); @@ -1231,7 +1231,7 @@ static void rkisp1_params_config_parameter(struct rkisp1_params *params) memset(hst.hist_weight, 0x01, sizeof(hst.hist_weight)); params->ops->hst_config(params, &hst); - rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP, + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP_V10, rkisp1_hst_params_default_config.mode); /* set the range */ @@ -1293,16 +1293,16 @@ void rkisp1_params_disable(struct rkisp1_params *params) RKISP1_CIF_ISP_DPF_MODE_EN); } -static const struct rkisp1_params_ops rkisp1_params_ops = { - .lsc_matrix_config = rkisp1_lsc_matrix_config, - .goc_config = rkisp1_goc_config, - .awb_meas_config = rkisp1_awb_meas_config, - .awb_meas_enable = rkisp1_awb_meas_enable, - .awb_gain_config = rkisp1_awb_gain_config, - .aec_config = rkisp1_aec_config, - .hst_config = rkisp1_hst_config, - .hst_enable = rkisp1_hst_enable, - .afm_config = rkisp1_afm_config, +static const struct rkisp1_params_ops rkisp1_v10_params_ops = { + .lsc_matrix_config = rkisp1_lsc_matrix_config_v10, + .goc_config = rkisp1_goc_config_v10, + .awb_meas_config = rkisp1_awb_meas_config_v10, + .awb_meas_enable = rkisp1_awb_meas_enable_v10, + .awb_gain_config = rkisp1_awb_gain_config_v10, + .aec_config = rkisp1_aec_config_v10, + .hst_config = rkisp1_hst_config_v10, + .hst_enable = rkisp1_hst_enable_v10, + .afm_config = rkisp1_afm_config_v10, }; static int rkisp1_params_enum_fmt_meta_out(struct file *file, void *priv, @@ -1471,7 +1471,7 @@ static void rkisp1_init_params(struct rkisp1_params *params) params->vdev_fmt.fmt.meta.buffersize = sizeof(struct rkisp1_params_cfg); - params->ops = &rkisp1_params_ops; + params->ops = &rkisp1_v10_params_ops; } int rkisp1_params_register(struct rkisp1_device *rkisp1) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index fa33080f51db..e3944c04102f 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -346,26 +346,26 @@ #define RKISP1_CIF_SUPER_IMP_CTRL_TRANSP_DIS BIT(2) /* ISP HISTOGRAM CALCULATION : ISP_HIST_PROP */ -#define RKISP1_CIF_ISP_HIST_PROP_MODE_DIS (0 << 0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_RGB BIT(0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_RED (2 << 0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_GREEN (3 << 0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_BLUE (4 << 0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_LUM (5 << 0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_MASK 0x7 -#define RKISP1_CIF_ISP_HIST_PREDIV_SET(x) (((x) & 0x7F) << 3) -#define RKISP1_CIF_ISP_HIST_WEIGHT_SET(v0, v1, v2, v3) \ +#define RKISP1_CIF_ISP_HIST_PROP_MODE_DIS_V10 (0 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_RGB_V10 BIT(0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_RED_V10 (2 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_GREEN_V10 (3 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_BLUE_V10 (4 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_LUM_V10 (5 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_MASK_V10 0x7 +#define RKISP1_CIF_ISP_HIST_PREDIV_SET_V10(x) (((x) & 0x7F) << 3) +#define RKISP1_CIF_ISP_HIST_WEIGHT_SET_V10(v0, v1, v2, v3) \ (((v0) & 0x1F) | (((v1) & 0x1F) << 8) |\ (((v2) & 0x1F) << 16) | \ (((v3) & 0x1F) << 24)) -#define RKISP1_CIF_ISP_HIST_WINDOW_OFFSET_RESERVED 0xFFFFF000 -#define RKISP1_CIF_ISP_HIST_WINDOW_SIZE_RESERVED 0xFFFFF800 -#define RKISP1_CIF_ISP_HIST_WEIGHT_RESERVED 0xE0E0E0E0 -#define RKISP1_CIF_ISP_MAX_HIST_PREDIVIDER 0x0000007F -#define RKISP1_CIF_ISP_HIST_ROW_NUM 5 -#define RKISP1_CIF_ISP_HIST_COLUMN_NUM 5 -#define RKISP1_CIF_ISP_HIST_GET_BIN(x) ((x) & 0x000FFFFF) +#define RKISP1_CIF_ISP_HIST_WINDOW_OFFSET_RESERVED_V10 0xFFFFF000 +#define RKISP1_CIF_ISP_HIST_WINDOW_SIZE_RESERVED_V10 0xFFFFF800 +#define RKISP1_CIF_ISP_HIST_WEIGHT_RESERVED_V10 0xE0E0E0E0 +#define RKISP1_CIF_ISP_MAX_HIST_PREDIVIDER_V10 0x0000007F +#define RKISP1_CIF_ISP_HIST_ROW_NUM_V10 5 +#define RKISP1_CIF_ISP_HIST_COLUMN_NUM_V10 5 +#define RKISP1_CIF_ISP_HIST_GET_BIN_V10(x) ((x) & 0x000FFFFF) /* AUTO FOCUS MEASUREMENT: ISP_AFM_CTRL */ #define RKISP1_ISP_AFM_CTRL_ENABLE BIT(0) @@ -442,41 +442,41 @@ #define RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1 BIT(31) /* ISP_EXP_H_SIZE */ -#define RKISP1_CIF_ISP_EXP_H_SIZE_SET(x) ((x) & 0x7FF) -#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK 0x000007FF +#define RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(x) ((x) & 0x7FF) +#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK_V10 0x000007FF /* ISP_EXP_V_SIZE : vertical size must be a multiple of 2). */ -#define RKISP1_CIF_ISP_EXP_V_SIZE_SET(x) ((x) & 0x7FE) +#define RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(x) ((x) & 0x7FE) /* ISP_EXP_H_OFFSET */ -#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET(x) ((x) & 0x1FFF) -#define RKISP1_CIF_ISP_EXP_MAX_HOFFS 2424 +#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V10(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_EXP_MAX_HOFFS_V10 2424 /* ISP_EXP_V_OFFSET */ -#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET(x) ((x) & 0x1FFF) -#define RKISP1_CIF_ISP_EXP_MAX_VOFFS 1806 - -#define RKISP1_CIF_ISP_EXP_ROW_NUM 5 -#define RKISP1_CIF_ISP_EXP_COLUMN_NUM 5 -#define RKISP1_CIF_ISP_EXP_NUM_LUMA_REGS \ - (RKISP1_CIF_ISP_EXP_ROW_NUM * RKISP1_CIF_ISP_EXP_COLUMN_NUM) -#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE 516 -#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE 35 -#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE 390 -#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE 28 -#define RKISP1_CIF_ISP_EXP_MAX_HSIZE \ - (RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE * RKISP1_CIF_ISP_EXP_COLUMN_NUM + 1) -#define RKISP1_CIF_ISP_EXP_MIN_HSIZE \ - (RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE * RKISP1_CIF_ISP_EXP_COLUMN_NUM + 1) -#define RKISP1_CIF_ISP_EXP_MAX_VSIZE \ - (RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE * RKISP1_CIF_ISP_EXP_ROW_NUM + 1) -#define RKISP1_CIF_ISP_EXP_MIN_VSIZE \ - (RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE * RKISP1_CIF_ISP_EXP_ROW_NUM + 1) +#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V10(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_EXP_MAX_VOFFS_V10 1806 + +#define RKISP1_CIF_ISP_EXP_ROW_NUM_V10 5 +#define RKISP1_CIF_ISP_EXP_COLUMN_NUM_V10 5 +#define RKISP1_CIF_ISP_EXP_NUM_LUMA_REGS_V10 \ + (RKISP1_CIF_ISP_EXP_ROW_NUM_V10 * RKISP1_CIF_ISP_EXP_COLUMN_NUM_V10) +#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE_V10 516 +#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE_V10 35 +#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE_V10 390 +#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE_V10 28 +#define RKISP1_CIF_ISP_EXP_MAX_HSIZE_V10 \ + (RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE_V10 * RKISP1_CIF_ISP_EXP_COLUMN_NUM_V10 + 1) +#define RKISP1_CIF_ISP_EXP_MIN_HSIZE_V10 \ + (RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE_V10 * RKISP1_CIF_ISP_EXP_COLUMN_NUM_V10 + 1) +#define RKISP1_CIF_ISP_EXP_MAX_VSIZE_V10 \ + (RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE_V10 * RKISP1_CIF_ISP_EXP_ROW_NUM_V10 + 1) +#define RKISP1_CIF_ISP_EXP_MIN_VSIZE_V10 \ + (RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE_V10 * RKISP1_CIF_ISP_EXP_ROW_NUM_V10 + 1) /* LSC: ISP_LSC_CTRL */ #define RKISP1_CIF_ISP_LSC_CTRL_ENA BIT(0) #define RKISP1_CIF_ISP_LSC_SECT_SIZE_RESERVED 0xFC00FC00 -#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED 0xF000F000 -#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED 0xF000F000 -#define RKISP1_CIF_ISP_LSC_TABLE_DATA(v0, v1) \ +#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED_V10 0xF000F000 +#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED_V10 0xF000F000 +#define RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(v0, v1) \ (((v0) & 0xFFF) | (((v1) & 0xFFF) << 12)) #define RKISP1_CIF_ISP_LSC_SECT_SIZE(v0, v1) \ (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) @@ -667,18 +667,18 @@ #define RKISP1_CIF_ISP_GAMMA_B_Y14 (RKISP1_CIF_ISP_BASE + 0x000000E4) #define RKISP1_CIF_ISP_GAMMA_B_Y15 (RKISP1_CIF_ISP_BASE + 0x000000E8) #define RKISP1_CIF_ISP_GAMMA_B_Y16 (RKISP1_CIF_ISP_BASE + 0x000000EC) -#define RKISP1_CIF_ISP_AWB_PROP (RKISP1_CIF_ISP_BASE + 0x00000110) -#define RKISP1_CIF_ISP_AWB_WND_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000114) -#define RKISP1_CIF_ISP_AWB_WND_V_OFFS (RKISP1_CIF_ISP_BASE + 0x00000118) -#define RKISP1_CIF_ISP_AWB_WND_H_SIZE (RKISP1_CIF_ISP_BASE + 0x0000011C) -#define RKISP1_CIF_ISP_AWB_WND_V_SIZE (RKISP1_CIF_ISP_BASE + 0x00000120) -#define RKISP1_CIF_ISP_AWB_FRAMES (RKISP1_CIF_ISP_BASE + 0x00000124) -#define RKISP1_CIF_ISP_AWB_REF (RKISP1_CIF_ISP_BASE + 0x00000128) -#define RKISP1_CIF_ISP_AWB_THRESH (RKISP1_CIF_ISP_BASE + 0x0000012C) -#define RKISP1_CIF_ISP_AWB_GAIN_G (RKISP1_CIF_ISP_BASE + 0x00000138) -#define RKISP1_CIF_ISP_AWB_GAIN_RB (RKISP1_CIF_ISP_BASE + 0x0000013C) -#define RKISP1_CIF_ISP_AWB_WHITE_CNT (RKISP1_CIF_ISP_BASE + 0x00000140) -#define RKISP1_CIF_ISP_AWB_MEAN (RKISP1_CIF_ISP_BASE + 0x00000144) +#define RKISP1_CIF_ISP_AWB_PROP_V10 (RKISP1_CIF_ISP_BASE + 0x00000110) +#define RKISP1_CIF_ISP_AWB_WND_H_OFFS_V10 (RKISP1_CIF_ISP_BASE + 0x00000114) +#define RKISP1_CIF_ISP_AWB_WND_V_OFFS_V10 (RKISP1_CIF_ISP_BASE + 0x00000118) +#define RKISP1_CIF_ISP_AWB_WND_H_SIZE_V10 (RKISP1_CIF_ISP_BASE + 0x0000011C) +#define RKISP1_CIF_ISP_AWB_WND_V_SIZE_V10 (RKISP1_CIF_ISP_BASE + 0x00000120) +#define RKISP1_CIF_ISP_AWB_FRAMES_V10 (RKISP1_CIF_ISP_BASE + 0x00000124) +#define RKISP1_CIF_ISP_AWB_REF_V10 (RKISP1_CIF_ISP_BASE + 0x00000128) +#define RKISP1_CIF_ISP_AWB_THRESH_V10 (RKISP1_CIF_ISP_BASE + 0x0000012C) +#define RKISP1_CIF_ISP_AWB_GAIN_G_V10 (RKISP1_CIF_ISP_BASE + 0x00000138) +#define RKISP1_CIF_ISP_AWB_GAIN_RB_V10 (RKISP1_CIF_ISP_BASE + 0x0000013C) +#define RKISP1_CIF_ISP_AWB_WHITE_CNT_V10 (RKISP1_CIF_ISP_BASE + 0x00000140) +#define RKISP1_CIF_ISP_AWB_MEAN_V10 (RKISP1_CIF_ISP_BASE + 0x00000144) #define RKISP1_CIF_ISP_CC_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x00000170) #define RKISP1_CIF_ISP_CC_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x00000174) #define RKISP1_CIF_ISP_CC_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x00000178) @@ -712,24 +712,24 @@ #define RKISP1_CIF_ISP_CT_COEFF_6 (RKISP1_CIF_ISP_BASE + 0x000001E8) #define RKISP1_CIF_ISP_CT_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x000001EC) #define RKISP1_CIF_ISP_CT_COEFF_8 (RKISP1_CIF_ISP_BASE + 0x000001F0) -#define RKISP1_CIF_ISP_GAMMA_OUT_MODE (RKISP1_CIF_ISP_BASE + 0x000001F4) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_0 (RKISP1_CIF_ISP_BASE + 0x000001F8) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_1 (RKISP1_CIF_ISP_BASE + 0x000001FC) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_2 (RKISP1_CIF_ISP_BASE + 0x00000200) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_3 (RKISP1_CIF_ISP_BASE + 0x00000204) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_4 (RKISP1_CIF_ISP_BASE + 0x00000208) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_5 (RKISP1_CIF_ISP_BASE + 0x0000020C) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_6 (RKISP1_CIF_ISP_BASE + 0x00000210) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_7 (RKISP1_CIF_ISP_BASE + 0x00000214) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_8 (RKISP1_CIF_ISP_BASE + 0x00000218) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_9 (RKISP1_CIF_ISP_BASE + 0x0000021C) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_10 (RKISP1_CIF_ISP_BASE + 0x00000220) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_11 (RKISP1_CIF_ISP_BASE + 0x00000224) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_12 (RKISP1_CIF_ISP_BASE + 0x00000228) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_13 (RKISP1_CIF_ISP_BASE + 0x0000022C) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_14 (RKISP1_CIF_ISP_BASE + 0x00000230) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_15 (RKISP1_CIF_ISP_BASE + 0x00000234) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_16 (RKISP1_CIF_ISP_BASE + 0x00000238) +#define RKISP1_CIF_ISP_GAMMA_OUT_MODE_V10 (RKISP1_CIF_ISP_BASE + 0x000001F4) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 (RKISP1_CIF_ISP_BASE + 0x000001F8) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_1_V10 (RKISP1_CIF_ISP_BASE + 0x000001FC) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_2_V10 (RKISP1_CIF_ISP_BASE + 0x00000200) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_3_V10 (RKISP1_CIF_ISP_BASE + 0x00000204) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_4_V10 (RKISP1_CIF_ISP_BASE + 0x00000208) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_5_V10 (RKISP1_CIF_ISP_BASE + 0x0000020C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_6_V10 (RKISP1_CIF_ISP_BASE + 0x00000210) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_7_V10 (RKISP1_CIF_ISP_BASE + 0x00000214) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_8_V10 (RKISP1_CIF_ISP_BASE + 0x00000218) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_9_V10 (RKISP1_CIF_ISP_BASE + 0x0000021C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_10_V10 (RKISP1_CIF_ISP_BASE + 0x00000220) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_11_V10 (RKISP1_CIF_ISP_BASE + 0x00000224) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_12_V10 (RKISP1_CIF_ISP_BASE + 0x00000228) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_13_V10 (RKISP1_CIF_ISP_BASE + 0x0000022C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_14_V10 (RKISP1_CIF_ISP_BASE + 0x00000230) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_15_V10 (RKISP1_CIF_ISP_BASE + 0x00000234) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_16_V10 (RKISP1_CIF_ISP_BASE + 0x00000238) #define RKISP1_CIF_ISP_ERR (RKISP1_CIF_ISP_BASE + 0x0000023C) #define RKISP1_CIF_ISP_ERR_CLR (RKISP1_CIF_ISP_BASE + 0x00000240) #define RKISP1_CIF_ISP_FRAME_COUNT (RKISP1_CIF_ISP_BASE + 0x00000244) @@ -1005,36 +1005,35 @@ #define RKISP1_CIF_ISP_IS_H_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x0000002C) #define RKISP1_CIF_ISP_IS_V_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000030) -#define RKISP1_CIF_ISP_HIST_BASE 0x00002400 - -#define RKISP1_CIF_ISP_HIST_PROP (RKISP1_CIF_ISP_HIST_BASE + 0x00000000) -#define RKISP1_CIF_ISP_HIST_H_OFFS (RKISP1_CIF_ISP_HIST_BASE + 0x00000004) -#define RKISP1_CIF_ISP_HIST_V_OFFS (RKISP1_CIF_ISP_HIST_BASE + 0x00000008) -#define RKISP1_CIF_ISP_HIST_H_SIZE (RKISP1_CIF_ISP_HIST_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_HIST_V_SIZE (RKISP1_CIF_ISP_HIST_BASE + 0x00000010) -#define RKISP1_CIF_ISP_HIST_BIN_0 (RKISP1_CIF_ISP_HIST_BASE + 0x00000014) -#define RKISP1_CIF_ISP_HIST_BIN_1 (RKISP1_CIF_ISP_HIST_BASE + 0x00000018) -#define RKISP1_CIF_ISP_HIST_BIN_2 (RKISP1_CIF_ISP_HIST_BASE + 0x0000001C) -#define RKISP1_CIF_ISP_HIST_BIN_3 (RKISP1_CIF_ISP_HIST_BASE + 0x00000020) -#define RKISP1_CIF_ISP_HIST_BIN_4 (RKISP1_CIF_ISP_HIST_BASE + 0x00000024) -#define RKISP1_CIF_ISP_HIST_BIN_5 (RKISP1_CIF_ISP_HIST_BASE + 0x00000028) -#define RKISP1_CIF_ISP_HIST_BIN_6 (RKISP1_CIF_ISP_HIST_BASE + 0x0000002C) -#define RKISP1_CIF_ISP_HIST_BIN_7 (RKISP1_CIF_ISP_HIST_BASE + 0x00000030) -#define RKISP1_CIF_ISP_HIST_BIN_8 (RKISP1_CIF_ISP_HIST_BASE + 0x00000034) -#define RKISP1_CIF_ISP_HIST_BIN_9 (RKISP1_CIF_ISP_HIST_BASE + 0x00000038) -#define RKISP1_CIF_ISP_HIST_BIN_10 (RKISP1_CIF_ISP_HIST_BASE + 0x0000003C) -#define RKISP1_CIF_ISP_HIST_BIN_11 (RKISP1_CIF_ISP_HIST_BASE + 0x00000040) -#define RKISP1_CIF_ISP_HIST_BIN_12 (RKISP1_CIF_ISP_HIST_BASE + 0x00000044) -#define RKISP1_CIF_ISP_HIST_BIN_13 (RKISP1_CIF_ISP_HIST_BASE + 0x00000048) -#define RKISP1_CIF_ISP_HIST_BIN_14 (RKISP1_CIF_ISP_HIST_BASE + 0x0000004C) -#define RKISP1_CIF_ISP_HIST_BIN_15 (RKISP1_CIF_ISP_HIST_BASE + 0x00000050) -#define RKISP1_CIF_ISP_HIST_WEIGHT_00TO30 (RKISP1_CIF_ISP_HIST_BASE + 0x00000054) -#define RKISP1_CIF_ISP_HIST_WEIGHT_40TO21 (RKISP1_CIF_ISP_HIST_BASE + 0x00000058) -#define RKISP1_CIF_ISP_HIST_WEIGHT_31TO12 (RKISP1_CIF_ISP_HIST_BASE + 0x0000005C) -#define RKISP1_CIF_ISP_HIST_WEIGHT_22TO03 (RKISP1_CIF_ISP_HIST_BASE + 0x00000060) -#define RKISP1_CIF_ISP_HIST_WEIGHT_13TO43 (RKISP1_CIF_ISP_HIST_BASE + 0x00000064) -#define RKISP1_CIF_ISP_HIST_WEIGHT_04TO34 (RKISP1_CIF_ISP_HIST_BASE + 0x00000068) -#define RKISP1_CIF_ISP_HIST_WEIGHT_44 (RKISP1_CIF_ISP_HIST_BASE + 0x0000006C) +#define RKISP1_CIF_ISP_HIST_BASE_V10 0x00002400 +#define RKISP1_CIF_ISP_HIST_PROP_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000000) +#define RKISP1_CIF_ISP_HIST_H_OFFS_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000004) +#define RKISP1_CIF_ISP_HIST_V_OFFS_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000008) +#define RKISP1_CIF_ISP_HIST_H_SIZE_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000000C) +#define RKISP1_CIF_ISP_HIST_V_SIZE_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000010) +#define RKISP1_CIF_ISP_HIST_BIN_0_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000014) +#define RKISP1_CIF_ISP_HIST_BIN_1_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000018) +#define RKISP1_CIF_ISP_HIST_BIN_2_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000001C) +#define RKISP1_CIF_ISP_HIST_BIN_3_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000020) +#define RKISP1_CIF_ISP_HIST_BIN_4_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000024) +#define RKISP1_CIF_ISP_HIST_BIN_5_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000028) +#define RKISP1_CIF_ISP_HIST_BIN_6_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000002C) +#define RKISP1_CIF_ISP_HIST_BIN_7_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000030) +#define RKISP1_CIF_ISP_HIST_BIN_8_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000034) +#define RKISP1_CIF_ISP_HIST_BIN_9_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000038) +#define RKISP1_CIF_ISP_HIST_BIN_10_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000003C) +#define RKISP1_CIF_ISP_HIST_BIN_11_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000040) +#define RKISP1_CIF_ISP_HIST_BIN_12_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000044) +#define RKISP1_CIF_ISP_HIST_BIN_13_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000048) +#define RKISP1_CIF_ISP_HIST_BIN_14_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000004C) +#define RKISP1_CIF_ISP_HIST_BIN_15_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000050) +#define RKISP1_CIF_ISP_HIST_WEIGHT_00TO30_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000054) +#define RKISP1_CIF_ISP_HIST_WEIGHT_40TO21_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000058) +#define RKISP1_CIF_ISP_HIST_WEIGHT_31TO12_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000005C) +#define RKISP1_CIF_ISP_HIST_WEIGHT_22TO03_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000060) +#define RKISP1_CIF_ISP_HIST_WEIGHT_13TO43_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000064) +#define RKISP1_CIF_ISP_HIST_WEIGHT_04TO34_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000068) +#define RKISP1_CIF_ISP_HIST_WEIGHT_44_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000006C) #define RKISP1_CIF_ISP_FILT_BASE 0x00002500 #define RKISP1_CIF_ISP_FILT_MODE (RKISP1_CIF_ISP_FILT_BASE + 0x00000000) @@ -1060,35 +1059,35 @@ #define RKISP1_CIF_ISP_EXP_BASE 0x00002600 #define RKISP1_CIF_ISP_EXP_CTRL (RKISP1_CIF_ISP_EXP_BASE + 0x00000000) -#define RKISP1_CIF_ISP_EXP_H_OFFSET (RKISP1_CIF_ISP_EXP_BASE + 0x00000004) -#define RKISP1_CIF_ISP_EXP_V_OFFSET (RKISP1_CIF_ISP_EXP_BASE + 0x00000008) -#define RKISP1_CIF_ISP_EXP_H_SIZE (RKISP1_CIF_ISP_EXP_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_EXP_V_SIZE (RKISP1_CIF_ISP_EXP_BASE + 0x00000010) -#define RKISP1_CIF_ISP_EXP_MEAN_00 (RKISP1_CIF_ISP_EXP_BASE + 0x00000014) -#define RKISP1_CIF_ISP_EXP_MEAN_10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000018) -#define RKISP1_CIF_ISP_EXP_MEAN_20 (RKISP1_CIF_ISP_EXP_BASE + 0x0000001c) -#define RKISP1_CIF_ISP_EXP_MEAN_30 (RKISP1_CIF_ISP_EXP_BASE + 0x00000020) -#define RKISP1_CIF_ISP_EXP_MEAN_40 (RKISP1_CIF_ISP_EXP_BASE + 0x00000024) -#define RKISP1_CIF_ISP_EXP_MEAN_01 (RKISP1_CIF_ISP_EXP_BASE + 0x00000028) -#define RKISP1_CIF_ISP_EXP_MEAN_11 (RKISP1_CIF_ISP_EXP_BASE + 0x0000002c) -#define RKISP1_CIF_ISP_EXP_MEAN_21 (RKISP1_CIF_ISP_EXP_BASE + 0x00000030) -#define RKISP1_CIF_ISP_EXP_MEAN_31 (RKISP1_CIF_ISP_EXP_BASE + 0x00000034) -#define RKISP1_CIF_ISP_EXP_MEAN_41 (RKISP1_CIF_ISP_EXP_BASE + 0x00000038) -#define RKISP1_CIF_ISP_EXP_MEAN_02 (RKISP1_CIF_ISP_EXP_BASE + 0x0000003c) -#define RKISP1_CIF_ISP_EXP_MEAN_12 (RKISP1_CIF_ISP_EXP_BASE + 0x00000040) -#define RKISP1_CIF_ISP_EXP_MEAN_22 (RKISP1_CIF_ISP_EXP_BASE + 0x00000044) -#define RKISP1_CIF_ISP_EXP_MEAN_32 (RKISP1_CIF_ISP_EXP_BASE + 0x00000048) -#define RKISP1_CIF_ISP_EXP_MEAN_42 (RKISP1_CIF_ISP_EXP_BASE + 0x0000004c) -#define RKISP1_CIF_ISP_EXP_MEAN_03 (RKISP1_CIF_ISP_EXP_BASE + 0x00000050) -#define RKISP1_CIF_ISP_EXP_MEAN_13 (RKISP1_CIF_ISP_EXP_BASE + 0x00000054) -#define RKISP1_CIF_ISP_EXP_MEAN_23 (RKISP1_CIF_ISP_EXP_BASE + 0x00000058) -#define RKISP1_CIF_ISP_EXP_MEAN_33 (RKISP1_CIF_ISP_EXP_BASE + 0x0000005c) -#define RKISP1_CIF_ISP_EXP_MEAN_43 (RKISP1_CIF_ISP_EXP_BASE + 0x00000060) -#define RKISP1_CIF_ISP_EXP_MEAN_04 (RKISP1_CIF_ISP_EXP_BASE + 0x00000064) -#define RKISP1_CIF_ISP_EXP_MEAN_14 (RKISP1_CIF_ISP_EXP_BASE + 0x00000068) -#define RKISP1_CIF_ISP_EXP_MEAN_24 (RKISP1_CIF_ISP_EXP_BASE + 0x0000006c) -#define RKISP1_CIF_ISP_EXP_MEAN_34 (RKISP1_CIF_ISP_EXP_BASE + 0x00000070) -#define RKISP1_CIF_ISP_EXP_MEAN_44 (RKISP1_CIF_ISP_EXP_BASE + 0x00000074) +#define RKISP1_CIF_ISP_EXP_H_OFFSET_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000004) +#define RKISP1_CIF_ISP_EXP_V_OFFSET_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000008) +#define RKISP1_CIF_ISP_EXP_H_SIZE_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_EXP_V_SIZE_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000010) +#define RKISP1_CIF_ISP_EXP_MEAN_00_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000014) +#define RKISP1_CIF_ISP_EXP_MEAN_10_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000018) +#define RKISP1_CIF_ISP_EXP_MEAN_20_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x0000001c) +#define RKISP1_CIF_ISP_EXP_MEAN_30_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000020) +#define RKISP1_CIF_ISP_EXP_MEAN_40_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000024) +#define RKISP1_CIF_ISP_EXP_MEAN_01_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000028) +#define RKISP1_CIF_ISP_EXP_MEAN_11_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x0000002c) +#define RKISP1_CIF_ISP_EXP_MEAN_21_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000030) +#define RKISP1_CIF_ISP_EXP_MEAN_31_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000034) +#define RKISP1_CIF_ISP_EXP_MEAN_41_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000038) +#define RKISP1_CIF_ISP_EXP_MEAN_02_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x0000003c) +#define RKISP1_CIF_ISP_EXP_MEAN_12_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000040) +#define RKISP1_CIF_ISP_EXP_MEAN_22_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000044) +#define RKISP1_CIF_ISP_EXP_MEAN_32_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000048) +#define RKISP1_CIF_ISP_EXP_MEAN_42_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x0000004c) +#define RKISP1_CIF_ISP_EXP_MEAN_03_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000050) +#define RKISP1_CIF_ISP_EXP_MEAN_13_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000054) +#define RKISP1_CIF_ISP_EXP_MEAN_23_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000058) +#define RKISP1_CIF_ISP_EXP_MEAN_33_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x0000005c) +#define RKISP1_CIF_ISP_EXP_MEAN_43_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000060) +#define RKISP1_CIF_ISP_EXP_MEAN_04_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000064) +#define RKISP1_CIF_ISP_EXP_MEAN_14_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000068) +#define RKISP1_CIF_ISP_EXP_MEAN_24_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x0000006c) +#define RKISP1_CIF_ISP_EXP_MEAN_34_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000070) +#define RKISP1_CIF_ISP_EXP_MEAN_44_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000074) #define RKISP1_CIF_ISP_BLS_BASE 0x00002700 #define RKISP1_CIF_ISP_BLS_CTRL (RKISP1_CIF_ISP_BLS_BASE + 0x00000000) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c index a61fba28f529..d4e72027d61f 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c @@ -174,18 +174,18 @@ rkisp1_stats_init_vb2_queue(struct vb2_queue *q, struct rkisp1_stats *stats) return vb2_queue_init(q); } -static void rkisp1_stats_get_awb_meas(struct rkisp1_stats *stats, - struct rkisp1_stat_buffer *pbuf) +static void rkisp1_stats_get_awb_meas_v10(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) { /* Protect against concurrent access from ISR? */ struct rkisp1_device *rkisp1 = stats->rkisp1; u32 reg_val; pbuf->meas_type |= RKISP1_CIF_ISP_STAT_AWB; - reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB_WHITE_CNT); + reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB_WHITE_CNT_V10); pbuf->params.awb.awb_mean[0].cnt = RKISP1_CIF_ISP_AWB_GET_PIXEL_CNT(reg_val); - reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB_MEAN); + reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB_MEAN_V10); pbuf->params.awb.awb_mean[0].mean_cr_or_r = RKISP1_CIF_ISP_AWB_GET_MEAN_CR_R(reg_val); @@ -195,8 +195,8 @@ static void rkisp1_stats_get_awb_meas(struct rkisp1_stats *stats, RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(reg_val); } -static void rkisp1_stats_get_aec_meas(struct rkisp1_stats *stats, - struct rkisp1_stat_buffer *pbuf) +static void rkisp1_stats_get_aec_meas_v10(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) { struct rkisp1_device *rkisp1 = stats->rkisp1; unsigned int i; @@ -205,7 +205,7 @@ static void rkisp1_stats_get_aec_meas(struct rkisp1_stats *stats, for (i = 0; i < RKISP1_CIF_ISP_AE_MEAN_MAX_V10; i++) pbuf->params.ae.exp_mean[i] = (u8)rkisp1_read(rkisp1, - RKISP1_CIF_ISP_EXP_MEAN_00 + i * 4); + RKISP1_CIF_ISP_EXP_MEAN_00_V10 + i * 4); } static void rkisp1_stats_get_afc_meas(struct rkisp1_stats *stats, @@ -225,17 +225,17 @@ static void rkisp1_stats_get_afc_meas(struct rkisp1_stats *stats, af->window[2].lum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_LUM_C); } -static void rkisp1_stats_get_hst_meas(struct rkisp1_stats *stats, - struct rkisp1_stat_buffer *pbuf) +static void rkisp1_stats_get_hst_meas_v10(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) { struct rkisp1_device *rkisp1 = stats->rkisp1; unsigned int i; pbuf->meas_type |= RKISP1_CIF_ISP_STAT_HIST; for (i = 0; i < RKISP1_CIF_ISP_HIST_BIN_N_MAX_V10; i++) { - u32 reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_HIST_BIN_0 + i * 4); + u32 reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_HIST_BIN_0_V10 + i * 4); - pbuf->params.hist.hist_bins[i] = RKISP1_CIF_ISP_HIST_GET_BIN(reg_val); + pbuf->params.hist.hist_bins[i] = RKISP1_CIF_ISP_HIST_GET_BIN_V10(reg_val); } } @@ -286,10 +286,10 @@ static void rkisp1_stats_get_bls_meas(struct rkisp1_stats *stats, } } -static const struct rkisp1_stats_ops rkisp1_stats_ops = { - .get_awb_meas = rkisp1_stats_get_awb_meas, - .get_aec_meas = rkisp1_stats_get_aec_meas, - .get_hst_meas = rkisp1_stats_get_hst_meas, +static const struct rkisp1_stats_ops rkisp1_v10_stats_ops = { + .get_awb_meas = rkisp1_stats_get_awb_meas_v10, + .get_aec_meas = rkisp1_stats_get_aec_meas_v10, + .get_hst_meas = rkisp1_stats_get_hst_meas_v10, }; static void @@ -359,7 +359,7 @@ static void rkisp1_init_stats(struct rkisp1_stats *stats) stats->vdev_fmt.fmt.meta.buffersize = sizeof(struct rkisp1_stat_buffer); - stats->ops = &rkisp1_stats_ops; + stats->ops = &rkisp1_v10_stats_ops; } int rkisp1_stats_register(struct rkisp1_device *rkisp1) -- cgit v1.2.3 From cd42f8023f16e8c5614be529972e9ffbb309db85 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 23 Jul 2021 09:32:19 +0200 Subject: media: rockchip: rkisp1: add support for v12 isp variants The rkisp1 evolved over soc generations and the rk3326/px30 introduced the so called v12 - probably meaning v1.2. Add the new register definitions. Signed-off-by: Heiko Stuebner Reviewed-by: Dafna Hirschfeld Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/drivers/rkisp1.rst | 43 +++ .../media/platform/rockchip/rkisp1/rkisp1-isp.c | 13 + .../media/platform/rockchip/rkisp1/rkisp1-params.c | 338 ++++++++++++++++++++- .../media/platform/rockchip/rkisp1/rkisp1-regs.h | 143 +++++++++ .../media/platform/rockchip/rkisp1/rkisp1-stats.c | 73 ++++- 5 files changed, 608 insertions(+), 2 deletions(-) create mode 100644 Documentation/driver-api/media/drivers/rkisp1.rst diff --git a/Documentation/driver-api/media/drivers/rkisp1.rst b/Documentation/driver-api/media/drivers/rkisp1.rst new file mode 100644 index 000000000000..ea336958a3af --- /dev/null +++ b/Documentation/driver-api/media/drivers/rkisp1.rst @@ -0,0 +1,43 @@ +.. SPDX-License-Identifier: GPL-2.0 + +The Rockchip Image Signal Processor Driver (rkisp1) +=================================================== + +Versions and their differences +------------------------------ + +The rkisp1 block underwent some changes between SoC implementations. +The vendor designates them as: + +- V10: used at least in rk3288 and rk3399 +- V11: declared in the original vendor code, but not used +- V12: used at least in rk3326 and px30 +- V13: used at least in rk1808 +- V20: used in rk3568 and beyond + +Right now the kernel supports rkisp1 implementations based +on V10 and V12 variants. V11 does not seem to be actually used +and V13 will need some more additions but isn't researched yet, +especially as it seems to be limited to the rk1808 which hasn't +reached much market spread. + +V20 on the other hand will probably be used in future SoCs and +has seen really big changes in the vendor kernel, so will need +quite a bit of research. + +Changes from V10 to V12 +----------------------- + +- V12 supports a new CSI-host implementation but can still + also use the same implementation from V10 +- The module for lens shading correction got changed + from 12bit to 13bit width +- The AWB and AEC modules got replaced to support finer + grained data collection + +Changes from V12 to V13 +----------------------- + +The list for V13 is incomplete and needs further investigation. + +- V13 does not support the old CSI-host implementation anymore diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index d7c422cb3276..2a35bf24e54e 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -414,6 +414,10 @@ static int rkisp1_config_mipi(struct rkisp1_device *rkisp1) rkisp1_write(rkisp1, mipi_ctrl, RKISP1_CIF_MIPI_CTRL); + /* V12 could also use a newer csi2-host, but we don't want that yet */ + if (rkisp1->media_dev.hw_revision == RKISP1_V12) + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_CSI0_CTRL0); + /* Configure Data Type and Virtual Channel */ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_DATA_SEL_DT(sink_fmt->mipi_dt) | @@ -533,6 +537,15 @@ static void rkisp1_config_clk(struct rkisp1_device *rkisp1) RKISP1_CIF_ICCL_DCROP_CLK; rkisp1_write(rkisp1, val, RKISP1_CIF_ICCL); + + /* ensure sp and mp can run at the same time in V12 */ + if (rkisp1->media_dev.hw_revision == RKISP1_V12) { + val = RKISP1_CIF_CLK_CTRL_MI_Y12 | RKISP1_CIF_CLK_CTRL_MI_SP | + RKISP1_CIF_CLK_CTRL_MI_RAW0 | RKISP1_CIF_CLK_CTRL_MI_RAW1 | + RKISP1_CIF_CLK_CTRL_MI_READ | RKISP1_CIF_CLK_CTRL_MI_RAWRD | + RKISP1_CIF_CLK_CTRL_CP | RKISP1_CIF_CLK_CTRL_IE; + rkisp1_write(rkisp1, val, RKISP1_CIF_VI_ISP_CLK_CTRL_V12); + } } static void rkisp1_isp_start(struct rkisp1_device *rkisp1) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 9807ce1d4c7d..8f62f09e635f 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -255,6 +255,78 @@ rkisp1_lsc_matrix_config_v10(struct rkisp1_params *params, RKISP1_CIF_ISP_LSC_TABLE_SEL); } +static void +rkisp1_lsc_matrix_config_v12(struct rkisp1_params *params, + const struct rkisp1_cif_isp_lsc_config *pconfig) +{ + unsigned int isp_lsc_status, sram_addr, isp_lsc_table_sel, i, j, data; + + isp_lsc_status = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_STATUS); + + /* RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */ + sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? + RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : + RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; + rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR); + rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR); + rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR); + rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR); + + /* program data tables (table size is 9 * 17 = 153) */ + for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) { + /* + * 17 sectors with 2 values in one DWORD = 9 + * DWORDs (2nd value of last DWORD unused) + */ + for (j = 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX - 1; j += 2) { + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( + pconfig->r_data_tbl[i][j], + pconfig->r_data_tbl[i][j + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( + pconfig->gr_data_tbl[i][j], + pconfig->gr_data_tbl[i][j + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( + pconfig->gb_data_tbl[i][j], + pconfig->gb_data_tbl[i][j + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( + pconfig->b_data_tbl[i][j], + pconfig->b_data_tbl[i][j + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + } + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->r_data_tbl[i][j], 0); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gr_data_tbl[i][j], 0); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gb_data_tbl[i][j], 0); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->b_data_tbl[i][j], 0); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + } + isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? + RKISP1_CIF_ISP_LSC_TABLE_0 : + RKISP1_CIF_ISP_LSC_TABLE_1; + rkisp1_write(params->rkisp1, isp_lsc_table_sel, + RKISP1_CIF_ISP_LSC_TABLE_SEL); +} + static void rkisp1_lsc_config(struct rkisp1_params *params, const struct rkisp1_cif_isp_lsc_config *arg) { @@ -396,6 +468,25 @@ static void rkisp1_goc_config_v10(struct rkisp1_params *params, RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 + i * 4); } +static void rkisp1_goc_config_v12(struct rkisp1_params *params, + const struct rkisp1_cif_isp_goc_config *arg) +{ + unsigned int i; + u32 value; + + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); + rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V12); + + for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V12 / 2; i++) { + value = RKISP1_CIF_ISP_GAMMA_VALUE_V12( + arg->gamma_y[2 * i + 1], + arg->gamma_y[2 * i]); + rkisp1_write(params->rkisp1, value, + RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V12 + i * 4); + } +} + /* ISP Cross Talk */ static void rkisp1_ctk_config(struct rkisp1_params *params, const struct rkisp1_cif_isp_ctk_config *arg) @@ -473,6 +564,45 @@ static void rkisp1_awb_meas_config_v10(struct rkisp1_params *params, arg->frames, RKISP1_CIF_ISP_AWB_FRAMES_V10); } +static void rkisp1_awb_meas_config_v12(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_meas_config *arg) +{ + u32 reg_val = 0; + /* based on the mode,configure the awb module */ + if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_YCBCR) { + /* Reference Cb and Cr */ + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) | + arg->awb_ref_cb, RKISP1_CIF_ISP_AWB_REF_V12); + /* Yc Threshold */ + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AWB_MAX_Y_SET(arg->max_y) | + RKISP1_CIF_ISP_AWB_MIN_Y_SET(arg->min_y) | + RKISP1_CIF_ISP_AWB_MAX_CS_SET(arg->max_csum) | + arg->min_c, RKISP1_CIF_ISP_AWB_THRESH_V12); + } + + reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12); + if (arg->enable_ymax_cmp) + reg_val |= RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; + else + reg_val &= ~RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; + reg_val &= ~RKISP1_CIF_ISP_AWB_SET_FRAMES_MASK_V12; + reg_val |= RKISP1_CIF_ISP_AWB_SET_FRAMES_V12(arg->frames); + rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V12); + + /* window offset */ + rkisp1_write(params->rkisp1, + arg->awb_wnd.v_offs << 16 | + arg->awb_wnd.h_offs, + RKISP1_CIF_ISP_AWB_OFFS_V12); + /* AWB window size */ + rkisp1_write(params->rkisp1, + arg->awb_wnd.v_size << 16 | + arg->awb_wnd.h_size, + RKISP1_CIF_ISP_AWB_SIZE_V12); +} + static void rkisp1_awb_meas_enable_v10(struct rkisp1_params *params, const struct rkisp1_cif_isp_awb_meas_config *arg, @@ -502,6 +632,35 @@ rkisp1_awb_meas_enable_v10(struct rkisp1_params *params, } } +static void +rkisp1_awb_meas_enable_v12(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_meas_config *arg, + bool en) +{ + u32 reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12); + + /* switch off */ + reg_val &= RKISP1_CIF_ISP_AWB_MODE_MASK_NONE; + + if (en) { + if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_RGB) + reg_val |= RKISP1_CIF_ISP_AWB_MODE_RGB_EN; + else + reg_val |= RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN; + + rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V12); + + /* Measurements require AWB block be active. */ + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); + } else { + rkisp1_write(params->rkisp1, + reg_val, RKISP1_CIF_ISP_AWB_PROP_V12); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); + } +} + static void rkisp1_awb_gain_config_v10(struct rkisp1_params *params, const struct rkisp1_cif_isp_awb_gain_config *arg) @@ -515,6 +674,19 @@ rkisp1_awb_gain_config_v10(struct rkisp1_params *params, arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB_V10); } +static void +rkisp1_awb_gain_config_v12(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_gain_config *arg) +{ + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) | + arg->gain_green_b, RKISP1_CIF_ISP_AWB_GAIN_G_V12); + + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) | + arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB_V12); +} + static void rkisp1_aec_config_v10(struct rkisp1_params *params, const struct rkisp1_cif_isp_aec_config *arg) { @@ -548,6 +720,38 @@ static void rkisp1_aec_config_v10(struct rkisp1_params *params, RKISP1_CIF_ISP_EXP_V_SIZE_V10); } +static void rkisp1_aec_config_v12(struct rkisp1_params *params, + const struct rkisp1_cif_isp_aec_config *arg) +{ + u32 exp_ctrl; + u32 block_hsize, block_vsize; + u32 wnd_num_idx = 1; + const u32 ae_wnd_num[] = { 5, 9, 15, 15 }; + + /* avoid to override the old enable value */ + exp_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL); + exp_ctrl &= RKISP1_CIF_ISP_EXP_ENA; + if (arg->autostop) + exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP; + if (arg->mode == RKISP1_CIF_ISP_EXP_MEASURING_MODE_1) + exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1; + exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_WNDNUM_SET_V12(wnd_num_idx); + rkisp1_write(params->rkisp1, exp_ctrl, RKISP1_CIF_ISP_EXP_CTRL); + + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V12(arg->meas_window.v_offs) | + RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V12(arg->meas_window.h_offs), + RKISP1_CIF_ISP_EXP_OFFS_V12); + + block_hsize = arg->meas_window.h_size / ae_wnd_num[wnd_num_idx] - 1; + block_vsize = arg->meas_window.v_size / ae_wnd_num[wnd_num_idx] - 1; + + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_EXP_V_SIZE_SET_V12(block_vsize) | + RKISP1_CIF_ISP_EXP_H_SIZE_SET_V12(block_hsize), + RKISP1_CIF_ISP_EXP_SIZE_V12); +} + static void rkisp1_cproc_config(struct rkisp1_params *params, const struct rkisp1_cif_isp_cproc_config *arg) { @@ -625,6 +829,64 @@ static void rkisp1_hst_config_v10(struct rkisp1_params *params, rkisp1_write(params->rkisp1, weight[0] & 0x1F, RKISP1_CIF_ISP_HIST_WEIGHT_44_V10); } +static void rkisp1_hst_config_v12(struct rkisp1_params *params, + const struct rkisp1_cif_isp_hst_config *arg) +{ + unsigned int i, j; + u32 block_hsize, block_vsize; + u32 wnd_num_idx, hist_weight_num, hist_ctrl, value; + u8 weight15x15[RKISP1_CIF_ISP_HIST_WEIGHT_REG_SIZE_V12]; + const u32 hist_wnd_num[] = { 5, 9, 15, 15 }; + + /* now we just support 9x9 window */ + wnd_num_idx = 1; + memset(weight15x15, 0x00, sizeof(weight15x15)); + /* avoid to override the old enable value */ + hist_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_HIST_CTRL_V12); + hist_ctrl &= RKISP1_CIF_ISP_HIST_CTRL_MODE_MASK_V12 | + RKISP1_CIF_ISP_HIST_CTRL_EN_MASK_V12; + hist_ctrl = hist_ctrl | + RKISP1_CIF_ISP_HIST_CTRL_INTRSEL_SET_V12(1) | + RKISP1_CIF_ISP_HIST_CTRL_DATASEL_SET_V12(0) | + RKISP1_CIF_ISP_HIST_CTRL_WATERLINE_SET_V12(0) | + RKISP1_CIF_ISP_HIST_CTRL_AUTOSTOP_SET_V12(0) | + RKISP1_CIF_ISP_HIST_CTRL_WNDNUM_SET_V12(1) | + RKISP1_CIF_ISP_HIST_CTRL_STEPSIZE_SET_V12(arg->histogram_predivider); + rkisp1_write(params->rkisp1, hist_ctrl, RKISP1_CIF_ISP_HIST_CTRL_V12); + + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_HIST_OFFS_SET_V12(arg->meas_window.h_offs, + arg->meas_window.v_offs), + RKISP1_CIF_ISP_HIST_OFFS_V12); + + block_hsize = arg->meas_window.h_size / hist_wnd_num[wnd_num_idx] - 1; + block_vsize = arg->meas_window.v_size / hist_wnd_num[wnd_num_idx] - 1; + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_HIST_SIZE_SET_V12(block_hsize, block_vsize), + RKISP1_CIF_ISP_HIST_SIZE_V12); + + for (i = 0; i < hist_wnd_num[wnd_num_idx]; i++) { + for (j = 0; j < hist_wnd_num[wnd_num_idx]; j++) { + weight15x15[i * RKISP1_CIF_ISP_HIST_ROW_NUM_V12 + j] = + arg->hist_weight[i * hist_wnd_num[wnd_num_idx] + j]; + } + } + + hist_weight_num = RKISP1_CIF_ISP_HIST_WEIGHT_REG_SIZE_V12; + for (i = 0; i < (hist_weight_num / 4); i++) { + value = RKISP1_CIF_ISP_HIST_WEIGHT_SET_V12( + weight15x15[4 * i + 0], + weight15x15[4 * i + 1], + weight15x15[4 * i + 2], + weight15x15[4 * i + 3]); + rkisp1_write(params->rkisp1, value, + RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i); + } + value = RKISP1_CIF_ISP_HIST_WEIGHT_SET_V12(weight15x15[4 * i + 0], 0, 0, 0); + rkisp1_write(params->rkisp1, value, + RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i); +} + static void rkisp1_hst_enable_v10(struct rkisp1_params *params, const struct rkisp1_cif_isp_hst_config *arg, bool en) @@ -643,6 +905,26 @@ rkisp1_hst_enable_v10(struct rkisp1_params *params, } } +static void +rkisp1_hst_enable_v12(struct rkisp1_params *params, + const struct rkisp1_cif_isp_hst_config *arg, bool en) +{ + if (en) { + u32 hist_ctrl = rkisp1_read(params->rkisp1, + RKISP1_CIF_ISP_HIST_CTRL_V12); + + hist_ctrl &= ~RKISP1_CIF_ISP_HIST_CTRL_MODE_MASK_V12; + hist_ctrl |= RKISP1_CIF_ISP_HIST_CTRL_MODE_SET_V12(arg->mode); + hist_ctrl |= RKISP1_CIF_ISP_HIST_CTRL_EN_SET_V12(1); + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_CTRL_V12, + hist_ctrl); + } else { + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_HIST_CTRL_V12, + RKISP1_CIF_ISP_HIST_CTRL_MODE_MASK_V12 | + RKISP1_CIF_ISP_HIST_CTRL_EN_MASK_V12); + } +} + static void rkisp1_afm_config_v10(struct rkisp1_params *params, const struct rkisp1_cif_isp_afc_config *arg) { @@ -674,6 +956,45 @@ static void rkisp1_afm_config_v10(struct rkisp1_params *params, rkisp1_write(params->rkisp1, afm_ctrl, RKISP1_CIF_ISP_AFM_CTRL); } +static void rkisp1_afm_config_v12(struct rkisp1_params *params, + const struct rkisp1_cif_isp_afc_config *arg) +{ + size_t num_of_win = min_t(size_t, ARRAY_SIZE(arg->afm_win), + arg->num_afm_win); + u32 afm_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AFM_CTRL); + u32 lum_var_shift, afm_var_shift; + unsigned int i; + + /* Switch off to configure. */ + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_AFM_CTRL, + RKISP1_CIF_ISP_AFM_ENA); + + for (i = 0; i < num_of_win; i++) { + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_offs) | + RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs), + RKISP1_CIF_ISP_AFM_LT_A + i * 8); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_size + + arg->afm_win[i].h_offs) | + RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_size + + arg->afm_win[i].v_offs), + RKISP1_CIF_ISP_AFM_RB_A + i * 8); + } + rkisp1_write(params->rkisp1, arg->thres, RKISP1_CIF_ISP_AFM_THRES); + + lum_var_shift = RKISP1_CIF_ISP_AFM_GET_LUM_SHIFT_a_V12(arg->var_shift); + afm_var_shift = RKISP1_CIF_ISP_AFM_GET_AFM_SHIFT_a_V12(arg->var_shift); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AFM_SET_SHIFT_a_V12(lum_var_shift, afm_var_shift) | + RKISP1_CIF_ISP_AFM_SET_SHIFT_b_V12(lum_var_shift, afm_var_shift) | + RKISP1_CIF_ISP_AFM_SET_SHIFT_c_V12(lum_var_shift, afm_var_shift), + RKISP1_CIF_ISP_AFM_VAR_SHIFT); + + /* restore afm status */ + rkisp1_write(params->rkisp1, afm_ctrl, RKISP1_CIF_ISP_AFM_CTRL); +} + static void rkisp1_ie_config(struct rkisp1_params *params, const struct rkisp1_cif_isp_ie_config *arg) { @@ -1305,6 +1626,18 @@ static const struct rkisp1_params_ops rkisp1_v10_params_ops = { .afm_config = rkisp1_afm_config_v10, }; +static struct rkisp1_params_ops rkisp1_v12_params_ops = { + .lsc_matrix_config = rkisp1_lsc_matrix_config_v12, + .goc_config = rkisp1_goc_config_v12, + .awb_meas_config = rkisp1_awb_meas_config_v12, + .awb_meas_enable = rkisp1_awb_meas_enable_v12, + .awb_gain_config = rkisp1_awb_gain_config_v12, + .aec_config = rkisp1_aec_config_v12, + .hst_config = rkisp1_hst_config_v12, + .hst_enable = rkisp1_hst_enable_v12, + .afm_config = rkisp1_afm_config_v12, +}; + static int rkisp1_params_enum_fmt_meta_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { @@ -1471,7 +1804,10 @@ static void rkisp1_init_params(struct rkisp1_params *params) params->vdev_fmt.fmt.meta.buffersize = sizeof(struct rkisp1_params_cfg); - params->ops = &rkisp1_v10_params_ops; + if (params->rkisp1->media_dev.hw_revision == RKISP1_V12) + params->ops = &rkisp1_v12_params_ops; + else + params->ops = &rkisp1_v10_params_ops; } int rkisp1_params_register(struct rkisp1_device *rkisp1) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index e3944c04102f..d326214c7e07 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -212,6 +212,35 @@ /* CCL */ #define RKISP1_CIF_CCL_CIF_CLK_DIS BIT(2) +/* VI_ISP_CLK_CTRL */ +#define RKISP1_CIF_CLK_CTRL_ISP_RAW BIT(0) +#define RKISP1_CIF_CLK_CTRL_ISP_RGB BIT(1) +#define RKISP1_CIF_CLK_CTRL_ISP_YUV BIT(2) +#define RKISP1_CIF_CLK_CTRL_ISP_3A BIT(3) +#define RKISP1_CIF_CLK_CTRL_MIPI_RAW BIT(4) +#define RKISP1_CIF_CLK_CTRL_ISP_IE BIT(5) +#define RKISP1_CIF_CLK_CTRL_RSZ_RAM BIT(6) +#define RKISP1_CIF_CLK_CTRL_JPEG_RAM BIT(7) +#define RKISP1_CIF_CLK_CTRL_ACLK_ISP BIT(8) +#define RKISP1_CIF_CLK_CTRL_MI_IDC BIT(9) +#define RKISP1_CIF_CLK_CTRL_MI_MP BIT(10) +#define RKISP1_CIF_CLK_CTRL_MI_JPEG BIT(11) +#define RKISP1_CIF_CLK_CTRL_MI_DP BIT(12) +#define RKISP1_CIF_CLK_CTRL_MI_Y12 BIT(13) +#define RKISP1_CIF_CLK_CTRL_MI_SP BIT(14) +#define RKISP1_CIF_CLK_CTRL_MI_RAW0 BIT(15) +#define RKISP1_CIF_CLK_CTRL_MI_RAW1 BIT(16) +#define RKISP1_CIF_CLK_CTRL_MI_READ BIT(17) +#define RKISP1_CIF_CLK_CTRL_MI_RAWRD BIT(18) +#define RKISP1_CIF_CLK_CTRL_CP BIT(19) +#define RKISP1_CIF_CLK_CTRL_IE BIT(20) +#define RKISP1_CIF_CLK_CTRL_SI BIT(21) +#define RKISP1_CIF_CLK_CTRL_RSZM BIT(22) +#define RKISP1_CIF_CLK_CTRL_DPMUX BIT(23) +#define RKISP1_CIF_CLK_CTRL_JPEG BIT(24) +#define RKISP1_CIF_CLK_CTRL_RSZS BIT(25) +#define RKISP1_CIF_CLK_CTRL_MIPI BIT(26) +#define RKISP1_CIF_CLK_CTRL_MARVINMI BIT(27) /* ICCL */ #define RKISP1_CIF_ICCL_ISP_CLK BIT(0) #define RKISP1_CIF_ICCL_CP_CLK BIT(1) @@ -367,6 +396,38 @@ #define RKISP1_CIF_ISP_HIST_COLUMN_NUM_V10 5 #define RKISP1_CIF_ISP_HIST_GET_BIN_V10(x) ((x) & 0x000FFFFF) +/* ISP HISTOGRAM CALCULATION : CIF_ISP_HIST */ +#define RKISP1_CIF_ISP_HIST_CTRL_EN_SET_V12(x) (((x) & 0x01) << 0) +#define RKISP1_CIF_ISP_HIST_CTRL_EN_MASK_V12 RKISP1_CIF_ISP_HIST_CTRL_EN_SET_V12(0x01) +#define RKISP1_CIF_ISP_HIST_CTRL_STEPSIZE_SET_V12(x) (((x) & 0x7F) << 1) +#define RKISP1_CIF_ISP_HIST_CTRL_MODE_SET_V12(x) (((x) & 0x07) << 8) +#define RKISP1_CIF_ISP_HIST_CTRL_MODE_MASK_V12 RKISP1_CIF_ISP_HIST_CTRL_MODE_SET_V12(0x07) +#define RKISP1_CIF_ISP_HIST_CTRL_AUTOSTOP_SET_V12(x) (((x) & 0x01) << 11) +#define RKISP1_CIF_ISP_HIST_CTRL_WATERLINE_SET_V12(x) (((x) & 0xFFF) << 12) +#define RKISP1_CIF_ISP_HIST_CTRL_DATASEL_SET_V12(x) (((x) & 0x07) << 24) +#define RKISP1_CIF_ISP_HIST_CTRL_INTRSEL_SET_V12(x) (((x) & 0x01) << 27) +#define RKISP1_CIF_ISP_HIST_CTRL_WNDNUM_SET_V12(x) (((x) & 0x03) << 28) +#define RKISP1_CIF_ISP_HIST_CTRL_DBGEN_SET_V12(x) (((x) & 0x01) << 30) +#define RKISP1_CIF_ISP_HIST_ROW_NUM_V12 15 +#define RKISP1_CIF_ISP_HIST_COLUMN_NUM_V12 15 +#define RKISP1_CIF_ISP_HIST_WEIGHT_REG_SIZE_V12 \ + (RKISP1_CIF_ISP_HIST_ROW_NUM_V12 * RKISP1_CIF_ISP_HIST_COLUMN_NUM_V12) + +#define RKISP1_CIF_ISP_HIST_WEIGHT_SET_V12(v0, v1, v2, v3) \ + (((v0) & 0x3F) | (((v1) & 0x3F) << 8) |\ + (((v2) & 0x3F) << 16) |\ + (((v3) & 0x3F) << 24)) + +#define RKISP1_CIF_ISP_HIST_OFFS_SET_V12(v0, v1) \ + (((v0) & 0x1FFF) | (((v1) & 0x1FFF) << 16)) +#define RKISP1_CIF_ISP_HIST_SIZE_SET_V12(v0, v1) \ + (((v0) & 0x7FF) | (((v1) & 0x7FF) << 16)) + +#define RKISP1_CIF_ISP_HIST_GET_BIN0_V12(x) \ + ((x) & 0xFFFF) +#define RKISP1_CIF_ISP_HIST_GET_BIN1_V12(x) \ + (((x) >> 16) & 0xFFFF) + /* AUTO FOCUS MEASUREMENT: ISP_AFM_CTRL */ #define RKISP1_ISP_AFM_CTRL_ENABLE BIT(0) @@ -401,6 +462,8 @@ #define RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN ((0 << 31) | (0x2 << 0)) #define RKISP1_CIF_ISP_AWB_MODE_MASK_NONE 0xFFFFFFFC #define RKISP1_CIF_ISP_AWB_MODE_READ(x) ((x) & 3) +#define RKISP1_CIF_ISP_AWB_SET_FRAMES_V12(x) (((x) & 0x07) << 28) +#define RKISP1_CIF_ISP_AWB_SET_FRAMES_MASK_V12 RKISP1_CIF_ISP_AWB_SET_FRAMES_V12(0x07) /* ISP_AWB_GAIN_RB, ISP_AWB_GAIN_G */ #define RKISP1_CIF_ISP_AWB_GAIN_R_SET(x) (((x) & 0x3FF) << 16) #define RKISP1_CIF_ISP_AWB_GAIN_R_READ(x) (((x) >> 16) & 0x3FF) @@ -435,6 +498,7 @@ /* ISP_EXP_CTRL */ #define RKISP1_CIF_ISP_EXP_ENA BIT(0) #define RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP BIT(1) +#define RKISP1_CIF_ISP_EXP_CTRL_WNDNUM_SET_V12(x) (((x) & 0x03) << 2) /* *'1' luminance calculation according to Y=(R+G+B) x 0.332 (85/256) *'0' luminance calculation according to Y=16+0.25R+0.5G+0.1094B @@ -444,15 +508,22 @@ /* ISP_EXP_H_SIZE */ #define RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(x) ((x) & 0x7FF) #define RKISP1_CIF_ISP_EXP_HEIGHT_MASK_V10 0x000007FF +#define RKISP1_CIF_ISP_EXP_H_SIZE_SET_V12(x) ((x) & 0x7FF) +#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK_V12 0x000007FF /* ISP_EXP_V_SIZE : vertical size must be a multiple of 2). */ #define RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(x) ((x) & 0x7FE) +#define RKISP1_CIF_ISP_EXP_V_SIZE_SET_V12(x) (((x) & 0x7FE) << 16) /* ISP_EXP_H_OFFSET */ #define RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V10(x) ((x) & 0x1FFF) #define RKISP1_CIF_ISP_EXP_MAX_HOFFS_V10 2424 +#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V12(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_EXP_MAX_HOFFS_V12 0x1FFF /* ISP_EXP_V_OFFSET */ #define RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V10(x) ((x) & 0x1FFF) #define RKISP1_CIF_ISP_EXP_MAX_VOFFS_V10 1806 +#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V12(x) (((x) & 0x1FFF) << 16) +#define RKISP1_CIF_ISP_EXP_MAX_VOFFS_V12 0x1FFF #define RKISP1_CIF_ISP_EXP_ROW_NUM_V10 5 #define RKISP1_CIF_ISP_EXP_COLUMN_NUM_V10 5 @@ -471,13 +542,40 @@ #define RKISP1_CIF_ISP_EXP_MIN_VSIZE_V10 \ (RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE_V10 * RKISP1_CIF_ISP_EXP_ROW_NUM_V10 + 1) +#define RKISP1_CIF_ISP_EXP_ROW_NUM_V12 15 +#define RKISP1_CIF_ISP_EXP_COLUMN_NUM_V12 15 +#define RKISP1_CIF_ISP_EXP_NUM_LUMA_REGS_V12 \ + (RKISP1_CIF_ISP_EXP_ROW_NUM_V12 * RKISP1_CIF_ISP_EXP_COLUMN_NUM_V12) + +#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE_V12 0x7FF +#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE_V12 0xE +#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE_V12 0x7FE +#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE_V12 0xE +#define RKISP1_CIF_ISP_EXP_MAX_HSIZE_V12 \ + (RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE_V12 * RKISP1_CIF_ISP_EXP_COLUMN_NUM_V12 + 1) +#define RKISP1_CIF_ISP_EXP_MIN_HSIZE_V12 \ + (RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE_V12 * RKISP1_CIF_ISP_EXP_COLUMN_NUM_V12 + 1) +#define RKISP1_CIF_ISP_EXP_MAX_VSIZE_V12 \ + (RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE_V12 * RKISP1_CIF_ISP_EXP_ROW_NUM_V12 + 1) +#define RKISP1_CIF_ISP_EXP_MIN_VSIZE_V12 \ + (RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE_V12 * RKISP1_CIF_ISP_EXP_ROW_NUM_V12 + 1) + +#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy0_V12(x) ((x) & 0xFF) +#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy1_V12(x) (((x) >> 8) & 0xFF) +#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy2_V12(x) (((x) >> 16) & 0xFF) +#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy3_V12(x) (((x) >> 24) & 0xFF) + /* LSC: ISP_LSC_CTRL */ #define RKISP1_CIF_ISP_LSC_CTRL_ENA BIT(0) #define RKISP1_CIF_ISP_LSC_SECT_SIZE_RESERVED 0xFC00FC00 #define RKISP1_CIF_ISP_LSC_GRAD_RESERVED_V10 0xF000F000 #define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED_V10 0xF000F000 +#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED_V12 0xE000E000 +#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED_V12 0xE000E000 #define RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(v0, v1) \ (((v0) & 0xFFF) | (((v1) & 0xFFF) << 12)) +#define RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(v0, v1) \ + (((v0) & 0x1FFF) | (((v1) & 0x1FFF) << 13)) #define RKISP1_CIF_ISP_LSC_SECT_SIZE(v0, v1) \ (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) #define RKISP1_CIF_ISP_LSC_GRAD_SIZE(v0, v1) \ @@ -550,6 +648,10 @@ (1 << 15) | (1 << 11) | (1 << 7) | (1 << 3)) #define RKISP1_CIFISP_DEGAMMA_Y_RESERVED 0xFFFFF000 +/* GAMMA-OUT */ +#define RKISP1_CIF_ISP_GAMMA_VALUE_V12(x, y) \ + (((x) & 0xFFF) << 16 | ((y) & 0xFFF) << 0) + /* AFM */ #define RKISP1_CIF_ISP_AFM_ENA BIT(0) #define RKISP1_CIF_ISP_AFM_THRES_RESERVED 0xFFFF0000 @@ -560,6 +662,11 @@ #define RKISP1_CIF_ISP_AFM_WINDOW_Y_MIN 0x2 #define RKISP1_CIF_ISP_AFM_WINDOW_X(x) (((x) & 0x1FFF) << 16) #define RKISP1_CIF_ISP_AFM_WINDOW_Y(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_AFM_SET_SHIFT_a_V12(x, y) (((x) & 0x7) << 16 | ((y) & 0x7) << 0) +#define RKISP1_CIF_ISP_AFM_SET_SHIFT_b_V12(x, y) (((x) & 0x7) << 20 | ((y) & 0x7) << 4) +#define RKISP1_CIF_ISP_AFM_SET_SHIFT_c_V12(x, y) (((x) & 0x7) << 24 | ((y) & 0x7) << 8) +#define RKISP1_CIF_ISP_AFM_GET_LUM_SHIFT_a_V12(x) (((x) & 0x70000) >> 16) +#define RKISP1_CIF_ISP_AFM_GET_AFM_SHIFT_a_V12(x) ((x) & 0x7) /* DPF */ #define RKISP1_CIF_ISP_DPF_MODE_EN BIT(0) @@ -582,6 +689,7 @@ #define RKISP1_CIF_CTRL_BASE 0x00000000 #define RKISP1_CIF_CCL (RKISP1_CIF_CTRL_BASE + 0x00000000) #define RKISP1_CIF_VI_ID (RKISP1_CIF_CTRL_BASE + 0x00000008) +#define RKISP1_CIF_VI_ISP_CLK_CTRL_V12 (RKISP1_CIF_CTRL_BASE + 0x0000000C) #define RKISP1_CIF_ICCL (RKISP1_CIF_CTRL_BASE + 0x00000010) #define RKISP1_CIF_IRCL (RKISP1_CIF_CTRL_BASE + 0x00000014) #define RKISP1_CIF_VI_DPCL (RKISP1_CIF_CTRL_BASE + 0x00000018) @@ -679,6 +787,23 @@ #define RKISP1_CIF_ISP_AWB_GAIN_RB_V10 (RKISP1_CIF_ISP_BASE + 0x0000013C) #define RKISP1_CIF_ISP_AWB_WHITE_CNT_V10 (RKISP1_CIF_ISP_BASE + 0x00000140) #define RKISP1_CIF_ISP_AWB_MEAN_V10 (RKISP1_CIF_ISP_BASE + 0x00000144) +#define RKISP1_CIF_ISP_AWB_PROP_V12 (RKISP1_CIF_ISP_BASE + 0x00000110) +#define RKISP1_CIF_ISP_AWB_SIZE_V12 (RKISP1_CIF_ISP_BASE + 0x00000114) +#define RKISP1_CIF_ISP_AWB_OFFS_V12 (RKISP1_CIF_ISP_BASE + 0x00000118) +#define RKISP1_CIF_ISP_AWB_REF_V12 (RKISP1_CIF_ISP_BASE + 0x0000011C) +#define RKISP1_CIF_ISP_AWB_THRESH_V12 (RKISP1_CIF_ISP_BASE + 0x00000120) +#define RKISP1_CIF_ISP_X_COOR12_V12 (RKISP1_CIF_ISP_BASE + 0x00000124) +#define RKISP1_CIF_ISP_X_COOR34_V12 (RKISP1_CIF_ISP_BASE + 0x00000128) +#define RKISP1_CIF_ISP_AWB_WHITE_CNT_V12 (RKISP1_CIF_ISP_BASE + 0x0000012C) +#define RKISP1_CIF_ISP_AWB_MEAN_V12 (RKISP1_CIF_ISP_BASE + 0x00000130) +#define RKISP1_CIF_ISP_DEGAIN_V12 (RKISP1_CIF_ISP_BASE + 0x00000134) +#define RKISP1_CIF_ISP_AWB_GAIN_G_V12 (RKISP1_CIF_ISP_BASE + 0x00000138) +#define RKISP1_CIF_ISP_AWB_GAIN_RB_V12 (RKISP1_CIF_ISP_BASE + 0x0000013C) +#define RKISP1_CIF_ISP_REGION_LINE_V12 (RKISP1_CIF_ISP_BASE + 0x00000140) +#define RKISP1_CIF_ISP_WP_CNT_REGION0_V12 (RKISP1_CIF_ISP_BASE + 0x00000160) +#define RKISP1_CIF_ISP_WP_CNT_REGION1_V12 (RKISP1_CIF_ISP_BASE + 0x00000164) +#define RKISP1_CIF_ISP_WP_CNT_REGION2_V12 (RKISP1_CIF_ISP_BASE + 0x00000168) +#define RKISP1_CIF_ISP_WP_CNT_REGION3_V12 (RKISP1_CIF_ISP_BASE + 0x0000016C) #define RKISP1_CIF_ISP_CC_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x00000170) #define RKISP1_CIF_ISP_CC_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x00000174) #define RKISP1_CIF_ISP_CC_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x00000178) @@ -736,6 +861,8 @@ #define RKISP1_CIF_ISP_CT_OFFSET_R (RKISP1_CIF_ISP_BASE + 0x00000248) #define RKISP1_CIF_ISP_CT_OFFSET_G (RKISP1_CIF_ISP_BASE + 0x0000024C) #define RKISP1_CIF_ISP_CT_OFFSET_B (RKISP1_CIF_ISP_BASE + 0x00000250) +#define RKISP1_CIF_ISP_GAMMA_OUT_MODE_V12 (RKISP1_CIF_ISP_BASE + 0x00000300) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V12 (RKISP1_CIF_ISP_BASE + 0x00000304) #define RKISP1_CIF_ISP_FLASH_BASE 0x00000660 #define RKISP1_CIF_ISP_FLASH_CMD (RKISP1_CIF_ISP_FLASH_BASE + 0x00000000) @@ -1088,6 +1215,9 @@ #define RKISP1_CIF_ISP_EXP_MEAN_24_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x0000006c) #define RKISP1_CIF_ISP_EXP_MEAN_34_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000070) #define RKISP1_CIF_ISP_EXP_MEAN_44_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000074) +#define RKISP1_CIF_ISP_EXP_SIZE_V12 (RKISP1_CIF_ISP_EXP_BASE + 0x00000004) +#define RKISP1_CIF_ISP_EXP_OFFS_V12 (RKISP1_CIF_ISP_EXP_BASE + 0x00000008) +#define RKISP1_CIF_ISP_EXP_MEAN_V12 (RKISP1_CIF_ISP_EXP_BASE + 0x0000000c) #define RKISP1_CIF_ISP_BLS_BASE 0x00002700 #define RKISP1_CIF_ISP_BLS_CTRL (RKISP1_CIF_ISP_BLS_BASE + 0x00000000) @@ -1248,6 +1378,16 @@ #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000012C) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000130) +#define RKISP1_CIF_ISP_HIST_BASE_V12 0x00002C00 +#define RKISP1_CIF_ISP_HIST_CTRL_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000000) +#define RKISP1_CIF_ISP_HIST_SIZE_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000004) +#define RKISP1_CIF_ISP_HIST_OFFS_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000008) +#define RKISP1_CIF_ISP_HIST_DBG1_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000000C) +#define RKISP1_CIF_ISP_HIST_DBG2_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000001C) +#define RKISP1_CIF_ISP_HIST_DBG3_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000002C) +#define RKISP1_CIF_ISP_HIST_WEIGHT_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000003C) +#define RKISP1_CIF_ISP_HIST_BIN_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000120) + #define RKISP1_CIF_ISP_VSM_BASE 0x00002F00 #define RKISP1_CIF_ISP_VSM_MODE (RKISP1_CIF_ISP_VSM_BASE + 0x00000000) #define RKISP1_CIF_ISP_VSM_H_OFFS (RKISP1_CIF_ISP_VSM_BASE + 0x00000004) @@ -1259,4 +1399,7 @@ #define RKISP1_CIF_ISP_VSM_DELTA_H (RKISP1_CIF_ISP_VSM_BASE + 0x0000001C) #define RKISP1_CIF_ISP_VSM_DELTA_V (RKISP1_CIF_ISP_VSM_BASE + 0x00000020) +#define RKISP1_CIF_ISP_CSI0_BASE 0x00007000 +#define RKISP1_CIF_ISP_CSI0_CTRL0 (RKISP1_CIF_ISP_CSI0_BASE + 0x00000000) + #endif /* _RKISP1_REGS_H */ diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c index d4e72027d61f..be5777c65bfb 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c @@ -195,6 +195,27 @@ static void rkisp1_stats_get_awb_meas_v10(struct rkisp1_stats *stats, RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(reg_val); } +static void rkisp1_stats_get_awb_meas_v12(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) +{ + /* Protect against concurrent access from ISR? */ + struct rkisp1_device *rkisp1 = stats->rkisp1; + u32 reg_val; + + pbuf->meas_type |= RKISP1_CIF_ISP_STAT_AWB; + reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB_WHITE_CNT_V12); + pbuf->params.awb.awb_mean[0].cnt = + RKISP1_CIF_ISP_AWB_GET_PIXEL_CNT(reg_val); + reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB_MEAN_V12); + + pbuf->params.awb.awb_mean[0].mean_cr_or_r = + RKISP1_CIF_ISP_AWB_GET_MEAN_CR_R(reg_val); + pbuf->params.awb.awb_mean[0].mean_cb_or_b = + RKISP1_CIF_ISP_AWB_GET_MEAN_CB_B(reg_val); + pbuf->params.awb.awb_mean[0].mean_y_or_g = + RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(reg_val); +} + static void rkisp1_stats_get_aec_meas_v10(struct rkisp1_stats *stats, struct rkisp1_stat_buffer *pbuf) { @@ -208,6 +229,30 @@ static void rkisp1_stats_get_aec_meas_v10(struct rkisp1_stats *stats, RKISP1_CIF_ISP_EXP_MEAN_00_V10 + i * 4); } +static void rkisp1_stats_get_aec_meas_v12(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) +{ + struct rkisp1_device *rkisp1 = stats->rkisp1; + u32 value; + int i; + + pbuf->meas_type |= RKISP1_CIF_ISP_STAT_AUTOEXP; + for (i = 0; i < RKISP1_CIF_ISP_AE_MEAN_MAX_V12 / 4; i++) { + value = rkisp1_read(rkisp1, RKISP1_CIF_ISP_EXP_MEAN_V12 + i * 4); + pbuf->params.ae.exp_mean[4 * i + 0] = + RKISP1_CIF_ISP_EXP_GET_MEAN_xy0_V12(value); + pbuf->params.ae.exp_mean[4 * i + 1] = + RKISP1_CIF_ISP_EXP_GET_MEAN_xy1_V12(value); + pbuf->params.ae.exp_mean[4 * i + 2] = + RKISP1_CIF_ISP_EXP_GET_MEAN_xy2_V12(value); + pbuf->params.ae.exp_mean[4 * i + 3] = + RKISP1_CIF_ISP_EXP_GET_MEAN_xy3_V12(value); + } + + value = rkisp1_read(rkisp1, RKISP1_CIF_ISP_EXP_MEAN_V12 + i * 4); + pbuf->params.ae.exp_mean[4 * i + 0] = RKISP1_CIF_ISP_EXP_GET_MEAN_xy0_V12(value); +} + static void rkisp1_stats_get_afc_meas(struct rkisp1_stats *stats, struct rkisp1_stat_buffer *pbuf) { @@ -239,6 +284,23 @@ static void rkisp1_stats_get_hst_meas_v10(struct rkisp1_stats *stats, } } +static void rkisp1_stats_get_hst_meas_v12(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) +{ + struct rkisp1_device *rkisp1 = stats->rkisp1; + u32 value; + int i; + + pbuf->meas_type |= RKISP1_CIF_ISP_STAT_HIST; + for (i = 0; i < RKISP1_CIF_ISP_HIST_BIN_N_MAX_V12 / 2; i++) { + value = rkisp1_read(rkisp1, RKISP1_CIF_ISP_HIST_BIN_V12 + i * 4); + pbuf->params.hist.hist_bins[2 * i] = + RKISP1_CIF_ISP_HIST_GET_BIN0_V12(value); + pbuf->params.hist.hist_bins[2 * i + 1] = + RKISP1_CIF_ISP_HIST_GET_BIN1_V12(value); + } +} + static void rkisp1_stats_get_bls_meas(struct rkisp1_stats *stats, struct rkisp1_stat_buffer *pbuf) { @@ -292,6 +354,12 @@ static const struct rkisp1_stats_ops rkisp1_v10_stats_ops = { .get_hst_meas = rkisp1_stats_get_hst_meas_v10, }; +static struct rkisp1_stats_ops rkisp1_v12_stats_ops = { + .get_awb_meas = rkisp1_stats_get_awb_meas_v12, + .get_aec_meas = rkisp1_stats_get_aec_meas_v12, + .get_hst_meas = rkisp1_stats_get_hst_meas_v12, +}; + static void rkisp1_stats_send_measurement(struct rkisp1_stats *stats, u32 isp_ris) { @@ -359,7 +427,10 @@ static void rkisp1_init_stats(struct rkisp1_stats *stats) stats->vdev_fmt.fmt.meta.buffersize = sizeof(struct rkisp1_stat_buffer); - stats->ops = &rkisp1_v10_stats_ops; + if (stats->rkisp1->media_dev.hw_revision == RKISP1_V12) + stats->ops = &rkisp1_v12_stats_ops; + else + stats->ops = &rkisp1_v10_stats_ops; } int rkisp1_stats_register(struct rkisp1_device *rkisp1) -- cgit v1.2.3 From ad82ecd26931a087209a69edf36f380422e2ab3e Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 23 Jul 2021 09:32:20 +0200 Subject: media: dt-bindings: media: rkisp1: document px30 isp compatible Add the compatible for the px30-variant of the rkisp Signed-off-by: Heiko Stuebner Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/rockchip-isp1.yaml | 67 +++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml index 14ac5730b377..d1489b177331 100644 --- a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml +++ b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml @@ -15,7 +15,9 @@ description: | properties: compatible: - const: rockchip,rk3399-cif-isp + enum: + - rockchip,px30-cif-isp + - rockchip,rk3399-cif-isp reg: maxItems: 1 @@ -200,3 +202,66 @@ examples: }; }; }; + + - | + + #include + #include + + parent1: parent { + #address-cells = <2>; + #size-cells = <2>; + + isp: isp@ff4a0000 { + compatible = "rockchip,px30-cif-isp"; + reg = <0x0 0xff4a0000 0x0 0x8000>; + interrupts = , + , + ; + interrupt-names = "isp", "mi", "mipi"; + clocks = <&cru SCLK_ISP0>, + <&cru ACLK_ISP0_WRAPPER>, + <&cru HCLK_ISP0_WRAPPER>, + <&cru PCLK_ISP1_WRAPPER>; + clock-names = "isp", "aclk", "hclk", "pclk"; + iommus = <&isp_mmu>; + phys = <&csi_dphy>; + phy-names = "dphy"; + power-domains = <&power PX30_PD_VI>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi_in_ucam1: endpoint@0 { + reg = <0>; + remote-endpoint = <&ucam1_out>; + data-lanes = <1 2>; + }; + }; + }; + }; + + i2c2: i2c { + #address-cells = <1>; + #size-cells = <0>; + + ov5695: camera@36 { + compatible = "ovti,ov5647"; + reg = <0x36>; + clocks = <&cru SCLK_CIF_OUT>; + + port { + ucam1_out: endpoint { + remote-endpoint = <&mipi_in_ucam1>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; -- cgit v1.2.3 From ecf8d36f93c0aa1dc69e126983bac96edbdb69d8 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 23 Jul 2021 09:32:21 +0200 Subject: media: rockchip: rkisp1: add support for px30 isp version The px30 uses a V12 isp block so add compatible and matchdata for it. Signed-off-by: Heiko Stuebner Reviewed-by: Dafna Hirschfeld Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/rockchip/rkisp1/rkisp1-dev.c | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index b5e35b1287ac..50b166c49a03 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -406,6 +406,27 @@ static irqreturn_t rkisp1_isr(int irq, void *ctx) return IRQ_HANDLED; } +static const char * const px30_isp_clks[] = { + "isp", + "aclk", + "hclk", + "pclk", +}; + +static const struct rkisp1_isr_data px30_isp_isrs[] = { + { "isp", rkisp1_isp_isr }, + { "mi", rkisp1_capture_isr }, + { "mipi", rkisp1_mipi_isr }, +}; + +static const struct rkisp1_match_data px30_isp_match_data = { + .clks = px30_isp_clks, + .clk_size = ARRAY_SIZE(px30_isp_clks), + .isrs = px30_isp_isrs, + .isr_size = ARRAY_SIZE(px30_isp_isrs), + .isp_ver = RKISP1_V12, +}; + static const char * const rk3399_isp_clks[] = { "isp", "aclk", @@ -425,6 +446,10 @@ static const struct rkisp1_match_data rk3399_isp_match_data = { }; static const struct of_device_id rkisp1_of_match[] = { + { + .compatible = "rockchip,px30-cif-isp", + .data = &px30_isp_match_data, + }, { .compatible = "rockchip,rk3399-cif-isp", .data = &rk3399_isp_match_data, -- cgit v1.2.3 From 8cc80c606bd1db7febd43d900fc129520580beab Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Mon, 26 Jul 2021 10:01:10 +0200 Subject: media: camss: vfe: Don't read hardware version needlessly vfe_set_power() is invoked a few times, which causes a lot of VFE HW version prints. Secondly there is no real reason for calling hw_version_read() from this location specifically, since it does nothing more than print the VFE HW version. A better location for the hw_version_read() call would be somewhere which is only executed once per VFE unit. Signed-off-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-vfe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index e0f3a36f3f3f..f6e889c1598e 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -713,8 +713,6 @@ static int vfe_set_power(struct v4l2_subdev *sd, int on) ret = vfe_get(vfe); if (ret < 0) return ret; - - vfe->ops->hw_version_read(vfe, vfe->camss->dev); } else { vfe_put(vfe); } @@ -1301,6 +1299,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, return -EINVAL; } vfe->ops->subdev_init(dev, vfe); + vfe->ops->hw_version_read(vfe, dev); /* Memory */ -- cgit v1.2.3 From 2fa698e3da84edc6b7a2d670f8bd5035891a744e Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Mon, 26 Jul 2021 10:01:11 +0200 Subject: media: camss: vfe: Decrease priority of of VFE HW version to 'dbg' The HW Version can in no case represent an error, so change the print priority to 'dbg'. Signed-off-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-vfe-170.c | 2 +- drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 2 +- drivers/media/platform/qcom/camss/camss-vfe-4-8.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c index 8594d275b41d..1ad502a1c276 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-170.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -185,7 +185,7 @@ static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev) u32 rev = (hw_version >> 16) & 0xFFF; u32 step = hw_version & 0xFFFF; - dev_err(dev, "VFE HW Version = %u.%u.%u\n", gen, rev, step); + dev_dbg(dev, "VFE HW Version = %u.%u.%u\n", gen, rev, step); } static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c index a59635217758..13f0fa6a7d60 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c @@ -258,7 +258,7 @@ static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev) { u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION); - dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version); + dev_dbg(dev, "VFE HW Version = 0x%08x\n", hw_version); } static u16 vfe_get_ub_size(u8 vfe_id) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c index 998429dbb65c..03f92a6737b0 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c @@ -251,7 +251,7 @@ static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev) { u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION); - dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version); + dev_dbg(dev, "VFE HW Version = 0x%08x\n", hw_version); } static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits) -- cgit v1.2.3 From 5ad5866737991d83cb4a74a02d0c32a18adb9246 Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Mon, 26 Jul 2021 10:01:12 +0200 Subject: media: camss: vfe: Remove vfe_hw_version_read() argument The device argument is not needed, since it is accessible through the vfe_device argument already. Signed-off-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-vfe-170.c | 5 +++-- drivers/media/platform/qcom/camss/camss-vfe-4-1.c | 4 ++-- drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 4 ++-- drivers/media/platform/qcom/camss/camss-vfe-4-8.c | 4 ++-- drivers/media/platform/qcom/camss/camss-vfe.c | 2 +- drivers/media/platform/qcom/camss/camss-vfe.h | 2 +- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c index 1ad502a1c276..8ef4e80a62a2 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-170.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -177,7 +177,7 @@ #define VFE_BUS_WM_FRAME_INC(n) (0x2258 + (n) * 0x100) #define VFE_BUS_WM_BURST_LIMIT(n) (0x225c + (n) * 0x100) -static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev) +static void vfe_hw_version_read(struct vfe_device *vfe) { u32 hw_version = readl_relaxed(vfe->base + VFE_HW_VERSION); @@ -185,7 +185,8 @@ static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev) u32 rev = (hw_version >> 16) & 0xFFF; u32 step = hw_version & 0xFFFF; - dev_dbg(dev, "VFE HW Version = %u.%u.%u\n", gen, rev, step); + dev_dbg(vfe->camss->dev, "VFE HW Version = %u.%u.%u\n", + gen, rev, step); } static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c index 53c56a8d4545..614c266e8cd1 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c @@ -210,11 +210,11 @@ #define MSM_VFE_VFE0_UB_SIZE 1023 #define MSM_VFE_VFE0_UB_SIZE_RDI (MSM_VFE_VFE0_UB_SIZE / 3) -static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev) +static void vfe_hw_version_read(struct vfe_device *vfe) { u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION); - dev_dbg(dev, "VFE HW Version = 0x%08x\n", hw_version); + dev_dbg(vfe->camss->dev, "VFE HW Version = 0x%08x\n", hw_version); } static u16 vfe_get_ub_size(u8 vfe_id) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c index 13f0fa6a7d60..aa175e0f6331 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c @@ -254,11 +254,11 @@ #define MSM_VFE_VFE1_UB_SIZE 1535 #define MSM_VFE_VFE1_UB_SIZE_RDI (MSM_VFE_VFE1_UB_SIZE / 3) -static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev) +static void vfe_hw_version_read(struct vfe_device *vfe) { u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION); - dev_dbg(dev, "VFE HW Version = 0x%08x\n", hw_version); + dev_dbg(vfe->camss->dev, "VFE HW Version = 0x%08x\n", hw_version); } static u16 vfe_get_ub_size(u8 vfe_id) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c index 03f92a6737b0..b897f5163c5d 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c @@ -247,11 +247,11 @@ #define MSM_VFE_VFE1_UB_SIZE 1535 #define MSM_VFE_VFE1_UB_SIZE_RDI (MSM_VFE_VFE1_UB_SIZE / 3) -static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev) +static void vfe_hw_version_read(struct vfe_device *vfe) { u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION); - dev_dbg(dev, "VFE HW Version = 0x%08x\n", hw_version); + dev_dbg(vfe->camss->dev, "VFE HW Version = 0x%08x\n", hw_version); } static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits) diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index f6e889c1598e..9b4f8136759c 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -1299,7 +1299,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, return -EINVAL; } vfe->ops->subdev_init(dev, vfe); - vfe->ops->hw_version_read(vfe, dev); + vfe->ops->hw_version_read(vfe); /* Memory */ diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index 844b9275031d..cca251816d28 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -103,7 +103,7 @@ struct vfe_device; struct vfe_hw_ops { void (*enable_irq_common)(struct vfe_device *vfe); void (*global_reset)(struct vfe_device *vfe); - void (*hw_version_read)(struct vfe_device *vfe, struct device *dev); + void (*hw_version_read)(struct vfe_device *vfe); irqreturn_t (*isr)(int irq, void *dev); void (*isr_read)(struct vfe_device *vfe, u32 *value0, u32 *value1); void (*pm_domain_off)(struct vfe_device *vfe); -- cgit v1.2.3 From d2e86540366e1701baf852ee0301323ff113459c Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Mon, 26 Jul 2021 10:01:13 +0200 Subject: media: camss: vfe: Rework vfe_hw_version_read() function definition Expose the VFE version by returning the value read from the HW_VERSION register. Secondly, change the name of this function to conform with the CSID equivalent. Signed-off-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-vfe-170.c | 6 ++++-- drivers/media/platform/qcom/camss/camss-vfe-4-1.c | 6 ++++-- drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 6 ++++-- drivers/media/platform/qcom/camss/camss-vfe-4-8.c | 6 ++++-- drivers/media/platform/qcom/camss/camss-vfe.c | 2 +- drivers/media/platform/qcom/camss/camss-vfe.h | 2 +- 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c index 8ef4e80a62a2..5c083d70d495 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-170.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -177,7 +177,7 @@ #define VFE_BUS_WM_FRAME_INC(n) (0x2258 + (n) * 0x100) #define VFE_BUS_WM_BURST_LIMIT(n) (0x225c + (n) * 0x100) -static void vfe_hw_version_read(struct vfe_device *vfe) +static u32 vfe_hw_version(struct vfe_device *vfe) { u32 hw_version = readl_relaxed(vfe->base + VFE_HW_VERSION); @@ -187,6 +187,8 @@ static void vfe_hw_version_read(struct vfe_device *vfe) dev_dbg(vfe->camss->dev, "VFE HW Version = %u.%u.%u\n", gen, rev, step); + + return hw_version; } static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits) @@ -772,7 +774,7 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) const struct vfe_hw_ops vfe_ops_170 = { .global_reset = vfe_global_reset, - .hw_version_read = vfe_hw_version_read, + .hw_version = vfe_hw_version, .isr_read = vfe_isr_read, .isr = vfe_isr, .pm_domain_off = vfe_pm_domain_off, diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c index 614c266e8cd1..7b7c9a0aaab2 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c @@ -210,11 +210,13 @@ #define MSM_VFE_VFE0_UB_SIZE 1023 #define MSM_VFE_VFE0_UB_SIZE_RDI (MSM_VFE_VFE0_UB_SIZE / 3) -static void vfe_hw_version_read(struct vfe_device *vfe) +static u32 vfe_hw_version(struct vfe_device *vfe) { u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION); dev_dbg(vfe->camss->dev, "VFE HW Version = 0x%08x\n", hw_version); + + return hw_version; } static u16 vfe_get_ub_size(u8 vfe_id) @@ -1004,7 +1006,7 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) const struct vfe_hw_ops vfe_ops_4_1 = { .global_reset = vfe_global_reset, - .hw_version_read = vfe_hw_version_read, + .hw_version = vfe_hw_version, .isr_read = vfe_isr_read, .isr = vfe_isr, .pm_domain_off = vfe_pm_domain_off, diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c index aa175e0f6331..2836b12ec989 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c @@ -254,11 +254,13 @@ #define MSM_VFE_VFE1_UB_SIZE 1535 #define MSM_VFE_VFE1_UB_SIZE_RDI (MSM_VFE_VFE1_UB_SIZE / 3) -static void vfe_hw_version_read(struct vfe_device *vfe) +static u32 vfe_hw_version(struct vfe_device *vfe) { u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION); dev_dbg(vfe->camss->dev, "VFE HW Version = 0x%08x\n", hw_version); + + return hw_version; } static u16 vfe_get_ub_size(u8 vfe_id) @@ -1196,7 +1198,7 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) const struct vfe_hw_ops vfe_ops_4_7 = { .global_reset = vfe_global_reset, - .hw_version_read = vfe_hw_version_read, + .hw_version = vfe_hw_version, .isr_read = vfe_isr_read, .isr = vfe_isr, .pm_domain_off = vfe_pm_domain_off, diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c index b897f5163c5d..19519234f727 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c @@ -247,11 +247,13 @@ #define MSM_VFE_VFE1_UB_SIZE 1535 #define MSM_VFE_VFE1_UB_SIZE_RDI (MSM_VFE_VFE1_UB_SIZE / 3) -static void vfe_hw_version_read(struct vfe_device *vfe) +static u32 vfe_hw_version(struct vfe_device *vfe) { u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION); dev_dbg(vfe->camss->dev, "VFE HW Version = 0x%08x\n", hw_version); + + return hw_version; } static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits) @@ -1180,7 +1182,7 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) const struct vfe_hw_ops vfe_ops_4_8 = { .global_reset = vfe_global_reset, - .hw_version_read = vfe_hw_version_read, + .hw_version = vfe_hw_version, .isr_read = vfe_isr_read, .isr = vfe_isr, .pm_domain_off = vfe_pm_domain_off, diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 9b4f8136759c..6b2f33fc9be2 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -1299,7 +1299,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, return -EINVAL; } vfe->ops->subdev_init(dev, vfe); - vfe->ops->hw_version_read(vfe); + vfe->ops->hw_version(vfe); /* Memory */ diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index cca251816d28..f166d176cb77 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -103,7 +103,7 @@ struct vfe_device; struct vfe_hw_ops { void (*enable_irq_common)(struct vfe_device *vfe); void (*global_reset)(struct vfe_device *vfe); - void (*hw_version_read)(struct vfe_device *vfe); + u32 (*hw_version)(struct vfe_device *vfe); irqreturn_t (*isr)(int irq, void *dev); void (*isr_read)(struct vfe_device *vfe, u32 *value0, u32 *value1); void (*pm_domain_off)(struct vfe_device *vfe); -- cgit v1.2.3 From 7ba59fb6c3b473dc0c76e87cd493388480c6dd27 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 15 Jul 2021 17:12:22 +0200 Subject: media: hevc: Add scaling matrix control HEVC scaling lists are used for the scaling process for transform coefficients. V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED has to set when they are encoded in the bitstream. Signed-off-by: Benjamin Gaignard Reviewed-by: Jernej Skrabec Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/ext-ctrls-codec.rst | 57 ++++++++++++++++++++++ .../userspace-api/media/v4l/vidioc-queryctrl.rst | 6 +++ drivers/media/v4l2-core/v4l2-ctrls-core.c | 6 +++ drivers/media/v4l2-core/v4l2-ctrls-defs.c | 4 ++ include/media/hevc-ctrls.h | 11 +++++ 5 files changed, 84 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index 976d34445a24..e141f0e4eec9 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -3088,6 +3088,63 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - \normalsize +``V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (struct)`` + Specifies the HEVC scaling matrix parameters used for the scaling process + for transform coefficients. + These matrix and parameters are defined according to :ref:`hevc`. + They are described in section 7.4.5 "Scaling list data semantics" of + the specification. + +.. c:type:: v4l2_ctrl_hevc_scaling_matrix + +.. raw:: latex + + \scriptsize + +.. tabularcolumns:: |p{5.4cm}|p{6.8cm}|p{5.1cm}| + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_hevc_scaling_matrix + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``scaling_list_4x4[6][16]`` + - Scaling list is used for the scaling process for transform + coefficients. The values on each scaling list are expected + in raster scan order. + * - __u8 + - ``scaling_list_8x8[6][64]`` + - Scaling list is used for the scaling process for transform + coefficients. The values on each scaling list are expected + in raster scan order. + * - __u8 + - ``scaling_list_16x16[6][64]`` + - Scaling list is used for the scaling process for transform + coefficients. The values on each scaling list are expected + in raster scan order. + * - __u8 + - ``scaling_list_32x32[2][64]`` + - Scaling list is used for the scaling process for transform + coefficients. The values on each scaling list are expected + in raster scan order. + * - __u8 + - ``scaling_list_dc_coef_16x16[6]`` + - Scaling list is used for the scaling process for transform + coefficients. The values on each scaling list are expected + in raster scan order. + * - __u8 + - ``scaling_list_dc_coef_32x32[2]`` + - Scaling list is used for the scaling process for transform + coefficients. The values on each scaling list are expected + in raster scan order. + +.. raw:: latex + + \normalsize + .. c:type:: v4l2_hevc_dpb_entry .. raw:: latex diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst index f9ecf6276129..2f491c17dd5d 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst @@ -495,6 +495,12 @@ See also the examples in :ref:`control`. - n/a - A struct :c:type:`v4l2_ctrl_hevc_slice_params`, containing HEVC slice parameters for stateless video decoders. + * - ``V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_ctrl_hevc_scaling_matrix`, containing HEVC + scaling matrix for stateless video decoders. * - ``V4L2_CTRL_TYPE_VP8_FRAME`` - n/a - n/a diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c index c4b5082849b6..70adfc1b9c81 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -687,6 +687,9 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, break; + case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX: + break; + case V4L2_CTRL_TYPE_AREA: area = p; if (!area->width || !area->height) @@ -1240,6 +1243,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params); break; + case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX: + elem_size = sizeof(struct v4l2_ctrl_hevc_scaling_matrix); + break; case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS: elem_size = sizeof(struct v4l2_ctrl_hevc_decode_params); break; diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c index 421300e13a41..eae300c58274 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c @@ -997,6 +997,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_HEVC_SPS: return "HEVC Sequence Parameter Set"; case V4L2_CID_MPEG_VIDEO_HEVC_PPS: return "HEVC Picture Parameter Set"; case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters"; + case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX: return "HEVC Scaling Matrix"; case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS: return "HEVC Decode Parameters"; case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: return "HEVC Decode Mode"; case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return "HEVC Start Code"; @@ -1490,6 +1491,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: *type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS; break; + case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX: + *type = V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX; + break; case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS: *type = V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS; break; diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h index 781371bff2ad..ef63bc205756 100644 --- a/include/media/hevc-ctrls.h +++ b/include/media/hevc-ctrls.h @@ -19,6 +19,7 @@ #define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_CODEC_BASE + 1008) #define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_CODEC_BASE + 1009) #define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_CODEC_BASE + 1010) +#define V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (V4L2_CID_CODEC_BASE + 1011) #define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS (V4L2_CID_CODEC_BASE + 1012) #define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (V4L2_CID_CODEC_BASE + 1015) #define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (V4L2_CID_CODEC_BASE + 1016) @@ -27,6 +28,7 @@ #define V4L2_CTRL_TYPE_HEVC_SPS 0x0120 #define V4L2_CTRL_TYPE_HEVC_PPS 0x0121 #define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122 +#define V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX 0x0123 #define V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS 0x0124 enum v4l2_mpeg_video_hevc_decode_mode { @@ -225,6 +227,15 @@ struct v4l2_ctrl_hevc_decode_params { __u64 flags; }; +struct v4l2_ctrl_hevc_scaling_matrix { + __u8 scaling_list_4x4[6][16]; + __u8 scaling_list_8x8[6][64]; + __u8 scaling_list_16x16[6][64]; + __u8 scaling_list_32x32[2][64]; + __u8 scaling_list_dc_coef_16x16[6]; + __u8 scaling_list_dc_coef_32x32[2]; +}; + /* MPEG-class control IDs specific to the Hantro driver as defined by V4L2 */ #define V4L2_CID_CODEC_HANTRO_BASE (V4L2_CTRL_CLASS_CODEC | 0x1200) /* -- cgit v1.2.3 From 5523dc7b851849afe53bc4dd747c9709aace515d Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 15 Jul 2021 17:12:23 +0200 Subject: media: hantro: Add scaling lists feature If the bitstream embedded scaling lists allow the driver to use them for decode the frames. The scaling lists are expected to be in raster scan order (i.e. not up right diagonal scan order) Allocate the memory needed to store lists. Signed-off-by: Benjamin Gaignard Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil [hverkuil: add missing @scaling kernel doc description in hantro_hw.h] Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_drv.c | 8 ++-- drivers/staging/media/hantro/hantro_g2_hevc_dec.c | 52 +++++++++++++++++++++++ drivers/staging/media/hantro/hantro_hevc.c | 21 +++++++++ drivers/staging/media/hantro/hantro_hw.h | 4 ++ 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 8a2edd67f2c6..41345b9e54bd 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -263,9 +263,6 @@ static int hantro_try_ctrl(struct v4l2_ctrl *ctrl) if (sps->bit_depth_luma_minus8 != 0) /* Only 8-bit is supported */ return -EINVAL; - if (sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED) - /* No scaling support */ - return -EINVAL; } return 0; } @@ -447,6 +444,11 @@ static const struct hantro_ctrl controls[] = { .cfg = { .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS, }, + }, { + .codec = HANTRO_HEVC_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX, + }, }, { .codec = HANTRO_HEVC_DECODER, .cfg = { diff --git a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c index 340efb57fd18..76a921163b9a 100644 --- a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c +++ b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c @@ -516,6 +516,56 @@ static void set_buffers(struct hantro_ctx *ctx) hantro_write_addr(vpu, G2_TILE_BSD, ctx->hevc_dec.tile_bsd.dma); } +static void prepare_scaling_list_buffer(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; + const struct v4l2_ctrl_hevc_scaling_matrix *sc = ctrls->scaling; + const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps; + u8 *p = ((u8 *)ctx->hevc_dec.scaling_lists.cpu); + unsigned int scaling_list_enabled; + unsigned int i, j, k; + + scaling_list_enabled = !!(sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED); + hantro_reg_write(vpu, &g2_scaling_list_e, scaling_list_enabled); + + if (!scaling_list_enabled) + return; + + for (i = 0; i < ARRAY_SIZE(sc->scaling_list_dc_coef_16x16); i++) + *p++ = sc->scaling_list_dc_coef_16x16[i]; + + for (i = 0; i < ARRAY_SIZE(sc->scaling_list_dc_coef_32x32); i++) + *p++ = sc->scaling_list_dc_coef_32x32[i]; + + /* 128-bit boundary */ + p += 8; + + /* write scaling lists column by column */ + + for (i = 0; i < 6; i++) + for (j = 0; j < 4; j++) + for (k = 0; k < 4; k++) + *p++ = sc->scaling_list_4x4[i][4 * k + j]; + + for (i = 0; i < 6; i++) + for (j = 0; j < 8; j++) + for (k = 0; k < 8; k++) + *p++ = sc->scaling_list_8x8[i][8 * k + j]; + + for (i = 0; i < 6; i++) + for (j = 0; j < 8; j++) + for (k = 0; k < 8; k++) + *p++ = sc->scaling_list_16x16[i][8 * k + j]; + + for (i = 0; i < 2; i++) + for (j = 0; j < 8; j++) + for (k = 0; k < 8; k++) + *p++ = sc->scaling_list_32x32[i][8 * k + j]; + + hantro_write_addr(vpu, HEVC_SCALING_LIST, ctx->hevc_dec.scaling_lists.dma); +} + static void hantro_g2_check_idle(struct hantro_dev *vpu) { int i; @@ -556,6 +606,8 @@ int hantro_g2_hevc_dec_run(struct hantro_ctx *ctx) set_buffers(ctx); prepare_tile_info_buffer(ctx); + prepare_scaling_list_buffer(ctx); + hantro_end_prepare_run(ctx); hantro_reg_write(vpu, &g2_mode, HEVC_DEC_MODE); diff --git a/drivers/staging/media/hantro/hantro_hevc.c b/drivers/staging/media/hantro/hantro_hevc.c index 5347f5a41c2a..ee03123e7704 100644 --- a/drivers/staging/media/hantro/hantro_hevc.c +++ b/drivers/staging/media/hantro/hantro_hevc.c @@ -20,6 +20,8 @@ /* tile border coefficients of filter */ #define VERT_SAO_RAM_SIZE 48 /* bytes per pixel */ +#define SCALING_LIST_SIZE (16 * 64) + #define MAX_TILE_COLS 20 #define MAX_TILE_ROWS 22 @@ -256,6 +258,11 @@ int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx) if (WARN_ON(!ctrls->decode_params)) return -EINVAL; + ctrls->scaling = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX); + if (WARN_ON(!ctrls->scaling)) + return -EINVAL; + ctrls->sps = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SPS); if (WARN_ON(!ctrls->sps)) @@ -284,6 +291,12 @@ void hantro_hevc_dec_exit(struct hantro_ctx *ctx) hevc_dec->tile_sizes.dma); hevc_dec->tile_sizes.cpu = NULL; + if (hevc_dec->scaling_lists.cpu) + dma_free_coherent(vpu->dev, hevc_dec->scaling_lists.size, + hevc_dec->scaling_lists.cpu, + hevc_dec->scaling_lists.dma); + hevc_dec->scaling_lists.cpu = NULL; + if (hevc_dec->tile_filter.cpu) dma_free_coherent(vpu->dev, hevc_dec->tile_filter.size, hevc_dec->tile_filter.cpu, @@ -327,6 +340,14 @@ int hantro_hevc_dec_init(struct hantro_ctx *ctx) hevc_dec->tile_sizes.size = size; + hevc_dec->scaling_lists.cpu = dma_alloc_coherent(vpu->dev, SCALING_LIST_SIZE, + &hevc_dec->scaling_lists.dma, + GFP_KERNEL); + if (!hevc_dec->scaling_lists.cpu) + return -ENOMEM; + + hevc_dec->scaling_lists.size = SCALING_LIST_SIZE; + hantro_hevc_ref_init(ctx); return 0; diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index df7b5e3a57b9..267a6d33a47b 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -104,6 +104,7 @@ struct hantro_h264_dec_hw_ctx { /** * struct hantro_hevc_dec_ctrls * @decode_params: Decode params + * @scaling: Scaling matrix * @sps: SPS info * @pps: PPS info * @hevc_hdr_skip_length: the number of data (in bits) to skip in the @@ -112,6 +113,7 @@ struct hantro_h264_dec_hw_ctx { */ struct hantro_hevc_dec_ctrls { const struct v4l2_ctrl_hevc_decode_params *decode_params; + const struct v4l2_ctrl_hevc_scaling_matrix *scaling; const struct v4l2_ctrl_hevc_sps *sps; const struct v4l2_ctrl_hevc_pps *pps; u32 hevc_hdr_skip_length; @@ -124,6 +126,7 @@ struct hantro_hevc_dec_ctrls { * @tile_sao: Tile SAO buffer * @tile_bsd: Tile BSD control buffer * @ref_bufs: Internal reference buffers + * @scaling_lists: Scaling lists buffer * @ref_bufs_poc: Internal reference buffers picture order count * @ref_bufs_used: Bitfield of used reference buffers * @ctrls: V4L2 controls attached to a run @@ -135,6 +138,7 @@ struct hantro_hevc_dec_hw_ctx { struct hantro_aux_buf tile_sao; struct hantro_aux_buf tile_bsd; struct hantro_aux_buf ref_bufs[NUM_REF_PICTURES]; + struct hantro_aux_buf scaling_lists; int ref_bufs_poc[NUM_REF_PICTURES]; u32 ref_bufs_used; struct hantro_hevc_dec_ctrls ctrls; -- cgit v1.2.3 From 2845d9d6da0fb60494d91784affa1678c0ae68cf Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 6 Jun 2021 08:50:50 +0200 Subject: media: cedrus: hevc: Add support for scaling lists HEVC frames may use scaling list feature. Add support for it. Signed-off-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus.c | 6 ++ drivers/staging/media/sunxi/cedrus/cedrus.h | 1 + drivers/staging/media/sunxi/cedrus/cedrus_dec.c | 2 + drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 70 +++++++++++++++++++++++- drivers/staging/media/sunxi/cedrus/cedrus_regs.h | 2 + 5 files changed, 80 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index c0d005dafc6c..8114e2167013 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -135,6 +135,12 @@ static const struct cedrus_control cedrus_controls[] = { }, .codec = CEDRUS_CODEC_H265, }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX, + }, + .codec = CEDRUS_CODEC_H265, + }, { .cfg = { .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 88afba17b78b..9c7bfd2b6616 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -78,6 +78,7 @@ struct cedrus_h265_run { const struct v4l2_ctrl_hevc_pps *pps; const struct v4l2_ctrl_hevc_slice_params *slice_params; const struct v4l2_ctrl_hevc_decode_params *decode_params; + const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix; }; struct cedrus_vp8_run { diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index 40e8c4123f76..a16c1422558f 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -72,6 +72,8 @@ void cedrus_device_run(void *priv) V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS); run.h265.decode_params = cedrus_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS); + run.h265.scaling_matrix = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX); break; case V4L2_PIX_FMT_VP8_FRAME: diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index ef0311a16d01..3d9561d4aadb 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -238,6 +238,69 @@ static void cedrus_h265_skip_bits(struct cedrus_dev *dev, int num) } } +static void cedrus_h265_write_scaling_list(struct cedrus_ctx *ctx, + struct cedrus_run *run) +{ + const struct v4l2_ctrl_hevc_scaling_matrix *scaling; + struct cedrus_dev *dev = ctx->dev; + u32 i, j, k, val; + + scaling = run->h265.scaling_matrix; + + cedrus_write(dev, VE_DEC_H265_SCALING_LIST_DC_COEF0, + (scaling->scaling_list_dc_coef_32x32[1] << 24) | + (scaling->scaling_list_dc_coef_32x32[0] << 16) | + (scaling->scaling_list_dc_coef_16x16[1] << 8) | + (scaling->scaling_list_dc_coef_16x16[0] << 0)); + + cedrus_write(dev, VE_DEC_H265_SCALING_LIST_DC_COEF1, + (scaling->scaling_list_dc_coef_16x16[5] << 24) | + (scaling->scaling_list_dc_coef_16x16[4] << 16) | + (scaling->scaling_list_dc_coef_16x16[3] << 8) | + (scaling->scaling_list_dc_coef_16x16[2] << 0)); + + cedrus_h265_sram_write_offset(dev, VE_DEC_H265_SRAM_OFFSET_SCALING_LISTS); + + for (i = 0; i < 6; i++) + for (j = 0; j < 8; j++) + for (k = 0; k < 8; k += 4) { + val = ((u32)scaling->scaling_list_8x8[i][j + (k + 3) * 8] << 24) | + ((u32)scaling->scaling_list_8x8[i][j + (k + 2) * 8] << 16) | + ((u32)scaling->scaling_list_8x8[i][j + (k + 1) * 8] << 8) | + scaling->scaling_list_8x8[i][j + k * 8]; + cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val); + } + + for (i = 0; i < 2; i++) + for (j = 0; j < 8; j++) + for (k = 0; k < 8; k += 4) { + val = ((u32)scaling->scaling_list_32x32[i][j + (k + 3) * 8] << 24) | + ((u32)scaling->scaling_list_32x32[i][j + (k + 2) * 8] << 16) | + ((u32)scaling->scaling_list_32x32[i][j + (k + 1) * 8] << 8) | + scaling->scaling_list_32x32[i][j + k * 8]; + cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val); + } + + for (i = 0; i < 6; i++) + for (j = 0; j < 8; j++) + for (k = 0; k < 8; k += 4) { + val = ((u32)scaling->scaling_list_16x16[i][j + (k + 3) * 8] << 24) | + ((u32)scaling->scaling_list_16x16[i][j + (k + 2) * 8] << 16) | + ((u32)scaling->scaling_list_16x16[i][j + (k + 1) * 8] << 8) | + scaling->scaling_list_16x16[i][j + k * 8]; + cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val); + } + + for (i = 0; i < 6; i++) + for (j = 0; j < 4; j++) { + val = ((u32)scaling->scaling_list_4x4[i][j + 12] << 24) | + ((u32)scaling->scaling_list_4x4[i][j + 8] << 16) | + ((u32)scaling->scaling_list_4x4[i][j + 4] << 8) | + scaling->scaling_list_4x4[i][j]; + cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val); + } +} + static void cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) { @@ -527,7 +590,12 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, /* Scaling list. */ - reg = VE_DEC_H265_SCALING_LIST_CTRL0_DEFAULT; + if (sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED) { + cedrus_h265_write_scaling_list(ctx, run); + reg = VE_DEC_H265_SCALING_LIST_CTRL0_FLAG_ENABLED; + } else { + reg = VE_DEC_H265_SCALING_LIST_CTRL0_DEFAULT; + } cedrus_write(dev, VE_DEC_H265_SCALING_LIST_CTRL0, reg); /* Neightbor information address. */ diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h index 92ace87c1c7d..bdb062ad8682 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h @@ -494,6 +494,8 @@ #define VE_DEC_H265_ENTRY_POINT_OFFSET_ADDR (VE_ENGINE_DEC_H265 + 0x64) #define VE_DEC_H265_TILE_START_CTB (VE_ENGINE_DEC_H265 + 0x68) #define VE_DEC_H265_TILE_END_CTB (VE_ENGINE_DEC_H265 + 0x6c) +#define VE_DEC_H265_SCALING_LIST_DC_COEF0 (VE_ENGINE_DEC_H265 + 0x78) +#define VE_DEC_H265_SCALING_LIST_DC_COEF1 (VE_ENGINE_DEC_H265 + 0x7c) #define VE_DEC_H265_LOW_ADDR (VE_ENGINE_DEC_H265 + 0x80) -- cgit v1.2.3 From 4787db29f8b67894ba6d68859653f477154c8600 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 29 Jul 2021 15:36:25 +0200 Subject: media: cedrus: drop min_buffers_needed. There is no reason for the cedrus driver to set min_buffers_needed. A non-zero min_buffers_needed can cause problems with the Request API if start_streaming fails when queueing a buffer from a request. Since it is not needed for this driver, just remove it. Signed-off-by: Hans Verkuil Cc: Paul Kocialkowski Reviewed-by: Ezequiel Garcia Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus_video.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index c589fe9dae70..f3cd452575d4 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -570,7 +570,6 @@ int cedrus_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->io_modes = VB2_MMAP | VB2_DMABUF; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct cedrus_buffer); - src_vq->min_buffers_needed = 1; src_vq->ops = &cedrus_qops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; @@ -587,7 +586,6 @@ int cedrus_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct cedrus_buffer); - dst_vq->min_buffers_needed = 1; dst_vq->ops = &cedrus_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; -- cgit v1.2.3 From b72dd0f390aa34da510a34bb3f8fbb8d6d38f678 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 29 Jul 2021 15:36:26 +0200 Subject: media: vivid: add module option to set request support mode Currently vivid supports the Request API, but it also sets min_buffers_needed in the vb2 queue. But the combination of support_requests and min_buffers_needed is not allowed due to the fact that vb2_core_qbuf() isn't supposed to fail when called from the request framework. And if min_buffers_needed > 0, then is can call start_streaming() which definitely can fail. With the new module option you can control if requests are not allowed (min_buffers_needed is 2 in that case), optionally allowed or are required. In the latter two cases min_buffers_needed is set to 0. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vivid/vivid-core.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index d2bd2653cf54..87f27c7524ec 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -177,6 +177,15 @@ MODULE_PARM_DESC(cache_hints, " user-space cache hints, default is 0.\n" "\t\t 0 == forbid\n" "\t\t 1 == allow"); +static unsigned int supports_requests[VIVID_MAX_DEVS] = { + [0 ... (VIVID_MAX_DEVS - 1)] = 1 +}; +module_param_array(supports_requests, uint, NULL, 0444); +MODULE_PARM_DESC(supports_requests, " support for requests, default is 1.\n" + "\t\t 0 == no support\n" + "\t\t 1 == supports requests\n" + "\t\t 2 == requires requests"); + static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS]; const struct v4l2_rect vivid_min_rect = { @@ -883,10 +892,11 @@ static int vivid_create_queue(struct vivid_dev *dev, q->mem_ops = allocators[dev->inst] == 1 ? &vb2_dma_contig_memops : &vb2_vmalloc_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = min_buffers_needed; + q->min_buffers_needed = supports_requests[dev->inst] ? 0 : min_buffers_needed; q->lock = &dev->mutex; q->dev = dev->v4l2_dev.dev; - q->supports_requests = true; + q->supports_requests = supports_requests[dev->inst]; + q->requires_requests = supports_requests[dev->inst] >= 2; q->allow_cache_hints = (cache_hints[dev->inst] == 1); return vb2_queue_init(q); -- cgit v1.2.3 From 9015fcc256d3a74d4fdc3d87877e270968550444 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 29 Jul 2021 15:36:27 +0200 Subject: media: videobuf2-core: sanity checks for requests and qbuf The combination of supports_requests == 1 and min_buffers_needed > 0 is not allowed, WARN on that and return an error. Also check that if vb2_core_qbuf() is called from req_queue, that it doesn't return an error, unless it is -EIO. Signed-off-by: Hans Verkuil Cc: Paul Kocialkowski Reviewed-by: Ezequiel Garcia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-core.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 508ac295eb06..38ce7c274727 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -1421,9 +1421,19 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, static void vb2_req_queue(struct media_request_object *obj) { struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj); + int err; mutex_lock(vb->vb2_queue->lock); - vb2_core_qbuf(vb->vb2_queue, vb->index, NULL, NULL); + /* + * There is no method to propagate an error from vb2_core_qbuf(), + * so if this returns a non-0 value, then WARN. + * + * The only exception is -EIO which is returned if q->error is + * set. We just ignore that, and expect this will be caught the + * next time vb2_req_prepare() is called. + */ + err = vb2_core_qbuf(vb->vb2_queue, vb->index, NULL, NULL); + WARN_ON_ONCE(err && err != -EIO); mutex_unlock(vb->vb2_queue->lock); } @@ -2342,6 +2352,17 @@ int vb2_core_queue_init(struct vb2_queue *q) if (WARN_ON(q->requires_requests && !q->supports_requests)) return -EINVAL; + /* + * This combination is not allowed since a non-zero value of + * q->min_buffers_needed can cause vb2_core_qbuf() to fail if + * it has to call start_streaming(), and the Request API expects + * that queueing a request (and thus queueing a buffer contained + * in that request) will always succeed. There is no method of + * propagating an error back to userspace. + */ + if (WARN_ON(q->supports_requests && q->min_buffers_needed)) + return -EINVAL; + INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); spin_lock_init(&q->done_lock); -- cgit v1.2.3 From 2c98b8a3458df03abdc6945bbef67ef91d181938 Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Thu, 29 Jul 2021 22:23:33 +0200 Subject: media: em28xx: add missing em28xx_close_extension If em28xx dev has ->dev_next pointer, we need to delete ->dev_next list node from em28xx_extension_devlist on disconnect to avoid UAF bugs and corrupted list bugs, since driver frees this pointer on disconnect. Reported-and-tested-by: syzbot+a6969ef522a36d3344c9@syzkaller.appspotmail.com Fixes: 1a23f81b7dc3 ("V4L/DVB (9979): em28xx: move usb probe code to a proper place") Signed-off-by: Pavel Skripkin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index c1e0dccb7408..948e22e29b42 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -4139,8 +4139,11 @@ static void em28xx_usb_disconnect(struct usb_interface *intf) em28xx_close_extension(dev); - if (dev->dev_next) + if (dev->dev_next) { + em28xx_close_extension(dev->dev_next); em28xx_release_resources(dev->dev_next); + } + em28xx_release_resources(dev); if (dev->dev_next) { -- cgit v1.2.3 From 8d246e293228881b557798416cb064d644cdb10e Mon Sep 17 00:00:00 2001 From: Krzysztof Hałasa Date: Fri, 30 Jul 2021 08:59:19 +0200 Subject: media: TDA1997x: fix tda1997x_remove() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TDA1997x driver tried to hold two values in a single variable: device's "client data" pointer was first set to "sd" in v4l2_i2c_subdev_init(), then it was overwritten explicitly using dev_set_drvdata() with "state". This caused tda1997x_remove() to fail badly. Signed-off-by: Krzysztof Hałasa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda1997x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 6070aaf0b32e..1e2a263be933 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -2450,7 +2450,8 @@ static const struct media_entity_operations tda1997x_media_ops = { static int tda1997x_pcm_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct tda1997x_state *state = snd_soc_dai_get_drvdata(dai); + struct v4l2_subdev *sd = snd_soc_dai_get_drvdata(dai); + struct tda1997x_state *state = to_state(sd); struct snd_soc_component *component = dai->component; struct snd_pcm_runtime *rtd = substream->runtime; int rate, err; @@ -2759,7 +2760,6 @@ static int tda1997x_probe(struct i2c_client *client, dev_err(&client->dev, "register audio codec failed\n"); goto err_free_media; } - dev_set_drvdata(&state->client->dev, state); v4l_info(state->client, "registered audio codec\n"); } -- cgit v1.2.3 From 4b9e3e8af4b336eefca1f1ee535bc4b6734ed6aa Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 30 Jul 2021 21:35:05 +0200 Subject: media: meson-ge2d: Fix rotation parameter changes detection in 'ge2d_s_ctrl()' There is likely a typo here. To be consistent, we should compare 'fmt.height' with 'ctx->out.pix_fmt.height', not 'ctx->out.pix_fmt.width'. Instead of fixing the test, just remove it and copy 'fmt' unconditionally. Fixes: 59a635327ca7 ("media: meson: Add M2M driver for the Amlogic GE2D Accelerator Unit") Signed-off-by: Christophe JAILLET Acked-by: Neil Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/meson/ge2d/ge2d.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/media/platform/meson/ge2d/ge2d.c b/drivers/media/platform/meson/ge2d/ge2d.c index a1393fefa8ae..9b1e973e78da 100644 --- a/drivers/media/platform/meson/ge2d/ge2d.c +++ b/drivers/media/platform/meson/ge2d/ge2d.c @@ -779,11 +779,7 @@ static int ge2d_s_ctrl(struct v4l2_ctrl *ctrl) * If the rotation parameter changes the OUTPUT frames * parameters, take them in account */ - if (fmt.width != ctx->out.pix_fmt.width || - fmt.height != ctx->out.pix_fmt.width || - fmt.bytesperline > ctx->out.pix_fmt.bytesperline || - fmt.sizeimage > ctx->out.pix_fmt.sizeimage) - ctx->out.pix_fmt = fmt; + ctx->out.pix_fmt = fmt; break; } -- cgit v1.2.3 From 4461a723ab7bb84d013b3de6cfc03fa52b0c20c3 Mon Sep 17 00:00:00 2001 From: Pete Hemery Date: Mon, 2 Aug 2021 14:26:20 +0200 Subject: media: gspca/sn9c20x: Add ability to control built-in webcam LEDs If you image search "microdia sonix webcam", or SN9C120, you can find examples of the type of webcam I have. It has 6 built-in LEDs. It's ancient (2006 maybe?) but in 2020 it was the only USB webcam I had. It doesn't perform well, especially in low light. The Windows XP drivers had the ability to toggle the LEDs, as well as "Auto" mode which would read and adjust the exposure and turn them on when it got "too dark", along with other nice features, like smoothing dead pixels, funky filters, effects and face tracking. Watching Wireshark usbmon with the Windows driver I was able to discover which values are required to toggle the LEDs. Reading ext-ctrls-flash.rst, V4L2_FLASH_LED_MODE_TORCH seems to describe mostly what I want it to do. Ideally the control would be boolean/checkbox, but the existing implementation seems to require a menu. This patch implements the ability to control the LEDs, attempting to minimise changes to external files and other webcams. Review by anyone more familiar with the code base for unintended side effects would be welcome and appreciated. First kernel submission. Signed-off-by: Pete Hemery Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/sn9c20x.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c index bfd194c61819..da916127a896 100644 --- a/drivers/media/usb/gspca/sn9c20x.c +++ b/drivers/media/usb/gspca/sn9c20x.c @@ -50,6 +50,7 @@ MODULE_LICENSE("GPL"); #define HAS_NO_BUTTON 0x1 #define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */ #define FLIP_DETECT 0x4 +#define HAS_LED_TORCH 0x8 /* specific webcam descriptor */ struct sd { @@ -77,6 +78,8 @@ struct sd { }; struct v4l2_ctrl *jpegqual; + struct v4l2_ctrl *led_mode; + struct work_struct work; u32 pktsz; /* (used by pkt_scan) */ @@ -1533,6 +1536,12 @@ static void set_gain(struct gspca_dev *gspca_dev, s32 g) i2c_w(gspca_dev, gain); } +static void set_led_mode(struct gspca_dev *gspca_dev, s32 val) +{ + reg_w1(gspca_dev, 0x1007, 0x60); + reg_w1(gspca_dev, 0x1006, val ? 0x40 : 0x00); +} + static void set_quality(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -1699,6 +1708,9 @@ static int sd_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_JPEG_COMPRESSION_QUALITY: set_quality(gspca_dev, ctrl->val); break; + case V4L2_CID_FLASH_LED_MODE: + set_led_mode(gspca_dev, ctrl->val); + break; } return gspca_dev->usb_err; } @@ -1757,6 +1769,12 @@ static int sd_init_controls(struct gspca_dev *gspca_dev) sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_JPEG_COMPRESSION_QUALITY, 50, 90, 1, 80); + + if (sd->flags & HAS_LED_TORCH) + sd->led_mode = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_FLASH_LED_MODE, V4L2_FLASH_LED_MODE_TORCH, + ~0x5, V4L2_FLASH_LED_MODE_NONE); + if (hdl->error) { pr_err("Could not initialize controls\n"); return hdl->error; @@ -2048,6 +2066,8 @@ static int sd_start(struct gspca_dev *gspca_dev) sd->pktsz = sd->npkt = 0; sd->nchg = 0; } + if (sd->led_mode) + v4l2_ctrl_s_ctrl(sd->led_mode, 0); return gspca_dev->usb_err; } @@ -2325,7 +2345,7 @@ static const struct sd_desc sd_desc = { static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)}, - {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)}, + {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, HAS_LED_TORCH)}, {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)}, {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)}, {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)}, -- cgit v1.2.3 From 97e6e701f3498aba8d21b576c3ffa4febe02abb8 Mon Sep 17 00:00:00 2001 From: Irui Wang Date: Wed, 30 Jun 2021 10:52:45 +0200 Subject: media: mtk-vcodec: Clean redundant encoder format definition The supported capture/output formats don't depend on models, clean redundant definitions and naming with type instead. Signed-off-by: Irui Wang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c | 50 +++++++++------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c index 45d1870c83dd..4489a9744cd7 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c @@ -26,7 +26,7 @@ module_param(mtk_v4l2_dbg_level, int, S_IRUGO | S_IWUSR); module_param(mtk_vcodec_dbg, bool, S_IRUGO | S_IWUSR); -static const struct mtk_video_fmt mtk_video_formats_output_mt8173[] = { +static const struct mtk_video_fmt mtk_video_formats_output[] = { { .fourcc = V4L2_PIX_FMT_NV12M, .type = MTK_FMT_FRAME, @@ -49,7 +49,7 @@ static const struct mtk_video_fmt mtk_video_formats_output_mt8173[] = { }, }; -static const struct mtk_video_fmt mtk_video_formats_capture_mt8173_avc[] = { +static const struct mtk_video_fmt mtk_video_formats_capture_h264[] = { { .fourcc = V4L2_PIX_FMT_H264, .type = MTK_FMT_ENC, @@ -57,7 +57,7 @@ static const struct mtk_video_fmt mtk_video_formats_capture_mt8173_avc[] = { }, }; -static const struct mtk_video_fmt mtk_video_formats_capture_mt8173_vp8[] = { +static const struct mtk_video_fmt mtk_video_formats_capture_vp8[] = { { .fourcc = V4L2_PIX_FMT_VP8, .type = MTK_FMT_ENC, @@ -65,14 +65,6 @@ static const struct mtk_video_fmt mtk_video_formats_capture_mt8173_vp8[] = { }, }; -static const struct mtk_video_fmt mtk_video_formats_capture_mt8183[] = { - { - .fourcc = V4L2_PIX_FMT_H264, - .type = MTK_FMT_ENC, - .num_planes = 1, - }, -}; - /* Wake up context wait_queue */ static void wake_up_ctx(struct mtk_vcodec_ctx *ctx, unsigned int reason) { @@ -392,10 +384,10 @@ err_enc_pm: static const struct mtk_vcodec_enc_pdata mt8173_avc_pdata = { .chip = MTK_MT8173, - .capture_formats = mtk_video_formats_capture_mt8173_avc, - .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8173_avc), - .output_formats = mtk_video_formats_output_mt8173, - .num_output_formats = ARRAY_SIZE(mtk_video_formats_output_mt8173), + .capture_formats = mtk_video_formats_capture_h264, + .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), + .output_formats = mtk_video_formats_output, + .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), .min_bitrate = 1, .max_bitrate = 4000000, .core_id = VENC_SYS, @@ -403,10 +395,10 @@ static const struct mtk_vcodec_enc_pdata mt8173_avc_pdata = { static const struct mtk_vcodec_enc_pdata mt8173_vp8_pdata = { .chip = MTK_MT8173, - .capture_formats = mtk_video_formats_capture_mt8173_vp8, - .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8173_vp8), - .output_formats = mtk_video_formats_output_mt8173, - .num_output_formats = ARRAY_SIZE(mtk_video_formats_output_mt8173), + .capture_formats = mtk_video_formats_capture_vp8, + .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_vp8), + .output_formats = mtk_video_formats_output, + .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), .min_bitrate = 64, .max_bitrate = 4000000, .core_id = VENC_LT_SYS, @@ -415,11 +407,10 @@ static const struct mtk_vcodec_enc_pdata mt8173_vp8_pdata = { static const struct mtk_vcodec_enc_pdata mt8183_pdata = { .chip = MTK_MT8183, .uses_ext = true, - .capture_formats = mtk_video_formats_capture_mt8183, - .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8183), - /* MT8183 supports the same output formats as MT8173 */ - .output_formats = mtk_video_formats_output_mt8173, - .num_output_formats = ARRAY_SIZE(mtk_video_formats_output_mt8173), + .capture_formats = mtk_video_formats_capture_h264, + .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), + .output_formats = mtk_video_formats_output, + .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), .min_bitrate = 64, .max_bitrate = 40000000, .core_id = VENC_SYS, @@ -428,16 +419,15 @@ static const struct mtk_vcodec_enc_pdata mt8183_pdata = { static const struct mtk_vcodec_enc_pdata mt8192_pdata = { .chip = MTK_MT8192, .uses_ext = true, - /* MT8192 supports the same capture formats as MT8183 */ - .capture_formats = mtk_video_formats_capture_mt8183, - .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8183), - /* MT8192 supports the same output formats as MT8173 */ - .output_formats = mtk_video_formats_output_mt8173, - .num_output_formats = ARRAY_SIZE(mtk_video_formats_output_mt8173), + .capture_formats = mtk_video_formats_capture_h264, + .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), + .output_formats = mtk_video_formats_output, + .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), .min_bitrate = 64, .max_bitrate = 100000000, .core_id = VENC_SYS, }; + static const struct of_device_id mtk_vcodec_enc_match[] = { {.compatible = "mediatek,mt8173-vcodec-enc", .data = &mt8173_avc_pdata}, -- cgit v1.2.3 From 1386801acc5b8df63ba36f79810947d95fab84e8 Mon Sep 17 00:00:00 2001 From: Irui Wang Date: Wed, 30 Jun 2021 10:52:46 +0200 Subject: media: dt-bindings: media: mtk-vcodec: Add binding for MT8195 VENC Updates binding document for mt8195 encoder driver. Signed-off-by: Irui Wang Acked-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/mediatek-vcodec.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt index ad1321e5a22d..de961699ba0a 100644 --- a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt +++ b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt @@ -10,6 +10,7 @@ Required properties: "mediatek,mt8183-vcodec-enc" for MT8183 encoder. "mediatek,mt8173-vcodec-dec" for MT8173 decoder. "mediatek,mt8192-vcodec-enc" for MT8192 encoder. + "mediatek,mt8195-vcodec-enc" for MT8195 encoder. - reg : Physical base address of the video codec registers and length of memory mapped region. - interrupts : interrupt number to the cpu. -- cgit v1.2.3 From 9be0352dae9ad8d7838d55c80d3b2e76c98fed87 Mon Sep 17 00:00:00 2001 From: Irui Wang Date: Wed, 30 Jun 2021 10:52:47 +0200 Subject: media: mtk-vcodec: Add MT8195 H264 venc driver Add MT8195 venc driver's compatible and device private data. Signed-off-by: Irui Wang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 1 + drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index c6c7672fecfb..3f83710b4fa5 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -304,6 +304,7 @@ enum mtk_chip { MTK_MT8173, MTK_MT8183, MTK_MT8192, + MTK_MT8195, }; /** diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c index 4489a9744cd7..7b3e0ea4c410 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c @@ -428,6 +428,18 @@ static const struct mtk_vcodec_enc_pdata mt8192_pdata = { .core_id = VENC_SYS, }; +static const struct mtk_vcodec_enc_pdata mt8195_pdata = { + .chip = MTK_MT8195, + .uses_ext = true, + .capture_formats = mtk_video_formats_capture_h264, + .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), + .output_formats = mtk_video_formats_output, + .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), + .min_bitrate = 64, + .max_bitrate = 100000000, + .core_id = VENC_SYS, +}; + static const struct of_device_id mtk_vcodec_enc_match[] = { {.compatible = "mediatek,mt8173-vcodec-enc", .data = &mt8173_avc_pdata}, @@ -435,6 +447,7 @@ static const struct of_device_id mtk_vcodec_enc_match[] = { .data = &mt8173_vp8_pdata}, {.compatible = "mediatek,mt8183-vcodec-enc", .data = &mt8183_pdata}, {.compatible = "mediatek,mt8192-vcodec-enc", .data = &mt8192_pdata}, + {.compatible = "mediatek,mt8195-vcodec-enc", .data = &mt8195_pdata}, {}, }; MODULE_DEVICE_TABLE(of, mtk_vcodec_enc_match); -- cgit v1.2.3 From b84f60a307f09debe30cc171b0f0a5c36797cf67 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 5 Aug 2021 04:47:49 +0200 Subject: media: Rename V4L2_PIX_FMT_SUNXI_TILED_NV12 to V4L2_PIX_FMT_NV12_32L32 The V4L2_PIX_FMT_SUNXI_TILED_NV12 format is actually a fairly common NV12 tiled format, with 32x32 linear tiles. Rename the format and move its documentation together with the other tiled NV12 formats. Keep V4L2_PIX_FMT_SUNXI_TILED_NV12 for application compatibility. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/pixfmt-reserved.rst | 14 -------------- .../userspace-api/media/v4l/pixfmt-yuv-planar.rst | 13 ++++++++++--- .../userspace-api/media/videodev2.h.rst.exceptions | 1 + drivers/media/v4l2-core/v4l2-ioctl.c | 2 +- drivers/staging/media/sunxi/cedrus/cedrus.c | 2 +- drivers/staging/media/sunxi/cedrus/cedrus_hw.c | 2 +- drivers/staging/media/sunxi/cedrus/cedrus_video.c | 4 ++-- include/uapi/linux/videodev2.h | 9 ++++++++- 8 files changed, 24 insertions(+), 23 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst index 0b879c0da713..e762f911737a 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst @@ -246,20 +246,6 @@ please make a proposal on the linux-media mailing list. It is an opaque intermediate format and the MDP hardware must be used to convert ``V4L2_PIX_FMT_MT21C`` to ``V4L2_PIX_FMT_NV12M``, ``V4L2_PIX_FMT_YUV420M`` or ``V4L2_PIX_FMT_YVU420``. - * .. _V4L2-PIX-FMT-SUNXI-TILED-NV12: - - - ``V4L2_PIX_FMT_SUNXI_TILED_NV12`` - - 'ST12' - - Two-planar NV12-based format used by the video engine found on Allwinner - (codenamed sunxi) platforms, with 32x32 tiles for the luminance plane - and 32x64 tiles for the chrominance plane. The data in each tile is - stored in linear order, within the tile bounds. Each tile follows the - previous one linearly in memory (from left to right, top to bottom). - - The associated buffer dimensions are aligned to match an integer number - of tiles, resulting in 32-aligned resolutions for the luminance plane - and 16-aligned resolutions for the chrominance plane (with 2x2 - subsampling). .. raw:: latex diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst index 090c091affd2..edeaf7628b28 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst @@ -254,14 +254,16 @@ of the luma plane. .. _V4L2-PIX-FMT-NV12MT: .. _V4L2-PIX-FMT-NV12MT-16X16: +.. _V4L2-PIX-FMT-NV12-32L32: -NV12MT and MV12MT_16X16 ------------------------ +Tiled NV12 +---------- Semi-planar YUV 4:2:0 formats, using macroblock tiling. The chroma plane is subsampled by 2 in each direction. Chroma lines contain half the number of pixels and the same number of bytes as luma lines, and the chroma plane -contains half the number of lines of the luma plane. +contains half the number of lines of the luma plane. Each tile follows the +previous one linearly in memory (from left to right, top to bottom). ``V4L2_PIX_FMT_NV12MT_16X16`` stores pixel in 2D 16x16 macroblocks, and stores macroblocks linearly in memory. The line stride and image height must be @@ -276,6 +278,11 @@ If the vertical resolution is an odd number of macroblocks, the last row of macroblocks is stored in linear order. The layouts of the luma and chroma planes are identical. +``V4L2_PIX_FMT_NV12_32L32`` stores pixel in 32x32 tiles, and stores +tiles linearly in memory. The line stride and image height must be +aligned to a multiple of 32. The layouts of the luma and chroma planes are +identical. + .. _nv12mt: .. kernel-figure:: nv12mt.svg diff --git a/Documentation/userspace-api/media/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions index 2217b56c2686..982675a2342e 100644 --- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions +++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions @@ -187,6 +187,7 @@ replace define V4L2_CAP_IO_MC device-capabilities # V4L2 pix flags replace define V4L2_PIX_FMT_PRIV_MAGIC :c:type:`v4l2_pix_format` replace define V4L2_PIX_FMT_FLAG_PREMUL_ALPHA format-flags +replace define V4L2_PIX_FMT_SUNXI_TILED_NV12 :c:type:`v4l2_pix_format` # V4L2 format flags replace define V4L2_FMT_FLAG_COMPRESSED fmtdesc-flags diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 05d5db3d85e5..ed194e9da7b0 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1282,6 +1282,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_NV61: descr = "Y/CrCb 4:2:2"; break; case V4L2_PIX_FMT_NV24: descr = "Y/CbCr 4:4:4"; break; case V4L2_PIX_FMT_NV42: descr = "Y/CrCb 4:4:4"; break; + case V4L2_PIX_FMT_NV12_32L32: descr = "Y/CbCr 4:2:0 (32x32 Linear)"; break; case V4L2_PIX_FMT_NV12M: descr = "Y/CbCr 4:2:0 (N-C)"; break; case V4L2_PIX_FMT_NV21M: descr = "Y/CrCb 4:2:0 (N-C)"; break; case V4L2_PIX_FMT_NV16M: descr = "Y/CbCr 4:2:2 (N-C)"; break; @@ -1415,7 +1416,6 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_SE401: descr = "GSPCA SE401"; break; case V4L2_PIX_FMT_S5C_UYVY_JPG: descr = "S5C73MX interleaved UYVY/JPEG"; break; case V4L2_PIX_FMT_MT21C: descr = "Mediatek Compressed Format"; break; - case V4L2_PIX_FMT_SUNXI_TILED_NV12: descr = "Sunxi Tiled NV12 Format"; break; default: if (fmt->description[0]) return; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 8114e2167013..144286920749 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -288,7 +288,7 @@ static int cedrus_open(struct file *file) ret = PTR_ERR(ctx->fh.m2m_ctx); goto err_ctrls; } - ctx->dst_fmt.pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12; + ctx->dst_fmt.pixelformat = V4L2_PIX_FMT_NV12_32L32; cedrus_prepare_format(&ctx->dst_fmt); ctx->src_fmt.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE; /* diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c index e2f2ff609c7e..2d7663726467 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c @@ -99,7 +99,7 @@ void cedrus_dst_format_set(struct cedrus_dev *dev, cedrus_write(dev, VE_PRIMARY_FB_LINE_STRIDE, reg); break; - case V4L2_PIX_FMT_SUNXI_TILED_NV12: + case V4L2_PIX_FMT_NV12_32L32: default: reg = VE_PRIMARY_OUT_FMT_TILED_32_NV12; cedrus_write(dev, VE_PRIMARY_OUT_FMT, reg); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index f3cd452575d4..ee7353086641 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -56,7 +56,7 @@ static struct cedrus_format cedrus_formats[] = { .capabilities = CEDRUS_CAPABILITY_VP8_DEC, }, { - .pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12, + .pixelformat = V4L2_PIX_FMT_NV12_32L32, .directions = CEDRUS_DECODE_DST, }, { @@ -124,7 +124,7 @@ void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) sizeimage = max_t(u32, SZ_1K, sizeimage); break; - case V4L2_PIX_FMT_SUNXI_TILED_NV12: + case V4L2_PIX_FMT_NV12_32L32: /* 32-aligned stride. */ bytesperline = ALIGN(width, 32); diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 9260791b8438..0188cd39468f 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -627,6 +627,9 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_YUV444M v4l2_fourcc('Y', 'M', '2', '4') /* 24 YUV444 planar */ #define V4L2_PIX_FMT_YVU444M v4l2_fourcc('Y', 'M', '4', '2') /* 24 YVU444 planar */ +/* Tiled YUV formats */ +#define V4L2_PIX_FMT_NV12_32L32 v4l2_fourcc('S', 'T', '1', '2') /* 12 Y/CbCr 4:2:0 32x32 tiles */ + /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */ #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */ #define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */ @@ -734,7 +737,6 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_Z16 v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */ #define V4L2_PIX_FMT_MT21C v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode */ #define V4L2_PIX_FMT_INZI v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */ -#define V4L2_PIX_FMT_SUNXI_TILED_NV12 v4l2_fourcc('S', 'T', '1', '2') /* Sunxi Tiled NV12 Format */ #define V4L2_PIX_FMT_CNF4 v4l2_fourcc('C', 'N', 'F', '4') /* Intel 4-bit packed depth confidence information */ #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* BTTV 8-bit dithered RGB */ @@ -2615,4 +2617,9 @@ struct v4l2_create_buffers { #define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */ +/* Deprecated definitions kept for backwards compatibility */ +#ifndef __KERNEL__ +#define V4L2_PIX_FMT_SUNXI_TILED_NV12 V4L2_PIX_FMT_NV12_32L32 +#endif + #endif /* _UAPI__LINUX_VIDEODEV2_H */ -- cgit v1.2.3 From 78eee7b5f110c9884c8ffd1dfcdd9c29296f3e43 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 5 Aug 2021 04:47:50 +0200 Subject: media: Rename V4L2_PIX_FMT_HM12 to V4L2_PIX_FMT_NV12_16L16 The V4L2_PIX_FMT_HM12 format is actually a simple NV12 tiled format, with 16x16 linear tiles. Rename the format and move its documentation together with the other tiled NV12 formats. Keep V4L2_PIX_FMT_HM12 for application compatibility. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/admin-guide/media/ivtv.rst | 2 +- Documentation/userspace-api/media/drivers/cx2341x-uapi.rst | 8 +++----- Documentation/userspace-api/media/v4l/pixfmt-reserved.rst | 8 -------- Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst | 6 ++++++ Documentation/userspace-api/media/videodev2.h.rst.exceptions | 1 + drivers/media/pci/cx18/cx18-ioctl.c | 4 ++-- drivers/media/pci/cx18/cx18-streams.c | 8 ++++---- drivers/media/pci/ivtv/ivtv-ioctl.c | 8 ++++---- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 10 +++++----- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h | 2 +- drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c | 2 +- drivers/media/v4l2-core/v4l2-ioctl.c | 2 +- include/uapi/linux/videodev2.h | 3 ++- 13 files changed, 31 insertions(+), 33 deletions(-) diff --git a/Documentation/admin-guide/media/ivtv.rst b/Documentation/admin-guide/media/ivtv.rst index 7b8775d20214..101f16d0263e 100644 --- a/Documentation/admin-guide/media/ivtv.rst +++ b/Documentation/admin-guide/media/ivtv.rst @@ -159,7 +159,7 @@ whatever). Otherwise the device numbers can get confusing. The ivtv Read-only The raw YUV video output from the current video input. The YUV format - is non-standard (V4L2_PIX_FMT_HM12). + is a 16x16 linear tiled NV12 format (V4L2_PIX_FMT_NV12_16L16) Note that the YUV and PCM streams are not synchronized, so they are of limited use. diff --git a/Documentation/userspace-api/media/drivers/cx2341x-uapi.rst b/Documentation/userspace-api/media/drivers/cx2341x-uapi.rst index 8a7977af79d5..debde65fb8cd 100644 --- a/Documentation/userspace-api/media/drivers/cx2341x-uapi.rst +++ b/Documentation/userspace-api/media/drivers/cx2341x-uapi.rst @@ -7,9 +7,7 @@ Non-compressed file format -------------------------- The cx23416 can produce (and the cx23415 can also read) raw YUV output. The -format of a YUV frame is specific to this chip and is called HM12. 'HM' stands -for 'Hauppauge Macroblock', which is a misnomer as 'Conexant Macroblock' would -be more accurate. +format of a YUV frame is 16x16 linear tiled NV12 (V4L2_PIX_FMT_NV12_16L16). The format is YUV 4:2:0 which uses 1 Y byte per pixel and 1 U and V byte per four pixels. @@ -34,8 +32,8 @@ second line of 8 UV pairs of the top-left block, etc. After transmitting this block the first line of the block on the right to the first block is transmitted, etc. -The code below is given as an example on how to convert HM12 to separate -Y, U and V planes. This code assumes frames of 720x576 (PAL) pixels. +The code below is given as an example on how to convert V4L2_PIX_FMT_NV12_16L16 +to separate Y, U and V planes. This code assumes frames of 720x576 (PAL) pixels. The width of a frame is always 720 pixels, regardless of the actual specified width. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst index e762f911737a..adcad9454175 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst @@ -48,14 +48,6 @@ please make a proposal on the linux-media mailing list. - ``V4L2_PIX_FMT_HI240`` - 'HI24' - 8 bit RGB format used by the BTTV driver. - * .. _V4L2-PIX-FMT-HM12: - - - ``V4L2_PIX_FMT_HM12`` - - 'HM12' - - YUV 4:2:0 format used by the IVTV driver. - - The format is documented in the kernel sources in the file - ``Documentation/userspace-api/media/drivers/cx2341x-uapi.rst`` * .. _V4L2-PIX-FMT-CPIA1: - ``V4L2_PIX_FMT_CPIA1`` diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst index edeaf7628b28..884828f2272c 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst @@ -254,6 +254,7 @@ of the luma plane. .. _V4L2-PIX-FMT-NV12MT: .. _V4L2-PIX-FMT-NV12MT-16X16: +.. _V4L2-PIX-FMT-NV12-16L16: .. _V4L2-PIX-FMT-NV12-32L32: Tiled NV12 @@ -278,6 +279,11 @@ If the vertical resolution is an odd number of macroblocks, the last row of macroblocks is stored in linear order. The layouts of the luma and chroma planes are identical. +``V4L2_PIX_FMT_NV12_16L16`` stores pixel in 16x16 tiles, and stores +tiles linearly in memory. The line stride and image height must be +aligned to a multiple of 16. The layouts of the luma and chroma planes are +identical. + ``V4L2_PIX_FMT_NV12_32L32`` stores pixel in 32x32 tiles, and stores tiles linearly in memory. The line stride and image height must be aligned to a multiple of 32. The layouts of the luma and chroma planes are diff --git a/Documentation/userspace-api/media/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions index 982675a2342e..eb0b1cd37abd 100644 --- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions +++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions @@ -187,6 +187,7 @@ replace define V4L2_CAP_IO_MC device-capabilities # V4L2 pix flags replace define V4L2_PIX_FMT_PRIV_MAGIC :c:type:`v4l2_pix_format` replace define V4L2_PIX_FMT_FLAG_PREMUL_ALPHA format-flags +replace define V4L2_PIX_FMT_HM12 :c:type:`v4l2_pix_format` replace define V4L2_PIX_FMT_SUNXI_TILED_NV12 :c:type:`v4l2_pix_format` # V4L2 format flags diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 4864def20676..ce3f0141f94e 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -276,7 +276,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, s->pixelformat = fmt->fmt.pix.pixelformat; /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ - if (s->pixelformat == V4L2_PIX_FMT_HM12) { + if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16) { s->vb_bytes_per_frame = h * 720 * 3 / 2; s->vb_bytes_per_line = 720; /* First plane */ } else { @@ -470,7 +470,7 @@ static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, .index = 0, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .description = "HM12 (YUV 4:1:1)", - .pixelformat = V4L2_PIX_FMT_HM12, + .pixelformat = V4L2_PIX_FMT_NV12_16L16, }, { .index = 1, diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index c41bae118415..16d37ab48906 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -133,7 +133,7 @@ static int cx18_prepare_buffer(struct videobuf_queue *q, /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ - if (s->pixelformat == V4L2_PIX_FMT_HM12) + if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16) s->vb_bytes_per_frame = height * 720 * 3 / 2; else s->vb_bytes_per_frame = height * 720 * 2; @@ -155,7 +155,7 @@ static int cx18_prepare_buffer(struct videobuf_queue *q, /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ - if (s->pixelformat == V4L2_PIX_FMT_HM12) + if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16) s->vb_bytes_per_frame = height * 720 * 3 / 2; else s->vb_bytes_per_frame = height * 720 * 2; @@ -287,7 +287,7 @@ static void cx18_stream_init(struct cx18 *cx, int type) s, &cx->serialize_lock); /* Assume the previous pixel default */ - s->pixelformat = V4L2_PIX_FMT_HM12; + s->pixelformat = V4L2_PIX_FMT_NV12_16L16; s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2; s->vb_bytes_per_line = 720; } @@ -733,7 +733,7 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s) * Set the MDL size to the exact size needed for one frame. * Use enough buffers per MDL to cover the MDL size */ - if (s->pixelformat == V4L2_PIX_FMT_HM12) + if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16) s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2; else s->mdl_size = 720 * s->cx->cxhdl.height * 2; diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index da19b2e95e6c..0cdf6b3210c2 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -339,7 +339,7 @@ static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; pixfmt->field = V4L2_FIELD_INTERLACED; if (id->type == IVTV_ENC_STREAM_TYPE_YUV) { - pixfmt->pixelformat = V4L2_PIX_FMT_HM12; + pixfmt->pixelformat = V4L2_PIX_FMT_NV12_16L16; /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */ pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; pixfmt->bytesperline = 720; @@ -417,7 +417,7 @@ static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f pixfmt->field = V4L2_FIELD_ANY; break; } - pixfmt->pixelformat = V4L2_PIX_FMT_HM12; + pixfmt->pixelformat = V4L2_PIX_FMT_NV12_16L16; pixfmt->bytesperline = 720; pixfmt->width = itv->yuv_info.v4l2_src_w; pixfmt->height = itv->yuv_info.v4l2_src_h; @@ -917,7 +917,7 @@ static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdes static const struct v4l2_fmtdesc hm12 = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .description = "HM12 (YUV 4:2:0)", - .pixelformat = V4L2_PIX_FMT_HM12, + .pixelformat = V4L2_PIX_FMT_NV12_16L16, }; static const struct v4l2_fmtdesc mpeg = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, @@ -944,7 +944,7 @@ static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdes static const struct v4l2_fmtdesc hm12 = { .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, .description = "HM12 (YUV 4:2:0)", - .pixelformat = V4L2_PIX_FMT_HM12, + .pixelformat = V4L2_PIX_FMT_NV12_16L16, }; static const struct v4l2_fmtdesc mpeg = { .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 08df0c833423..4b8d66fec3cf 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -61,7 +61,7 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, || sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_BT656) && sdev->csi.v4l2_ep.bus.parallel.bus_width == 16) { switch (pixformat) { - case V4L2_PIX_FMT_HM12: + case V4L2_PIX_FMT_NV12_16L16: case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV16: @@ -124,7 +124,7 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, case V4L2_PIX_FMT_VYUY: return (mbus_code == MEDIA_BUS_FMT_VYUY8_2X8); - case V4L2_PIX_FMT_HM12: + case V4L2_PIX_FMT_NV12_16L16: case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV16: @@ -269,7 +269,7 @@ static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev, case V4L2_PIX_FMT_VYUY: return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; - case V4L2_PIX_FMT_HM12: + case V4L2_PIX_FMT_NV12_16L16: return buf_interlaced ? CSI_FRAME_MB_YUV420 : CSI_FIELD_MB_YUV420; case V4L2_PIX_FMT_NV12: @@ -311,7 +311,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, return 0; switch (pixformat) { - case V4L2_PIX_FMT_HM12: + case V4L2_PIX_FMT_NV12_16L16: case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_YUV420: @@ -526,7 +526,7 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) planar_offset[0] = 0; switch (config->pixelformat) { - case V4L2_PIX_FMT_HM12: + case V4L2_PIX_FMT_NV12_16L16: case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV16: diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index c626821aaedb..3a38d107ae3f 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -105,7 +105,7 @@ static inline int sun6i_csi_get_bpp(unsigned int pixformat) case V4L2_PIX_FMT_SGBRG12: case V4L2_PIX_FMT_SGRBG12: case V4L2_PIX_FMT_SRGGB12: - case V4L2_PIX_FMT_HM12: + case V4L2_PIX_FMT_NV12_16L16: case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_YUV420: diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 07b2161392d2..33459892c1a9 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -48,7 +48,7 @@ static const u32 supported_pixformats[] = { V4L2_PIX_FMT_YVYU, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_VYUY, - V4L2_PIX_FMT_HM12, + V4L2_PIX_FMT_NV12_16L16, V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV21, V4L2_PIX_FMT_YUV420, diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index ed194e9da7b0..8731d65ad39e 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1274,7 +1274,6 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_YUV410: descr = "Planar YUV 4:1:0"; break; case V4L2_PIX_FMT_YUV420: descr = "Planar YUV 4:2:0"; break; case V4L2_PIX_FMT_HI240: descr = "8-bit Dithered RGB (BTTV)"; break; - case V4L2_PIX_FMT_HM12: descr = "YUV 4:2:0 (16x16 Macroblocks)"; break; case V4L2_PIX_FMT_M420: descr = "YUV 4:2:0 (M420)"; break; case V4L2_PIX_FMT_NV12: descr = "Y/CbCr 4:2:0"; break; case V4L2_PIX_FMT_NV21: descr = "Y/CrCb 4:2:0"; break; @@ -1282,6 +1281,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_NV61: descr = "Y/CrCb 4:2:2"; break; case V4L2_PIX_FMT_NV24: descr = "Y/CbCr 4:4:4"; break; case V4L2_PIX_FMT_NV42: descr = "Y/CrCb 4:4:4"; break; + case V4L2_PIX_FMT_NV12_16L16: descr = "Y/CbCr 4:2:0 (16x16 Linear)"; break; case V4L2_PIX_FMT_NV12_32L32: descr = "Y/CbCr 4:2:0 (32x32 Linear)"; break; case V4L2_PIX_FMT_NV12M: descr = "Y/CbCr 4:2:0 (N-C)"; break; case V4L2_PIX_FMT_NV21M: descr = "Y/CrCb 4:2:0 (N-C)"; break; diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 0188cd39468f..40fec00ce73a 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -601,7 +601,6 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */ #define V4L2_PIX_FMT_NV24 v4l2_fourcc('N', 'V', '2', '4') /* 24 Y/CbCr 4:4:4 */ #define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */ -#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */ /* two non contiguous planes - one Y, one Cr + Cb interleaved */ #define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ @@ -628,6 +627,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_YVU444M v4l2_fourcc('Y', 'M', '4', '2') /* 24 YVU444 planar */ /* Tiled YUV formats */ +#define V4L2_PIX_FMT_NV12_16L16 v4l2_fourcc('H', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 16x16 tiles */ #define V4L2_PIX_FMT_NV12_32L32 v4l2_fourcc('S', 'T', '1', '2') /* 12 Y/CbCr 4:2:0 32x32 tiles */ /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */ @@ -2619,6 +2619,7 @@ struct v4l2_create_buffers { /* Deprecated definitions kept for backwards compatibility */ #ifndef __KERNEL__ +#define V4L2_PIX_FMT_HM12 V4L2_PIX_FMT_NV12_16L16 #define V4L2_PIX_FMT_SUNXI_TILED_NV12 V4L2_PIX_FMT_NV12_32L32 #endif -- cgit v1.2.3 From 683f71ebb35d9223b4a22488e2eaffac30af104d Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 5 Aug 2021 04:47:51 +0200 Subject: media: Add NV12_4L4 tiled format This format is produced by VeriSilicon Hantro G2 and VC8000D cores. It is a simple 4x4 tiling layout in a linear way. The pixel format was introduced by GStreamer using FourCC VT12, so let's stick to it. Link: https://gstreamer.freedesktop.org/documentation/video/video-format.html Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst | 6 ++++++ drivers/media/v4l2-core/v4l2-common.c | 3 +++ drivers/media/v4l2-core/v4l2-ioctl.c | 1 + include/uapi/linux/videodev2.h | 1 + 4 files changed, 11 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst index 884828f2272c..0fc74351605a 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst @@ -254,6 +254,7 @@ of the luma plane. .. _V4L2-PIX-FMT-NV12MT: .. _V4L2-PIX-FMT-NV12MT-16X16: +.. _V4L2-PIX-FMT-NV12-4L4: .. _V4L2-PIX-FMT-NV12-16L16: .. _V4L2-PIX-FMT-NV12-32L32: @@ -279,6 +280,11 @@ If the vertical resolution is an odd number of macroblocks, the last row of macroblocks is stored in linear order. The layouts of the luma and chroma planes are identical. +``V4L2_PIX_FMT_NV12_4L4`` stores pixel in 4x4 tiles, and stores +tiles linearly in memory. The line stride and image height must be +aligned to a multiple of 4. The layouts of the luma and chroma planes are +identical. + ``V4L2_PIX_FMT_NV12_16L16`` stores pixel in 16x16 tiles, and stores tiles linearly in memory. The line stride and image height must be aligned to a multiple of 16. The layouts of the luma and chroma planes are diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 04af03285a20..df34b2a283bc 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -275,6 +275,9 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) { .format = V4L2_PIX_FMT_YUV422P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, { .format = V4L2_PIX_FMT_GREY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + /* Tiled YUV formats */ + { .format = V4L2_PIX_FMT_NV12_4L4, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + /* YUV planar formats, non contiguous variant */ { .format = V4L2_PIX_FMT_YUV420M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, { .format = V4L2_PIX_FMT_YVU420M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 8731d65ad39e..ec6fc1ef291e 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1281,6 +1281,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_NV61: descr = "Y/CrCb 4:2:2"; break; case V4L2_PIX_FMT_NV24: descr = "Y/CbCr 4:4:4"; break; case V4L2_PIX_FMT_NV42: descr = "Y/CrCb 4:4:4"; break; + case V4L2_PIX_FMT_NV12_4L4: descr = "Y/CbCr 4:2:0 (4x4 Linear)"; break; case V4L2_PIX_FMT_NV12_16L16: descr = "Y/CbCr 4:2:0 (16x16 Linear)"; break; case V4L2_PIX_FMT_NV12_32L32: descr = "Y/CbCr 4:2:0 (32x32 Linear)"; break; case V4L2_PIX_FMT_NV12M: descr = "Y/CbCr 4:2:0 (N-C)"; break; diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 40fec00ce73a..56003a5467fc 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -627,6 +627,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_YVU444M v4l2_fourcc('Y', 'M', '4', '2') /* 24 YVU444 planar */ /* Tiled YUV formats */ +#define V4L2_PIX_FMT_NV12_4L4 v4l2_fourcc('V', 'T', '1', '2') /* 12 Y/CbCr 4:2:0 4x4 tiles */ #define V4L2_PIX_FMT_NV12_16L16 v4l2_fourcc('H', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 16x16 tiles */ #define V4L2_PIX_FMT_NV12_32L32 v4l2_fourcc('S', 'T', '1', '2') /* 12 Y/CbCr 4:2:0 32x32 tiles */ -- cgit v1.2.3 From 75b8f8f2646ccaf085a87983329be8e47bd8b6bc Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 5 Aug 2021 04:47:52 +0200 Subject: media: Clean V4L2_PIX_FMT_NV12MT documentation Add more information about V4L2_PIX_FMT_NV12MT and V4L2_PIX_FMT_NV12M_16X16, so it's clearer for driver authors and users. Also, group the two pixel formats with the other tiled formats, for clarity. Unlike the recently introduced tiled formats (V4L2_PIX_FMT_NV12_4L4, etc) these formats have remained Samsung-specific until now. Therefore, and although the NV12MT and NV12MT_16X16 nomenclatures are less clear, we are keeping them as-is. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-yuv-planar.rst | 25 +++++++++++----------- include/uapi/linux/videodev2.h | 6 ++++-- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst index 0fc74351605a..3a09d93d405b 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst @@ -99,7 +99,7 @@ All components are stored with the same number of bits per component. - 4:2:0 - Cb, Cr - No - - 64x32 macroblocks + - 64x32 tiles Horizontal Z order * - V4L2_PIX_FMT_NV12MT_16X16 @@ -108,7 +108,7 @@ All components are stored with the same number of bits per component. - 4:2:2 - Cb, Cr - No - - 16x16 macroblocks + - 16x16 tiles * - V4L2_PIX_FMT_NV16 - 'NV16' - 8 @@ -267,17 +267,18 @@ pixels and the same number of bytes as luma lines, and the chroma plane contains half the number of lines of the luma plane. Each tile follows the previous one linearly in memory (from left to right, top to bottom). -``V4L2_PIX_FMT_NV12MT_16X16`` stores pixel in 2D 16x16 macroblocks, and stores -macroblocks linearly in memory. The line stride and image height must be -aligned to a multiple of 16. The layouts of the luma and chroma planes are -identical. +``V4L2_PIX_FMT_NV12MT_16X16`` is similar to ``V4L2_PIX_FMT_NV12M`` but stores +pixels in 2D 16x16 tiles, and stores tiles linearly in memory. +The line stride and image height must be aligned to a multiple of 16. +The layouts of the luma and chroma planes are identical. -``V4L2_PIX_FMT_NV12MT`` stores pixels in 2D 64x32 macroblocks, and stores 2x2 -groups of macroblocks in Z-order in memory, alternating Z and mirrored Z shapes -horizontally. The line stride must be a multiple of 128 pixels to ensure an +``V4L2_PIX_FMT_NV12MT`` is similar to ``V4L2_PIX_FMT_NV12M`` but stores +pixels in 2D 64x32 tiles, and stores 2x2 groups of tiles in +Z-order in memory, alternating Z and mirrored Z shapes horizontally. +The line stride must be a multiple of 128 pixels to ensure an integer number of Z shapes. The image height must be a multiple of 32 pixels. -If the vertical resolution is an odd number of macroblocks, the last row of -macroblocks is stored in linear order. The layouts of the luma and chroma +If the vertical resolution is an odd number of tiles, the last row of +tiles is stored in linear order. The layouts of the luma and chroma planes are identical. ``V4L2_PIX_FMT_NV12_4L4`` stores pixel in 4x4 tiles, and stores @@ -309,7 +310,7 @@ identical. :alt: nv12mt_example.svg :align: center - Example V4L2_PIX_FMT_NV12MT memory layout of macroblocks + Example V4L2_PIX_FMT_NV12MT memory layout of tiles .. _V4L2-PIX-FMT-NV16: diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 56003a5467fc..58392dcd3bf5 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -607,8 +607,6 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_NV21M v4l2_fourcc('N', 'M', '2', '1') /* 21 Y/CrCb 4:2:0 */ #define V4L2_PIX_FMT_NV16M v4l2_fourcc('N', 'M', '1', '6') /* 16 Y/CbCr 4:2:2 */ #define V4L2_PIX_FMT_NV61M v4l2_fourcc('N', 'M', '6', '1') /* 16 Y/CrCb 4:2:2 */ -#define V4L2_PIX_FMT_NV12MT v4l2_fourcc('T', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 macroblocks */ -#define V4L2_PIX_FMT_NV12MT_16X16 v4l2_fourcc('V', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 16x16 macroblocks */ /* three planes - Y Cb, Cr */ #define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y', 'U', 'V', '9') /* 9 YUV 4:1:0 */ @@ -631,6 +629,10 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_NV12_16L16 v4l2_fourcc('H', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 16x16 tiles */ #define V4L2_PIX_FMT_NV12_32L32 v4l2_fourcc('S', 'T', '1', '2') /* 12 Y/CbCr 4:2:0 32x32 tiles */ +/* Tiled YUV formats, non contiguous planes */ +#define V4L2_PIX_FMT_NV12MT v4l2_fourcc('T', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 tiles */ +#define V4L2_PIX_FMT_NV12MT_16X16 v4l2_fourcc('V', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 16x16 tiles */ + /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */ #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */ #define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */ -- cgit v1.2.3 From e6d025d880f43d45d9f185d50b59936804457bcf Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 3 Aug 2021 11:03:30 +0200 Subject: media: mceusb: ensure rx resolution can be retrieved The receiver resolution is not populated. The resolution can be used to for various purposes like calculating the margins the decoder should use. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index e03dd1f0144f..28bf78ff246a 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1612,6 +1612,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->dev.parent = dev; rc->priv = ir; rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + rc->rx_resolution = MCE_TIME_UNIT; rc->min_timeout = MCE_TIME_UNIT; rc->timeout = MS_TO_US(100); if (!mceusb_model[ir->model].broken_irtimeout) { -- cgit v1.2.3 From 8dcea1d60858fbb22d563b7618d4160f9191d3d5 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 3 Aug 2021 11:19:54 +0200 Subject: media: streamzap: ensure rx resolution can be retrieved The receiver resolution is not populated. The resolution can be used to for various purposes like calculating the margins the decoder should use. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/streamzap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index 9cd765e31c49..1cc5ebb85b6c 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -293,6 +293,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz) rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rdev->driver_name = DRIVER_NAME; rdev->map_name = RC_MAP_STREAMZAP; + rdev->rx_resolution = SZ_RESOLUTION; ret = rc_register_device(rdev); if (ret < 0) { -- cgit v1.2.3 From 11b982e950d2138e90bd120501df10a439006ff8 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 20 Jul 2021 18:07:49 +0200 Subject: media: cxd2880-spi: Fix a null pointer dereference on error handling path Currently the null pointer check on dvb_spi->vcc_supply is inverted and this leads to only null values of the dvb_spi->vcc_supply being passed to the call of regulator_disable causing null pointer dereferences. Fix this by only calling regulator_disable if dvb_spi->vcc_supply is not null. Addresses-Coverity: ("Dereference after null check") Fixes: dcb014582101 ("media: cxd2880-spi: Fix an error handling path") Signed-off-by: Colin Ian King Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/spi/cxd2880-spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c index b91a1e845b97..506f52c1af10 100644 --- a/drivers/media/spi/cxd2880-spi.c +++ b/drivers/media/spi/cxd2880-spi.c @@ -618,7 +618,7 @@ fail_frontend: fail_attach: dvb_unregister_adapter(&dvb_spi->adapter); fail_adapter: - if (!dvb_spi->vcc_supply) + if (dvb_spi->vcc_supply) regulator_disable(dvb_spi->vcc_supply); fail_regulator: kfree(dvb_spi); -- cgit v1.2.3 From 36b9d695aa6fb8e9a312db21af41f90824d16ab4 Mon Sep 17 00:00:00 2001 From: Evgeny Novikov Date: Tue, 20 Jul 2021 11:28:27 +0200 Subject: media: ttusb-dec: avoid release of non-acquired mutex ttusb_dec_send_command() invokes mutex_lock_interruptible() that can fail but then it releases the non-acquired mutex. The patch fixes that. Found by Linux Driver Verification project (linuxtesting.org). Fixes: dba328bab4c6 ("media: ttusb-dec: cleanup an error handling logic") Signed-off-by: Evgeny Novikov Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/ttusb-dec/ttusb_dec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index bfda46a36dc5..38822cedd93a 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -327,7 +327,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, result = mutex_lock_interruptible(&dec->usb_mutex); if (result) { printk("%s: Failed to lock usb mutex.\n", __func__); - goto err; + goto err_free; } b[0] = 0xaa; @@ -349,7 +349,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, if (result) { printk("%s: command bulk message failed: error %d\n", __func__, result); - goto err; + goto err_mutex_unlock; } result = usb_bulk_msg(dec->udev, dec->result_pipe, b, @@ -358,7 +358,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, if (result) { printk("%s: result bulk message failed: error %d\n", __func__, result); - goto err; + goto err_mutex_unlock; } else { if (debug) { printk(KERN_DEBUG "%s: result: %*ph\n", @@ -371,9 +371,9 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, memcpy(cmd_result, &b[4], b[3]); } -err: +err_mutex_unlock: mutex_unlock(&dec->usb_mutex); - +err_free: kfree(b); return result; } -- cgit v1.2.3 From 2eecd3596ede95caf9b26c1ea9b884eac2216fbc Mon Sep 17 00:00:00 2001 From: lijian Date: Wed, 16 Jun 2021 05:43:33 +0200 Subject: media: tuners: mxl5007t: Removed unnecessary 'return' Removed unnecessary 'return'. Signed-off-by: lijian Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/mxl5007t.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/media/tuners/mxl5007t.c b/drivers/media/tuners/mxl5007t.c index 26a277975cb1..03c46a62bf26 100644 --- a/drivers/media/tuners/mxl5007t.c +++ b/drivers/media/tuners/mxl5007t.c @@ -172,7 +172,6 @@ static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val) i++; } - return; } static void copy_reg_bits(struct reg_pair_t *reg_pair1, @@ -193,7 +192,6 @@ static void copy_reg_bits(struct reg_pair_t *reg_pair1, } i++; } - return; } /* ------------------------------------------------------------------------- */ @@ -221,7 +219,6 @@ static void mxl5007t_set_mode_bits(struct mxl5007t_state *state, default: mxl_fail(-EINVAL); } - return; } static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, @@ -274,8 +271,6 @@ static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00); state->if_freq = if_freq; - - return; } static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state, @@ -343,8 +338,6 @@ static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state, mxl_fail(-EINVAL); return; } - - return; } static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state, @@ -398,8 +391,6 @@ static void mxl5007t_set_bw_bits(struct mxl5007t_state *state, return; } set_reg_bits(state->tab_rftune, 0x0c, 0x3f, val); - - return; } static struct -- cgit v1.2.3 From a5694cb73ad7b82b05444e8a76cdb32a3f247f76 Mon Sep 17 00:00:00 2001 From: Hirokazu Honda Date: Fri, 6 Aug 2021 06:15:17 +0200 Subject: media: mtk-vcodec: vdec: Support H264 profile control Add H264 profiles supported by the MediaTek 8173 decoder. [acourbot: fix commit log a bit, move to mtk_vcodec_dec.c] Signed-off-by: Hirokazu Honda Signed-off-by: Alexandre Courbot Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 56d86e59421e..8df8bcfe5e9c 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -1421,6 +1421,16 @@ int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx) V4L2_CID_MPEG_VIDEO_VP9_PROFILE, V4L2_MPEG_VIDEO_VP9_PROFILE_0, 0, V4L2_MPEG_VIDEO_VP9_PROFILE_0); + /* + * H264. Baseline / Extended decoding is not supported. + */ + v4l2_ctrl_new_std_menu(&ctx->ctrl_hdl, + &mtk_vcodec_dec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED), + V4L2_MPEG_VIDEO_H264_PROFILE_MAIN); if (ctx->ctrl_hdl.error) { mtk_v4l2_err("Adding control failed %d", -- cgit v1.2.3 From 61a76141beece86017656a69bedabc8c2f2d3717 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 6 Aug 2021 06:15:18 +0200 Subject: media: mtk-vcodec: vdec: use helpers in VIDIOC_(TRY_)DECODER_CMD Let's use the dedicated helpers to make sure we get the expected behavior and remove redundant code. Signed-off-by: Alexandre Courbot Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 8df8bcfe5e9c..1a633b485a69 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -484,18 +484,7 @@ static void mtk_vdec_worker(struct work_struct *work) static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - switch (cmd->cmd) { - case V4L2_DEC_CMD_STOP: - case V4L2_DEC_CMD_START: - if (cmd->flags != 0) { - mtk_v4l2_err("cmd->flags=%u", cmd->flags); - return -EINVAL; - } - break; - default: - return -EINVAL; - } - return 0; + return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd); } -- cgit v1.2.3 From 25e7f7d3c483dc91a1d5ea008c9ff14b72fb5050 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 6 Aug 2021 06:15:19 +0200 Subject: media: mtk-vcodec: vdec: clamp OUTPUT resolution to hardware limits Calling S_FMT or TRY_FMT on the OUTPUT queue should adjust the resolution to the limits supported by the hardware. Until now this was only done on the CAPTURE queue, which could make clients believe that unsupported resolutions can be used when they set the coded size on the OUTPUT queue. In the case of the stateless decoder, the problem was even bigger since subsequently calling G_FMT on the CAPTURE queue would result in the unclamped resolution being returned, further inducing the client into error. Signed-off-by: Alexandre Courbot Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 1a633b485a69..16e057f73789 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -649,19 +649,17 @@ static int vidioc_try_fmt(struct v4l2_format *f, pix_fmt_mp->field = V4L2_FIELD_NONE; + pix_fmt_mp->width = + clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, MTK_VDEC_MAX_W); + pix_fmt_mp->height = + clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, MTK_VDEC_MAX_H); + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { pix_fmt_mp->num_planes = 1; pix_fmt_mp->plane_fmt[0].bytesperline = 0; } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { int tmp_w, tmp_h; - pix_fmt_mp->height = clamp(pix_fmt_mp->height, - MTK_VDEC_MIN_H, - MTK_VDEC_MAX_H); - pix_fmt_mp->width = clamp(pix_fmt_mp->width, - MTK_VDEC_MIN_W, - MTK_VDEC_MAX_W); - /* * Find next closer width align 64, heign align 64, size align * 64 rectangle -- cgit v1.2.3 From 69466c22f51bb0085ed886f5a5b3db7368245872 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 6 Aug 2021 06:15:20 +0200 Subject: media: mtk-vcodec: make flush buffer reusable by encoder The flush buffer is a special buffer that tells the decoder driver to send an empty CAPTURE frame to the client with V4L2_BUF_FLAG_LAST set. We need similar functionality for the encoder ; however currently the flush buffer depends on decoder-specific structures and thus cannot be reused with the encoder. Fix this by testing for this buffer by its VB2 address, and not through a dedicated flag stored in a higher-level decoder structure. This also allows us to remove said flag and simplify the code a bit. Since the flush buffer should never be used in the stateless decoder, also add safeguards to check against it. Signed-off-by: Alexandre Courbot Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 24 ++++++++++------------ drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h | 2 -- .../media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 12 +---------- drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 6 ++++-- 4 files changed, 16 insertions(+), 28 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 16e057f73789..7edd6266dc6a 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -368,8 +368,6 @@ static void mtk_vdec_worker(struct work_struct *work) return; } - src_buf_info = container_of(src_buf, struct mtk_video_dec_buf, - m2m_buf.vb); dst_buf_info = container_of(dst_buf, struct mtk_video_dec_buf, m2m_buf.vb); @@ -390,7 +388,7 @@ static void mtk_vdec_worker(struct work_struct *work) pfb->base_y.va, &pfb->base_y.dma_addr, &pfb->base_c.dma_addr, pfb->base_y.size); - if (src_buf_info->lastframe) { + if (src_buf == &ctx->empty_flush_buf.vb) { mtk_v4l2_debug(1, "Got empty flush input buffer."); src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); @@ -411,6 +409,10 @@ static void mtk_vdec_worker(struct work_struct *work) v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); return; } + + src_buf_info = container_of(src_buf, struct mtk_video_dec_buf, + m2m_buf.vb); + buf.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); buf.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); buf.size = (size_t)src_buf->vb2_buf.planes[0].bytesused; @@ -514,8 +516,7 @@ static int vidioc_decoder_cmd(struct file *file, void *priv, mtk_v4l2_debug(1, "Capture stream is off. No need to flush."); return 0; } - v4l2_m2m_buf_queue(ctx->m2m_ctx, - &ctx->empty_flush_buf->m2m_buf.vb); + v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf.vb); v4l2_m2m_try_schedule(ctx->m2m_ctx); break; @@ -1122,7 +1123,6 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) unsigned int dpbsize = 1, i = 0; struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct vb2_v4l2_buffer *vb2_v4l2 = NULL; - struct mtk_video_dec_buf *buf = NULL; struct mtk_q_data *dst_q_data; mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", @@ -1132,6 +1132,8 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) * check if this buffer is ready to be used after decode */ if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + struct mtk_video_dec_buf *buf; + vb2_v4l2 = to_vb2_v4l2_buffer(vb); buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb); @@ -1161,8 +1163,8 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) mtk_v4l2_err("No src buffer"); return; } - buf = container_of(src_buf, struct mtk_video_dec_buf, m2m_buf.vb); - if (buf->lastframe) { + + if (src_buf == &ctx->empty_flush_buf.vb) { /* This shouldn't happen. Just in case. */ mtk_v4l2_err("Invalid flush buffer."); v4l2_m2m_src_buf_remove(ctx->m2m_ctx); @@ -1267,8 +1269,6 @@ static int vb2ops_vdec_buf_init(struct vb2_buffer *vb) if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { buf->used = false; buf->queued_in_v4l2 = false; - } else { - buf->lastframe = false; } return 0; @@ -1294,9 +1294,7 @@ static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) { - struct mtk_video_dec_buf *buf_info = container_of( - src_buf, struct mtk_video_dec_buf, m2m_buf.vb); - if (!buf_info->lastframe) + if (src_buf != &ctx->empty_flush_buf.vb) v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h index cf26b6c1486a..1f8b7300dce6 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h @@ -40,7 +40,6 @@ struct vdec_fb { * @queued_in_vb2: Capture buffer is queue in vb2 * @queued_in_v4l2: Capture buffer is in v4l2 driver, but not in vb2 * queue yet - * @lastframe: Intput buffer is last buffer - EOS * @error: An unrecoverable error occurs on this buffer. * @frame_buffer: Decode status, and buffer information of Capture buffer * @@ -52,7 +51,6 @@ struct mtk_video_dec_buf { bool used; bool queued_in_vb2; bool queued_in_v4l2; - bool lastframe; bool error; struct vdec_fb frame_buffer; }; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index f87dc47d9e63..5ce7f1b83e4e 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -81,21 +81,14 @@ static int fops_vcodec_open(struct file *file) { struct mtk_vcodec_dev *dev = video_drvdata(file); struct mtk_vcodec_ctx *ctx = NULL; - struct mtk_video_dec_buf *mtk_buf = NULL; int ret = 0; struct vb2_queue *src_vq; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; - mtk_buf = kzalloc(sizeof(*mtk_buf), GFP_KERNEL); - if (!mtk_buf) { - kfree(ctx); - return -ENOMEM; - } mutex_lock(&dev->dev_mutex); - ctx->empty_flush_buf = mtk_buf; ctx->id = dev->id_counter++; v4l2_fh_init(&ctx->fh, video_devdata(file)); file->private_data = &ctx->fh; @@ -121,8 +114,7 @@ static int fops_vcodec_open(struct file *file) } src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - ctx->empty_flush_buf->m2m_buf.vb.vb2_buf.vb2_queue = src_vq; - ctx->empty_flush_buf->lastframe = true; + ctx->empty_flush_buf.vb.vb2_buf.vb2_queue = src_vq; mtk_vcodec_dec_set_default_params(ctx); if (v4l2_fh_is_singular(&ctx->fh)) { @@ -162,7 +154,6 @@ err_m2m_ctx_init: err_ctrls_setup: v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); - kfree(ctx->empty_flush_buf); kfree(ctx); mutex_unlock(&dev->dev_mutex); @@ -193,7 +184,6 @@ static int fops_vcodec_release(struct file *file) v4l2_ctrl_handler_free(&ctx->ctrl_hdl); list_del_init(&ctx->list); - kfree(ctx->empty_flush_buf); kfree(ctx); mutex_unlock(&dev->dev_mutex); return 0; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 3f83710b4fa5..1d64c8e84168 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "mtk_vcodec_util.h" @@ -249,7 +250,8 @@ struct vdec_pic_info { * @decode_work: worker for the decoding * @encode_work: worker for the encoding * @last_decoded_picinfo: pic information get from latest decode - * @empty_flush_buf: a fake size-0 capture buffer that indicates flush + * @empty_flush_buf: a fake size-0 capture buffer that indicates flush. Only + * to be used with encoder and stateful decoder. * * @colorspace: enum v4l2_colorspace; supplemental to pixelformat * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding @@ -288,7 +290,7 @@ struct mtk_vcodec_ctx { struct work_struct decode_work; struct work_struct encode_work; struct vdec_pic_info last_decoded_picinfo; - struct mtk_video_dec_buf *empty_flush_buf; + struct v4l2_m2m_buffer empty_flush_buf; enum v4l2_colorspace colorspace; enum v4l2_ycbcr_encoding ycbcr_enc; -- cgit v1.2.3 From b375e01b796a3bdb2de93ebb15b645edb7972abd Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 6 Aug 2021 06:15:21 +0200 Subject: media: mtk-vcodec: venc: support START and STOP commands The V4L2 encoder specification requires encoders to support the V4L2_ENC_CMD_START and V4L2_ENC_CMD_STOP commands. Add support for these to the mtk-vcodec encoder by reusing the same flush buffer as used by the decoder driver. [hsinyi: fix double-free issue if flush buffer was not dequeued by the time streamoff is called] Signed-off-by: Alexandre Courbot Signed-off-by: Hsin-Yi Wang Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 2 + drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c | 140 +++++++++++++++++++-- .../media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c | 6 +- 3 files changed, 140 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 1d64c8e84168..09b8f05a5df8 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -252,6 +252,7 @@ struct vdec_pic_info { * @last_decoded_picinfo: pic information get from latest decode * @empty_flush_buf: a fake size-0 capture buffer that indicates flush. Only * to be used with encoder and stateful decoder. + * @is_flushing: set to true if flushing is in progress. * * @colorspace: enum v4l2_colorspace; supplemental to pixelformat * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding @@ -291,6 +292,7 @@ struct mtk_vcodec_ctx { struct work_struct encode_work; struct vdec_pic_info last_decoded_picinfo; struct v4l2_m2m_buffer empty_flush_buf; + bool is_flushing; enum v4l2_colorspace colorspace; enum v4l2_ycbcr_encoding ycbcr_enc; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index 416f356af363..efa53ea573a2 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c @@ -672,6 +672,7 @@ static int vidioc_venc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + int ret; if (ctx->state == MTK_STATE_ABORT) { mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error", @@ -679,7 +680,83 @@ static int vidioc_venc_dqbuf(struct file *file, void *priv, return -EIO; } - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); + ret = v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); + if (ret) + return ret; + + /* + * Complete flush if the user dequeued the 0-payload LAST buffer. + * We check the payload because a buffer with the LAST flag can also + * be seen during resolution changes. If we happen to be flushing at + * that time, the last buffer before the resolution changes could be + * misinterpreted for the buffer generated by the flush and terminate + * it earlier than we want. + */ + if (!V4L2_TYPE_IS_OUTPUT(buf->type) && + buf->flags & V4L2_BUF_FLAG_LAST && + buf->m.planes[0].bytesused == 0 && + ctx->is_flushing) { + /* + * Last CAPTURE buffer is dequeued, we can allow another flush + * to take place. + */ + ctx->is_flushing = false; + } + + return 0; +} + +static int vidioc_encoder_cmd(struct file *file, void *priv, + struct v4l2_encoder_cmd *cmd) +{ + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct vb2_queue *src_vq, *dst_vq; + int ret; + + if (ctx->state == MTK_STATE_ABORT) { + mtk_v4l2_err("[%d] Call to CMD after unrecoverable error", + ctx->id); + return -EIO; + } + + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, priv, cmd); + if (ret) + return ret; + + /* Calling START or STOP is invalid if a flush is in progress */ + if (ctx->is_flushing) + return -EBUSY; + + mtk_v4l2_debug(1, "encoder cmd=%u", cmd->cmd); + + dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + switch (cmd->cmd) { + case V4L2_ENC_CMD_STOP: + src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (!vb2_is_streaming(src_vq)) { + mtk_v4l2_debug(1, "Output stream is off. No need to flush."); + return 0; + } + if (!vb2_is_streaming(dst_vq)) { + mtk_v4l2_debug(1, "Capture stream is off. No need to flush."); + return 0; + } + ctx->is_flushing = true; + v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf.vb); + v4l2_m2m_try_schedule(ctx->m2m_ctx); + break; + + case V4L2_ENC_CMD_START: + vb2_clear_last_buffer_dequeued(dst_vq); + break; + + default: + return -EINVAL; + } + + return 0; } const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = { @@ -715,6 +792,9 @@ const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = { .vidioc_g_selection = vidioc_venc_g_selection, .vidioc_s_selection = vidioc_venc_s_selection, + + .vidioc_encoder_cmd = vidioc_encoder_cmd, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, }; static int vb2ops_venc_queue_setup(struct vb2_queue *vq, @@ -882,9 +962,38 @@ static void vb2ops_venc_stop_streaming(struct vb2_queue *q) dst_buf->vb2_buf.planes[0].bytesused = 0; v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); } + /* STREAMOFF on the CAPTURE queue completes any ongoing flush */ + if (ctx->is_flushing) { + struct v4l2_m2m_buffer *b, *n; + + mtk_v4l2_debug(1, "STREAMOFF called while flushing"); + /* + * STREAMOFF could be called before the flush buffer is + * dequeued. Check whether empty flush buf is still in + * queue before removing it. + */ + v4l2_m2m_for_each_src_buf_safe(ctx->m2m_ctx, b, n) { + if (b == &ctx->empty_flush_buf) { + v4l2_m2m_src_buf_remove_by_buf(ctx->m2m_ctx, &b->vb); + break; + } + } + ctx->is_flushing = false; + } } else { - while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) { + if (src_buf != &ctx->empty_flush_buf.vb) + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + } + if (ctx->is_flushing) { + /* + * If we are in the middle of a flush, put the flush + * buffer back into the queue so the next CAPTURE + * buffer gets returned with the LAST flag set. + */ + v4l2_m2m_buf_queue(ctx->m2m_ctx, + &ctx->empty_flush_buf.vb); + } } if ((q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && @@ -984,12 +1093,15 @@ static int mtk_venc_param_change(struct mtk_vcodec_ctx *ctx) { struct venc_enc_param enc_prm; struct vb2_v4l2_buffer *vb2_v4l2 = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - struct mtk_video_enc_buf *mtk_buf = - container_of(vb2_v4l2, struct mtk_video_enc_buf, - m2m_buf.vb); - + struct mtk_video_enc_buf *mtk_buf; int ret = 0; + /* Don't upcast the empty flush buffer */ + if (vb2_v4l2 == &ctx->empty_flush_buf.vb) + return 0; + + mtk_buf = container_of(vb2_v4l2, struct mtk_video_enc_buf, m2m_buf.vb); + memset(&enc_prm, 0, sizeof(enc_prm)); if (mtk_buf->param_change == MTK_ENCODE_PARAM_NONE) return 0; @@ -1075,6 +1187,20 @@ static void mtk_venc_worker(struct work_struct *work) } src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + + /* + * If we see the flush buffer, send an empty buffer with the LAST flag + * to the client. is_flushing will be reset at the time the buffer + * is dequeued. + */ + if (src_buf == &ctx->empty_flush_buf.vb) { + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx); + return; + } + memset(&frm_buf, 0, sizeof(frm_buf)); for (i = 0; i < src_buf->vb2_buf.num_planes ; i++) { frm_buf.fb_addr[i].dma_addr = diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c index 7b3e0ea4c410..8bbcb53fe3df 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c @@ -123,6 +123,7 @@ static int fops_vcodec_open(struct file *file) struct mtk_vcodec_dev *dev = video_drvdata(file); struct mtk_vcodec_ctx *ctx = NULL; int ret = 0; + struct vb2_queue *src_vq; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -149,13 +150,16 @@ static int fops_vcodec_open(struct file *file) goto err_ctrls_setup; } ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_enc, ctx, - &mtk_vcodec_enc_queue_init); + &mtk_vcodec_enc_queue_init); if (IS_ERR((__force void *)ctx->m2m_ctx)) { ret = PTR_ERR((__force void *)ctx->m2m_ctx); mtk_v4l2_err("Failed to v4l2_m2m_ctx_init() (%d)", ret); goto err_m2m_ctx_init; } + src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + ctx->empty_flush_buf.vb.vb2_buf.vb2_queue = src_vq; mtk_vcodec_enc_set_default_params(ctx); if (v4l2_fh_is_singular(&ctx->fh)) { -- cgit v1.2.3 From fd00d90330d1d2a962d010fc93515e2d77739ad8 Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Fri, 6 Aug 2021 06:15:22 +0200 Subject: media: mtk-vcodec: vdec: move stateful ops into their own file We are planning to add support for stateless decoders to this driver. Part of the driver will be shared between stateful and stateless codecs, but a few ops need to be specialized for both. Extract the stateful part of the driver and move it into its own file, accessible through ops that the common driver parts can call. This patch only moves code around and introduces a set of abstractions ; the behavior of the driver should not be changed in any way. Changes to code styling has been done to accommodate 'checkpatch.pl --strict'. [acourbot: refactor, cleanup and split] [tzungbi: fix errors from 'checkpatch.pl --strict'] Signed-off-by: Yunfei Dong Co-developed-by: Alexandre Courbot Signed-off-by: Alexandre Courbot Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/Makefile | 1 + drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 737 ++------------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h | 15 +- .../media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 10 +- .../platform/mtk-vcodec/mtk_vcodec_dec_stateful.c | 627 ++++++++++++++++++ drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 41 ++ 6 files changed, 750 insertions(+), 681 deletions(-) create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index 4618d43dbbc8..9c3cbb5b800e 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -11,6 +11,7 @@ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ vdec_drv_if.o \ vdec_vpu_if.o \ mtk_vcodec_dec.o \ + mtk_vcodec_dec_stateful.o \ mtk_vcodec_dec_pm.o \ mtk-vcodec-enc-y := venc/venc_vp8_if.o \ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 7edd6266dc6a..a220532802f9 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -16,68 +16,18 @@ #include "vdec_drv_if.h" #include "mtk_vcodec_dec_pm.h" -#define OUT_FMT_IDX 0 -#define CAP_FMT_IDX 3 - -#define MTK_VDEC_MIN_W 64U -#define MTK_VDEC_MIN_H 64U #define DFT_CFG_WIDTH MTK_VDEC_MIN_W #define DFT_CFG_HEIGHT MTK_VDEC_MIN_H -static const struct mtk_video_fmt mtk_video_formats[] = { - { - .fourcc = V4L2_PIX_FMT_H264, - .type = MTK_FMT_DEC, - .num_planes = 1, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, - }, - { - .fourcc = V4L2_PIX_FMT_VP8, - .type = MTK_FMT_DEC, - .num_planes = 1, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, - }, - { - .fourcc = V4L2_PIX_FMT_VP9, - .type = MTK_FMT_DEC, - .num_planes = 1, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, - }, - { - .fourcc = V4L2_PIX_FMT_MT21C, - .type = MTK_FMT_FRAME, - .num_planes = 2, - }, -}; - -static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { - { - .fourcc = V4L2_PIX_FMT_H264, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, - }, - { - .fourcc = V4L2_PIX_FMT_VP8, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, - }, - { - .fourcc = V4L2_PIX_FMT_VP9, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, - }, -}; - -#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) -#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) - -static const struct mtk_video_fmt *mtk_vdec_find_format(struct v4l2_format *f) +static const struct mtk_video_fmt * +mtk_vdec_find_format(struct v4l2_format *f, + const struct mtk_vcodec_dec_pdata *dec_pdata) { const struct mtk_video_fmt *fmt; unsigned int k; - for (k = 0; k < NUM_FORMATS; k++) { - fmt = &mtk_video_formats[k]; + for (k = 0; k < dec_pdata->num_formats; k++) { + fmt = &dec_pdata->vdec_formats[k]; if (fmt->fourcc == f->fmt.pix_mp.pixelformat) return fmt; } @@ -94,395 +44,6 @@ static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx, return &ctx->q_data[MTK_Q_DATA_DST]; } -/* - * This function tries to clean all display buffers, the buffers will return - * in display order. - * Note the buffers returned from codec driver may still be in driver's - * reference list. - */ -static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx) -{ - struct vdec_fb *disp_frame_buffer = NULL; - struct mtk_video_dec_buf *dstbuf; - struct vb2_v4l2_buffer *vb; - - mtk_v4l2_debug(3, "[%d]", ctx->id); - if (vdec_if_get_param(ctx, - GET_PARAM_DISP_FRAME_BUFFER, - &disp_frame_buffer)) { - mtk_v4l2_err("[%d]Cannot get param : GET_PARAM_DISP_FRAME_BUFFER", - ctx->id); - return NULL; - } - - if (disp_frame_buffer == NULL) { - mtk_v4l2_debug(3, "No display frame buffer"); - return NULL; - } - - dstbuf = container_of(disp_frame_buffer, struct mtk_video_dec_buf, - frame_buffer); - vb = &dstbuf->m2m_buf.vb; - mutex_lock(&ctx->lock); - if (dstbuf->used) { - vb2_set_plane_payload(&vb->vb2_buf, 0, - ctx->picinfo.fb_sz[0]); - if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) - vb2_set_plane_payload(&vb->vb2_buf, 1, - ctx->picinfo.fb_sz[1]); - - mtk_v4l2_debug(2, - "[%d]status=%x queue id=%d to done_list %d", - ctx->id, disp_frame_buffer->status, - vb->vb2_buf.index, - dstbuf->queued_in_vb2); - - v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE); - ctx->decoded_frame_cnt++; - } - mutex_unlock(&ctx->lock); - return &vb->vb2_buf; -} - -/* - * This function tries to clean all capture buffers that are not used as - * reference buffers by codec driver any more - * In this case, we need re-queue buffer to vb2 buffer if user space - * already returns this buffer to v4l2 or this buffer is just the output of - * previous sps/pps/resolution change decode, or do nothing if user - * space still owns this buffer - */ -static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx) -{ - struct mtk_video_dec_buf *dstbuf; - struct vdec_fb *free_frame_buffer = NULL; - struct vb2_v4l2_buffer *vb; - - if (vdec_if_get_param(ctx, - GET_PARAM_FREE_FRAME_BUFFER, - &free_frame_buffer)) { - mtk_v4l2_err("[%d] Error!! Cannot get param", ctx->id); - return NULL; - } - if (free_frame_buffer == NULL) { - mtk_v4l2_debug(3, " No free frame buffer"); - return NULL; - } - - mtk_v4l2_debug(3, "[%d] tmp_frame_addr = 0x%p", - ctx->id, free_frame_buffer); - - dstbuf = container_of(free_frame_buffer, struct mtk_video_dec_buf, - frame_buffer); - vb = &dstbuf->m2m_buf.vb; - - mutex_lock(&ctx->lock); - if (dstbuf->used) { - if ((dstbuf->queued_in_vb2) && - (dstbuf->queued_in_v4l2) && - (free_frame_buffer->status == FB_ST_FREE)) { - /* - * After decode sps/pps or non-display buffer, we don't - * need to return capture buffer to user space, but - * just re-queue this capture buffer to vb2 queue. - * This reduce overheads that dq/q unused capture - * buffer. In this case, queued_in_vb2 = true. - */ - mtk_v4l2_debug(2, - "[%d]status=%x queue id=%d to rdy_queue %d", - ctx->id, free_frame_buffer->status, - vb->vb2_buf.index, - dstbuf->queued_in_vb2); - v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); - } else if (!dstbuf->queued_in_vb2 && dstbuf->queued_in_v4l2) { - /* - * If buffer in v4l2 driver but not in vb2 queue yet, - * and we get this buffer from free_list, it means - * that codec driver do not use this buffer as - * reference buffer anymore. We should q buffer to vb2 - * queue, so later work thread could get this buffer - * for decode. In this case, queued_in_vb2 = false - * means this buffer is not from previous decode - * output. - */ - mtk_v4l2_debug(2, - "[%d]status=%x queue id=%d to rdy_queue", - ctx->id, free_frame_buffer->status, - vb->vb2_buf.index); - v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); - dstbuf->queued_in_vb2 = true; - } else { - /* - * Codec driver do not need to reference this capture - * buffer and this buffer is not in v4l2 driver. - * Then we don't need to do any thing, just add log when - * we need to debug buffer flow. - * When this buffer q from user space, it could - * directly q to vb2 buffer - */ - mtk_v4l2_debug(3, "[%d]status=%x err queue id=%d %d %d", - ctx->id, free_frame_buffer->status, - vb->vb2_buf.index, - dstbuf->queued_in_vb2, - dstbuf->queued_in_v4l2); - } - dstbuf->used = false; - } - mutex_unlock(&ctx->lock); - return &vb->vb2_buf; -} - -static void clean_display_buffer(struct mtk_vcodec_ctx *ctx) -{ - struct vb2_buffer *framptr; - - do { - framptr = get_display_buffer(ctx); - } while (framptr); -} - -static void clean_free_buffer(struct mtk_vcodec_ctx *ctx) -{ - struct vb2_buffer *framptr; - - do { - framptr = get_free_buffer(ctx); - } while (framptr); -} - -static void mtk_vdec_queue_res_chg_event(struct mtk_vcodec_ctx *ctx) -{ - static const struct v4l2_event ev_src_ch = { - .type = V4L2_EVENT_SOURCE_CHANGE, - .u.src_change.changes = - V4L2_EVENT_SRC_CH_RESOLUTION, - }; - - mtk_v4l2_debug(1, "[%d]", ctx->id); - v4l2_event_queue_fh(&ctx->fh, &ev_src_ch); -} - -static void mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx) -{ - bool res_chg; - int ret = 0; - - ret = vdec_if_decode(ctx, NULL, NULL, &res_chg); - if (ret) - mtk_v4l2_err("DecodeFinal failed, ret=%d", ret); - - clean_display_buffer(ctx); - clean_free_buffer(ctx); -} - -static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx, - unsigned int pixelformat) -{ - const struct mtk_video_fmt *fmt; - struct mtk_q_data *dst_q_data; - unsigned int k; - - dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; - for (k = 0; k < NUM_FORMATS; k++) { - fmt = &mtk_video_formats[k]; - if (fmt->fourcc == pixelformat) { - mtk_v4l2_debug(1, "Update cap fourcc(%d -> %d)", - dst_q_data->fmt->fourcc, pixelformat); - dst_q_data->fmt = fmt; - return; - } - } - - mtk_v4l2_err("Cannot get fourcc(%d), using init value", pixelformat); -} - -static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx) -{ - unsigned int dpbsize = 0; - int ret; - - if (vdec_if_get_param(ctx, - GET_PARAM_PIC_INFO, - &ctx->last_decoded_picinfo)) { - mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", - ctx->id); - return -EINVAL; - } - - if (ctx->last_decoded_picinfo.pic_w == 0 || - ctx->last_decoded_picinfo.pic_h == 0 || - ctx->last_decoded_picinfo.buf_w == 0 || - ctx->last_decoded_picinfo.buf_h == 0) { - mtk_v4l2_err("Cannot get correct pic info"); - return -EINVAL; - } - - if (ctx->last_decoded_picinfo.cap_fourcc != ctx->picinfo.cap_fourcc && - ctx->picinfo.cap_fourcc != 0) - mtk_vdec_update_fmt(ctx, ctx->picinfo.cap_fourcc); - - if ((ctx->last_decoded_picinfo.pic_w == ctx->picinfo.pic_w) || - (ctx->last_decoded_picinfo.pic_h == ctx->picinfo.pic_h)) - return 0; - - mtk_v4l2_debug(1, - "[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)", - ctx->id, ctx->last_decoded_picinfo.pic_w, - ctx->last_decoded_picinfo.pic_h, - ctx->picinfo.pic_w, ctx->picinfo.pic_h, - ctx->last_decoded_picinfo.buf_w, - ctx->last_decoded_picinfo.buf_h); - - ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); - if (dpbsize == 0) - mtk_v4l2_err("Incorrect dpb size, ret=%d", ret); - - ctx->dpb_size = dpbsize; - - return ret; -} - -static void mtk_vdec_worker(struct work_struct *work) -{ - struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx, - decode_work); - struct mtk_vcodec_dev *dev = ctx->dev; - struct vb2_v4l2_buffer *src_buf, *dst_buf; - struct mtk_vcodec_mem buf; - struct vdec_fb *pfb; - bool res_chg = false; - int ret; - struct mtk_video_dec_buf *dst_buf_info, *src_buf_info; - - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - if (src_buf == NULL) { - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); - mtk_v4l2_debug(1, "[%d] src_buf empty!!", ctx->id); - return; - } - - dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - if (dst_buf == NULL) { - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); - mtk_v4l2_debug(1, "[%d] dst_buf empty!!", ctx->id); - return; - } - - dst_buf_info = container_of(dst_buf, struct mtk_video_dec_buf, - m2m_buf.vb); - - pfb = &dst_buf_info->frame_buffer; - pfb->base_y.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); - pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); - pfb->base_y.size = ctx->picinfo.fb_sz[0]; - - pfb->base_c.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 1); - pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 1); - pfb->base_c.size = ctx->picinfo.fb_sz[1]; - pfb->status = 0; - mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id); - - mtk_v4l2_debug(3, - "id=%d Framebuf pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx", - dst_buf->vb2_buf.index, pfb, - pfb->base_y.va, &pfb->base_y.dma_addr, - &pfb->base_c.dma_addr, pfb->base_y.size); - - if (src_buf == &ctx->empty_flush_buf.vb) { - mtk_v4l2_debug(1, "Got empty flush input buffer."); - src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - - /* update dst buf status */ - dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); - mutex_lock(&ctx->lock); - dst_buf_info->used = false; - mutex_unlock(&ctx->lock); - - vdec_if_decode(ctx, NULL, NULL, &res_chg); - clean_display_buffer(ctx); - vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); - if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) - vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); - dst_buf->flags |= V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); - clean_free_buffer(ctx); - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); - return; - } - - src_buf_info = container_of(src_buf, struct mtk_video_dec_buf, - m2m_buf.vb); - - buf.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); - buf.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); - buf.size = (size_t)src_buf->vb2_buf.planes[0].bytesused; - if (!buf.va) { - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); - mtk_v4l2_err("[%d] id=%d src_addr is NULL!!", - ctx->id, src_buf->vb2_buf.index); - return; - } - mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p", - ctx->id, buf.va, &buf.dma_addr, buf.size, src_buf); - dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; - dst_buf->timecode = src_buf->timecode; - mutex_lock(&ctx->lock); - dst_buf_info->used = true; - mutex_unlock(&ctx->lock); - src_buf_info->used = true; - - ret = vdec_if_decode(ctx, &buf, pfb, &res_chg); - - if (ret) { - mtk_v4l2_err( - " <===[%d], src_buf[%d] sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>", - ctx->id, - src_buf->vb2_buf.index, - buf.size, - src_buf->vb2_buf.timestamp, - dst_buf->vb2_buf.index, - ret, res_chg); - src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - if (ret == -EIO) { - mutex_lock(&ctx->lock); - src_buf_info->error = true; - mutex_unlock(&ctx->lock); - } - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); - } else if (!res_chg) { - /* - * we only return src buffer with VB2_BUF_STATE_DONE - * when decode success without resolution change - */ - src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - } - - dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); - clean_display_buffer(ctx); - clean_free_buffer(ctx); - - if (!ret && res_chg) { - mtk_vdec_pic_info_update(ctx); - /* - * On encountering a resolution change in the stream. - * The driver must first process and decode all - * remaining buffers from before the resolution change - * point, so call flush decode here - */ - mtk_vdec_flush_decoder(ctx); - /* - * After all buffers containing decoded frames from - * before the resolution change point ready to be - * dequeued on the CAPTURE queue, the driver sends a - * V4L2_EVENT_SOURCE_CHANGE event for source change - * type V4L2_EVENT_SRC_CH_RESOLUTION - */ - mtk_vdec_queue_res_chg_event(ctx); - } - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); -} - static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { @@ -551,10 +112,12 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) { struct mtk_q_data *q_data; + ctx->dev->vdec_pdata->init_vdec_params(ctx); + ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex; ctx->fh.m2m_ctx = ctx->m2m_ctx; ctx->fh.ctrl_handler = &ctx->ctrl_hdl; - INIT_WORK(&ctx->decode_work, mtk_vdec_worker); + INIT_WORK(&ctx->decode_work, ctx->dev->vdec_pdata->worker); ctx->colorspace = V4L2_COLORSPACE_REC709; ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; ctx->quantization = V4L2_QUANTIZATION_DEFAULT; @@ -564,7 +127,7 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) memset(q_data, 0, sizeof(struct mtk_q_data)); q_data->visible_width = DFT_CFG_WIDTH; q_data->visible_height = DFT_CFG_HEIGHT; - q_data->fmt = &mtk_video_formats[OUT_FMT_IDX]; + q_data->fmt = ctx->dev->vdec_pdata->default_out_fmt; q_data->field = V4L2_FIELD_NONE; q_data->sizeimage[0] = DFT_CFG_WIDTH * DFT_CFG_HEIGHT; @@ -576,7 +139,7 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) q_data->visible_height = DFT_CFG_HEIGHT; q_data->coded_width = DFT_CFG_WIDTH; q_data->coded_height = DFT_CFG_HEIGHT; - q_data->fmt = &mtk_video_formats[CAP_FMT_IDX]; + q_data->fmt = ctx->dev->vdec_pdata->default_cap_fmt; q_data->field = V4L2_FIELD_NONE; v4l_bound_align_image(&q_data->coded_width, @@ -710,11 +273,14 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { const struct mtk_video_fmt *fmt; + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; - fmt = mtk_vdec_find_format(f); + fmt = mtk_vdec_find_format(f, dec_pdata); if (!fmt) { - f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc; - fmt = mtk_vdec_find_format(f); + f->fmt.pix.pixelformat = + ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc; + fmt = mtk_vdec_find_format(f, dec_pdata); } return vidioc_try_fmt(f, fmt); @@ -725,11 +291,14 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; const struct mtk_video_fmt *fmt; + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; - fmt = mtk_vdec_find_format(f); + fmt = mtk_vdec_find_format(f, dec_pdata); if (!fmt) { - f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc; - fmt = mtk_vdec_find_format(f); + f->fmt.pix.pixelformat = + ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc; + fmt = mtk_vdec_find_format(f, dec_pdata); } if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) { @@ -819,6 +388,7 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, struct mtk_q_data *q_data; int ret = 0; const struct mtk_video_fmt *fmt; + const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; mtk_v4l2_debug(3, "[%d]", ctx->id); @@ -847,16 +417,16 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, ret = -EBUSY; } - fmt = mtk_vdec_find_format(f); + fmt = mtk_vdec_find_format(f, dec_pdata); if (fmt == NULL) { if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { f->fmt.pix.pixelformat = - mtk_video_formats[OUT_FMT_IDX].fourcc; - fmt = mtk_vdec_find_format(f); + dec_pdata->default_out_fmt->fourcc; + fmt = mtk_vdec_find_format(f, dec_pdata); } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { f->fmt.pix.pixelformat = - mtk_video_formats[CAP_FMT_IDX].fourcc; - fmt = mtk_vdec_find_format(f); + dec_pdata->default_cap_fmt->fourcc; + fmt = mtk_vdec_find_format(f, dec_pdata); } } if (fmt == NULL) @@ -893,16 +463,17 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, { int i = 0; struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; if (fsize->index != 0) return -EINVAL; - for (i = 0; i < NUM_SUPPORTED_FRAMESIZE; ++i) { - if (fsize->pixel_format != mtk_vdec_framesizes[i].fourcc) + for (i = 0; i < dec_pdata->num_framesizes; ++i) { + if (fsize->pixel_format != dec_pdata->vdec_framesizes[i].fourcc) continue; fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise = mtk_vdec_framesizes[i].stepwise; + fsize->stepwise = dec_pdata->vdec_framesizes[i].stepwise; if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED)) { mtk_v4l2_debug(3, "4K is enabled"); @@ -925,16 +496,20 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, return -EINVAL; } -static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) +static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv, + bool output_queue) { + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; const struct mtk_video_fmt *fmt; int i, j = 0; - for (i = 0; i < NUM_FORMATS; i++) { - if (output_queue && (mtk_video_formats[i].type != MTK_FMT_DEC)) + for (i = 0; i < dec_pdata->num_formats; i++) { + if (output_queue && + dec_pdata->vdec_formats[i].type != MTK_FMT_DEC) continue; if (!output_queue && - (mtk_video_formats[i].type != MTK_FMT_FRAME)) + dec_pdata->vdec_formats[i].type != MTK_FMT_FRAME) continue; if (j == f->index) @@ -942,10 +517,10 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) ++j; } - if (i == NUM_FORMATS) + if (i == dec_pdata->num_formats) return -EINVAL; - fmt = &mtk_video_formats[i]; + fmt = &dec_pdata->vdec_formats[i]; f->pixelformat = fmt->fourcc; f->flags = fmt->flags; @@ -955,13 +530,13 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) static int vidioc_vdec_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(f, false); + return vidioc_enum_fmt(f, priv, false); } static int vidioc_vdec_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(f, true); + return vidioc_enum_fmt(f, priv, true); } static int vidioc_vdec_g_fmt(struct file *file, void *priv, @@ -1052,11 +627,9 @@ static int vidioc_vdec_g_fmt(struct file *file, void *priv, return 0; } -static int vb2ops_vdec_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, - unsigned int *nplanes, - unsigned int sizes[], - struct device *alloc_devs[]) +int vb2ops_vdec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) { struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vq); struct mtk_q_data *q_data; @@ -1076,7 +649,7 @@ static int vb2ops_vdec_queue_setup(struct vb2_queue *vq, } } else { if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - *nplanes = 2; + *nplanes = q_data->fmt->num_planes; else *nplanes = 1; @@ -1092,7 +665,7 @@ static int vb2ops_vdec_queue_setup(struct vb2_queue *vq, return 0; } -static int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) +int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) { struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct mtk_q_data *q_data; @@ -1114,129 +687,7 @@ static int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) return 0; } -static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *src_buf; - struct mtk_vcodec_mem src_mem; - bool res_chg = false; - int ret = 0; - unsigned int dpbsize = 1, i = 0; - struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct vb2_v4l2_buffer *vb2_v4l2 = NULL; - struct mtk_q_data *dst_q_data; - - mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", - ctx->id, vb->vb2_queue->type, - vb->index, vb); - /* - * check if this buffer is ready to be used after decode - */ - if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - struct mtk_video_dec_buf *buf; - - vb2_v4l2 = to_vb2_v4l2_buffer(vb); - buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, - m2m_buf.vb); - mutex_lock(&ctx->lock); - if (!buf->used) { - v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2); - buf->queued_in_vb2 = true; - buf->queued_in_v4l2 = true; - } else { - buf->queued_in_vb2 = false; - buf->queued_in_v4l2 = true; - } - mutex_unlock(&ctx->lock); - return; - } - - v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb)); - - if (ctx->state != MTK_STATE_INIT) { - mtk_v4l2_debug(3, "[%d] already init driver %d", - ctx->id, ctx->state); - return; - } - - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - if (!src_buf) { - mtk_v4l2_err("No src buffer"); - return; - } - - if (src_buf == &ctx->empty_flush_buf.vb) { - /* This shouldn't happen. Just in case. */ - mtk_v4l2_err("Invalid flush buffer."); - v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - return; - } - - src_mem.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); - src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); - src_mem.size = (size_t)src_buf->vb2_buf.planes[0].bytesused; - mtk_v4l2_debug(2, - "[%d] buf id=%d va=%p dma=%pad size=%zx", - ctx->id, src_buf->vb2_buf.index, - src_mem.va, &src_mem.dma_addr, - src_mem.size); - - ret = vdec_if_decode(ctx, &src_mem, NULL, &res_chg); - if (ret || !res_chg) { - /* - * fb == NULL means to parse SPS/PPS header or - * resolution info in src_mem. Decode can fail - * if there is no SPS header or picture info - * in bs - */ - - src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - if (ret == -EIO) { - mtk_v4l2_err("[%d] Unrecoverable error in vdec_if_decode.", - ctx->id); - ctx->state = MTK_STATE_ABORT; - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); - } else { - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - } - mtk_v4l2_debug(ret ? 0 : 1, - "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d", - ctx->id, src_buf->vb2_buf.index, - src_mem.size, ret, res_chg); - return; - } - - if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo)) { - mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", - ctx->id); - return; - } - - ctx->last_decoded_picinfo = ctx->picinfo; - dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; - for (i = 0; i < dst_q_data->fmt->num_planes; i++) { - dst_q_data->sizeimage[i] = ctx->picinfo.fb_sz[i]; - dst_q_data->bytesperline[i] = ctx->picinfo.buf_w; - } - - mtk_v4l2_debug(2, "[%d] vdec_if_init() OK wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x", - ctx->id, - ctx->picinfo.buf_w, ctx->picinfo.buf_h, - ctx->picinfo.pic_w, ctx->picinfo.pic_h, - dst_q_data->sizeimage[0], - dst_q_data->sizeimage[1]); - - ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); - if (dpbsize == 0) - mtk_v4l2_err("[%d] GET_PARAM_DPB_SIZE fail=%d", ctx->id, ret); - - ctx->dpb_size = dpbsize; - ctx->state = MTK_STATE_HEADER; - mtk_v4l2_debug(1, "[%d] dpbsize=%d", ctx->id, ctx->dpb_size); - - mtk_vdec_queue_res_chg_event(ctx); -} - -static void vb2ops_vdec_buf_finish(struct vb2_buffer *vb) +void vb2ops_vdec_buf_finish(struct vb2_buffer *vb) { struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct vb2_v4l2_buffer *vb2_v4l2; @@ -1259,7 +710,7 @@ static void vb2ops_vdec_buf_finish(struct vb2_buffer *vb) } } -static int vb2ops_vdec_buf_init(struct vb2_buffer *vb) +int vb2ops_vdec_buf_init(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); @@ -1274,7 +725,7 @@ static int vb2ops_vdec_buf_init(struct vb2_buffer *vb) return 0; } -static int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count) +int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count) { struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q); @@ -1284,10 +735,11 @@ static int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count) return 0; } -static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) +void vb2ops_vdec_stop_streaming(struct vb2_queue *q) { struct vb2_v4l2_buffer *src_buf = NULL, *dst_buf = NULL; struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q); + int ret; mtk_v4l2_debug(3, "[%d] (%d) state=(%x) ctx->decoded_frame_cnt=%d", ctx->id, q->type, ctx->state, ctx->decoded_frame_cnt); @@ -1319,7 +771,9 @@ static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) ctx->last_decoded_picinfo.buf_w, ctx->last_decoded_picinfo.buf_h); - mtk_vdec_flush_decoder(ctx); + ret = ctx->dev->vdec_pdata->flush_decoder(ctx); + if (ret) + mtk_v4l2_err("DecodeFinal failed, ret=%d", ret); } ctx->state = MTK_STATE_FLUSH; @@ -1366,85 +820,12 @@ static void m2mops_vdec_job_abort(void *priv) ctx->state = MTK_STATE_ABORT; } -static int mtk_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl) -{ - struct mtk_vcodec_ctx *ctx = ctrl_to_ctx(ctrl); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: - if (ctx->state >= MTK_STATE_HEADER) { - ctrl->val = ctx->dpb_size; - } else { - mtk_v4l2_debug(0, "Seqinfo not ready"); - ctrl->val = 0; - } - break; - default: - ret = -EINVAL; - } - return ret; -} - -static const struct v4l2_ctrl_ops mtk_vcodec_dec_ctrl_ops = { - .g_volatile_ctrl = mtk_vdec_g_v_ctrl, -}; - -int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx) -{ - struct v4l2_ctrl *ctrl; - - v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 1); - - ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl, - &mtk_vcodec_dec_ctrl_ops, - V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, - 0, 32, 1, 1); - ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; - v4l2_ctrl_new_std_menu(&ctx->ctrl_hdl, - &mtk_vcodec_dec_ctrl_ops, - V4L2_CID_MPEG_VIDEO_VP9_PROFILE, - V4L2_MPEG_VIDEO_VP9_PROFILE_0, - 0, V4L2_MPEG_VIDEO_VP9_PROFILE_0); - /* - * H264. Baseline / Extended decoding is not supported. - */ - v4l2_ctrl_new_std_menu(&ctx->ctrl_hdl, - &mtk_vcodec_dec_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_PROFILE, - V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED), - V4L2_MPEG_VIDEO_H264_PROFILE_MAIN); - - if (ctx->ctrl_hdl.error) { - mtk_v4l2_err("Adding control failed %d", - ctx->ctrl_hdl.error); - return ctx->ctrl_hdl.error; - } - - v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); - return 0; -} - const struct v4l2_m2m_ops mtk_vdec_m2m_ops = { .device_run = m2mops_vdec_device_run, .job_ready = m2mops_vdec_job_ready, .job_abort = m2mops_vdec_job_abort, }; -static const struct vb2_ops mtk_vdec_vb2_ops = { - .queue_setup = vb2ops_vdec_queue_setup, - .buf_prepare = vb2ops_vdec_buf_prepare, - .buf_queue = vb2ops_vdec_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .buf_init = vb2ops_vdec_buf_init, - .buf_finish = vb2ops_vdec_buf_finish, - .start_streaming = vb2ops_vdec_start_streaming, - .stop_streaming = vb2ops_vdec_stop_streaming, -}; - const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops = { .vidioc_streamon = v4l2_m2m_ioctl_streamon, .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, @@ -1491,7 +872,7 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->io_modes = VB2_DMABUF | VB2_MMAP; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf); - src_vq->ops = &mtk_vdec_vb2_ops; + src_vq->ops = ctx->dev->vdec_pdata->vdec_vb2_ops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->dev->dev_mutex; @@ -1506,7 +887,7 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf); - dst_vq->ops = &mtk_vdec_vb2_ops; + dst_vq->ops = ctx->dev->vdec_pdata->vdec_vb2_ops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = &ctx->dev->dev_mutex; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h index 1f8b7300dce6..76856c0b2db8 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h @@ -16,6 +16,8 @@ #define VCODEC_DEC_4K_CODED_HEIGHT 2304U #define MTK_VDEC_MAX_W 2048U #define MTK_VDEC_MAX_H 1088U +#define MTK_VDEC_MIN_W 64U +#define MTK_VDEC_MIN_H 64U #define MTK_VDEC_IRQ_STATUS_DEC_SUCCESS 0x10000 @@ -71,7 +73,18 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq); void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx); void mtk_vcodec_dec_release(struct mtk_vcodec_ctx *ctx); -int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx); + +/* + * VB2 ops + */ +int vb2ops_vdec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]); +int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb); +void vb2ops_vdec_buf_finish(struct vb2_buffer *vb); +int vb2ops_vdec_buf_init(struct vb2_buffer *vb); +int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count); +void vb2ops_vdec_stop_streaming(struct vb2_queue *q); #endif /* _MTK_VCODEC_DEC_H_ */ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index 5ce7f1b83e4e..1460951f302c 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -99,7 +99,7 @@ static int fops_vcodec_open(struct file *file) mutex_init(&ctx->lock); ctx->type = MTK_INST_DECODER; - ret = mtk_vcodec_dec_ctrls_setup(ctx); + ret = dev->vdec_pdata->ctrls_setup(ctx); if (ret) { mtk_v4l2_err("Failed to setup mt vcodec controls"); goto err_ctrls_setup; @@ -214,6 +214,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) INIT_LIST_HEAD(&dev->ctx_list); dev->plat_dev = pdev; + dev->vdec_pdata = of_device_get_match_data(&pdev->dev); if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu", &rproc_phandle)) { fw_type = VPU; @@ -341,8 +342,13 @@ err_dec_pm: return ret; } +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata; + static const struct of_device_id mtk_vcodec_match[] = { - {.compatible = "mediatek,mt8173-vcodec-dec",}, + { + .compatible = "mediatek,mt8173-vcodec-dec", + .data = &mtk_vdec_8173_pdata, + }, {}, }; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c new file mode 100644 index 000000000000..d77a7688688a --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c @@ -0,0 +1,627 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +#include "mtk_vcodec_drv.h" +#include "mtk_vcodec_dec.h" +#include "mtk_vcodec_intr.h" +#include "mtk_vcodec_util.h" +#include "mtk_vcodec_dec_pm.h" +#include "vdec_drv_if.h" + +static const struct mtk_video_fmt mtk_video_formats[] = { + { + .fourcc = V4L2_PIX_FMT_H264, + .type = MTK_FMT_DEC, + .num_planes = 1, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + }, + { + .fourcc = V4L2_PIX_FMT_VP8, + .type = MTK_FMT_DEC, + .num_planes = 1, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + }, + { + .fourcc = V4L2_PIX_FMT_VP9, + .type = MTK_FMT_DEC, + .num_planes = 1, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + }, + { + .fourcc = V4L2_PIX_FMT_MT21C, + .type = MTK_FMT_FRAME, + .num_planes = 2, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) +#define DEFAULT_OUT_FMT_IDX 0 +#define DEFAULT_CAP_FMT_IDX 3 + +static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { + { + .fourcc = V4L2_PIX_FMT_H264, + .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, + }, + { + .fourcc = V4L2_PIX_FMT_VP8, + .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, + }, + { + .fourcc = V4L2_PIX_FMT_VP9, + .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, + }, +}; + +#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) + +/* + * This function tries to clean all display buffers, the buffers will return + * in display order. + * Note the buffers returned from codec driver may still be in driver's + * reference list. + */ +static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx) +{ + struct vdec_fb *disp_frame_buffer = NULL; + struct mtk_video_dec_buf *dstbuf; + struct vb2_v4l2_buffer *vb; + + mtk_v4l2_debug(3, "[%d]", ctx->id); + if (vdec_if_get_param(ctx, GET_PARAM_DISP_FRAME_BUFFER, + &disp_frame_buffer)) { + mtk_v4l2_err("[%d]Cannot get param : GET_PARAM_DISP_FRAME_BUFFER", ctx->id); + return NULL; + } + + if (!disp_frame_buffer) { + mtk_v4l2_debug(3, "No display frame buffer"); + return NULL; + } + + dstbuf = container_of(disp_frame_buffer, struct mtk_video_dec_buf, + frame_buffer); + vb = &dstbuf->m2m_buf.vb; + mutex_lock(&ctx->lock); + if (dstbuf->used) { + vb2_set_plane_payload(&vb->vb2_buf, 0, ctx->picinfo.fb_sz[0]); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + vb2_set_plane_payload(&vb->vb2_buf, 1, + ctx->picinfo.fb_sz[1]); + + mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to done_list %d", + ctx->id, disp_frame_buffer->status, + vb->vb2_buf.index, dstbuf->queued_in_vb2); + + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE); + ctx->decoded_frame_cnt++; + } + mutex_unlock(&ctx->lock); + return &vb->vb2_buf; +} + +/* + * This function tries to clean all capture buffers that are not used as + * reference buffers by codec driver any more + * In this case, we need re-queue buffer to vb2 buffer if user space + * already returns this buffer to v4l2 or this buffer is just the output of + * previous sps/pps/resolution change decode, or do nothing if user + * space still owns this buffer + */ +static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx) +{ + struct mtk_video_dec_buf *dstbuf; + struct vdec_fb *free_frame_buffer = NULL; + struct vb2_v4l2_buffer *vb; + + if (vdec_if_get_param(ctx, GET_PARAM_FREE_FRAME_BUFFER, + &free_frame_buffer)) { + mtk_v4l2_err("[%d] Error!! Cannot get param", ctx->id); + return NULL; + } + if (!free_frame_buffer) { + mtk_v4l2_debug(3, " No free frame buffer"); + return NULL; + } + + mtk_v4l2_debug(3, "[%d] tmp_frame_addr = 0x%p", ctx->id, + free_frame_buffer); + + dstbuf = container_of(free_frame_buffer, struct mtk_video_dec_buf, + frame_buffer); + vb = &dstbuf->m2m_buf.vb; + + mutex_lock(&ctx->lock); + if (dstbuf->used) { + if (dstbuf->queued_in_vb2 && dstbuf->queued_in_v4l2 && + free_frame_buffer->status == FB_ST_FREE) { + /* + * After decode sps/pps or non-display buffer, we don't + * need to return capture buffer to user space, but + * just re-queue this capture buffer to vb2 queue. + * This reduce overheads that dq/q unused capture + * buffer. In this case, queued_in_vb2 = true. + */ + mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to rdy_queue %d", + ctx->id, free_frame_buffer->status, + vb->vb2_buf.index, dstbuf->queued_in_vb2); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); + } else if (!dstbuf->queued_in_vb2 && dstbuf->queued_in_v4l2) { + /* + * If buffer in v4l2 driver but not in vb2 queue yet, + * and we get this buffer from free_list, it means + * that codec driver do not use this buffer as + * reference buffer anymore. We should q buffer to vb2 + * queue, so later work thread could get this buffer + * for decode. In this case, queued_in_vb2 = false + * means this buffer is not from previous decode + * output. + */ + mtk_v4l2_debug(2, + "[%d]status=%x queue id=%d to rdy_queue", + ctx->id, free_frame_buffer->status, + vb->vb2_buf.index); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); + dstbuf->queued_in_vb2 = true; + } else { + /* + * Codec driver do not need to reference this capture + * buffer and this buffer is not in v4l2 driver. + * Then we don't need to do any thing, just add log when + * we need to debug buffer flow. + * When this buffer q from user space, it could + * directly q to vb2 buffer + */ + mtk_v4l2_debug(3, "[%d]status=%x err queue id=%d %d %d", + ctx->id, free_frame_buffer->status, + vb->vb2_buf.index, dstbuf->queued_in_vb2, + dstbuf->queued_in_v4l2); + } + dstbuf->used = false; + } + mutex_unlock(&ctx->lock); + return &vb->vb2_buf; +} + +static void clean_display_buffer(struct mtk_vcodec_ctx *ctx) +{ + while (get_display_buffer(ctx)) + ; +} + +static void clean_free_buffer(struct mtk_vcodec_ctx *ctx) +{ + while (get_free_buffer(ctx)) + ; +} + +static void mtk_vdec_queue_res_chg_event(struct mtk_vcodec_ctx *ctx) +{ + static const struct v4l2_event ev_src_ch = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + mtk_v4l2_debug(1, "[%d]", ctx->id); + v4l2_event_queue_fh(&ctx->fh, &ev_src_ch); +} + +static int mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx) +{ + bool res_chg; + int ret; + + ret = vdec_if_decode(ctx, NULL, NULL, &res_chg); + if (ret) + mtk_v4l2_err("DecodeFinal failed, ret=%d", ret); + + clean_display_buffer(ctx); + clean_free_buffer(ctx); + + return 0; +} + +static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx, + unsigned int pixelformat) +{ + const struct mtk_video_fmt *fmt; + struct mtk_q_data *dst_q_data; + unsigned int k; + + dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; + for (k = 0; k < NUM_FORMATS; k++) { + fmt = &mtk_video_formats[k]; + if (fmt->fourcc == pixelformat) { + mtk_v4l2_debug(1, "Update cap fourcc(%d -> %d)", + dst_q_data->fmt->fourcc, pixelformat); + dst_q_data->fmt = fmt; + return; + } + } + + mtk_v4l2_err("Cannot get fourcc(%d), using init value", pixelformat); +} + +static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx) +{ + unsigned int dpbsize = 0; + int ret; + + if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, + &ctx->last_decoded_picinfo)) { + mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", ctx->id); + return -EINVAL; + } + + if (ctx->last_decoded_picinfo.pic_w == 0 || + ctx->last_decoded_picinfo.pic_h == 0 || + ctx->last_decoded_picinfo.buf_w == 0 || + ctx->last_decoded_picinfo.buf_h == 0) { + mtk_v4l2_err("Cannot get correct pic info"); + return -EINVAL; + } + + if (ctx->last_decoded_picinfo.cap_fourcc != ctx->picinfo.cap_fourcc && + ctx->picinfo.cap_fourcc != 0) + mtk_vdec_update_fmt(ctx, ctx->picinfo.cap_fourcc); + + if (ctx->last_decoded_picinfo.pic_w == ctx->picinfo.pic_w || + ctx->last_decoded_picinfo.pic_h == ctx->picinfo.pic_h) + return 0; + + mtk_v4l2_debug(1, "[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)", ctx->id, + ctx->last_decoded_picinfo.pic_w, + ctx->last_decoded_picinfo.pic_h, ctx->picinfo.pic_w, + ctx->picinfo.pic_h, ctx->last_decoded_picinfo.buf_w, + ctx->last_decoded_picinfo.buf_h); + + ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); + if (dpbsize == 0) + mtk_v4l2_err("Incorrect dpb size, ret=%d", ret); + + ctx->dpb_size = dpbsize; + + return ret; +} + +static void mtk_vdec_worker(struct work_struct *work) +{ + struct mtk_vcodec_ctx *ctx = + container_of(work, struct mtk_vcodec_ctx, decode_work); + struct mtk_vcodec_dev *dev = ctx->dev; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct mtk_vcodec_mem buf; + struct vdec_fb *pfb; + bool res_chg = false; + int ret; + struct mtk_video_dec_buf *dst_buf_info, *src_buf_info; + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + if (!src_buf) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_debug(1, "[%d] src_buf empty!!", ctx->id); + return; + } + + dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + if (!dst_buf) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_debug(1, "[%d] dst_buf empty!!", ctx->id); + return; + } + + dst_buf_info = + container_of(dst_buf, struct mtk_video_dec_buf, m2m_buf.vb); + + pfb = &dst_buf_info->frame_buffer; + pfb->base_y.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); + pfb->base_y.dma_addr = + vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + pfb->base_y.size = ctx->picinfo.fb_sz[0]; + + pfb->base_c.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 1); + pfb->base_c.dma_addr = + vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 1); + pfb->base_c.size = ctx->picinfo.fb_sz[1]; + pfb->status = 0; + mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id); + + mtk_v4l2_debug(3, + "id=%d Framebuf pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx", + dst_buf->vb2_buf.index, pfb, pfb->base_y.va, + &pfb->base_y.dma_addr, &pfb->base_c.dma_addr, pfb->base_y.size); + + if (src_buf == &ctx->empty_flush_buf.vb) { + mtk_v4l2_debug(1, "Got empty flush input buffer."); + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + + /* update dst buf status */ + dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + mutex_lock(&ctx->lock); + dst_buf_info->used = false; + mutex_unlock(&ctx->lock); + + vdec_if_decode(ctx, NULL, NULL, &res_chg); + clean_display_buffer(ctx); + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + clean_free_buffer(ctx); + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + return; + } + + src_buf_info = + container_of(src_buf, struct mtk_video_dec_buf, m2m_buf.vb); + + buf.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); + buf.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + buf.size = (size_t)src_buf->vb2_buf.planes[0].bytesused; + if (!buf.va) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_err("[%d] id=%d src_addr is NULL!!", ctx->id, + src_buf->vb2_buf.index); + return; + } + mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p", + ctx->id, buf.va, &buf.dma_addr, buf.size, src_buf); + dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; + dst_buf->timecode = src_buf->timecode; + mutex_lock(&ctx->lock); + dst_buf_info->used = true; + mutex_unlock(&ctx->lock); + src_buf_info->used = true; + + ret = vdec_if_decode(ctx, &buf, pfb, &res_chg); + + if (ret) { + mtk_v4l2_err(" <===[%d], src_buf[%d] sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>", + ctx->id, src_buf->vb2_buf.index, buf.size, + src_buf->vb2_buf.timestamp, dst_buf->vb2_buf.index, ret, res_chg); + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + if (ret == -EIO) { + mutex_lock(&ctx->lock); + src_buf_info->error = true; + mutex_unlock(&ctx->lock); + } + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + } else if (!res_chg) { + /* + * we only return src buffer with VB2_BUF_STATE_DONE + * when decode success without resolution change + */ + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } + + dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + clean_display_buffer(ctx); + clean_free_buffer(ctx); + + if (!ret && res_chg) { + mtk_vdec_pic_info_update(ctx); + /* + * On encountering a resolution change in the stream. + * The driver must first process and decode all + * remaining buffers from before the resolution change + * point, so call flush decode here + */ + mtk_vdec_flush_decoder(ctx); + /* + * After all buffers containing decoded frames from + * before the resolution change point ready to be + * dequeued on the CAPTURE queue, the driver sends a + * V4L2_EVENT_SOURCE_CHANGE event for source change + * type V4L2_EVENT_SRC_CH_RESOLUTION + */ + mtk_vdec_queue_res_chg_event(ctx); + } + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); +} + +static void vb2ops_vdec_stateful_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *src_buf; + struct mtk_vcodec_mem src_mem; + bool res_chg = false; + int ret; + unsigned int dpbsize = 1, i; + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vb2_v4l2; + struct mtk_q_data *dst_q_data; + + mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id, + vb->vb2_queue->type, vb->index, vb); + /* + * check if this buffer is ready to be used after decode + */ + if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + struct mtk_video_dec_buf *buf; + + vb2_v4l2 = to_vb2_v4l2_buffer(vb); + buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, + m2m_buf.vb); + mutex_lock(&ctx->lock); + if (!buf->used) { + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2); + buf->queued_in_vb2 = true; + buf->queued_in_v4l2 = true; + } else { + buf->queued_in_vb2 = false; + buf->queued_in_v4l2 = true; + } + mutex_unlock(&ctx->lock); + return; + } + + v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb)); + + if (ctx->state != MTK_STATE_INIT) { + mtk_v4l2_debug(3, "[%d] already init driver %d", ctx->id, + ctx->state); + return; + } + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + if (!src_buf) { + mtk_v4l2_err("No src buffer"); + return; + } + + if (src_buf == &ctx->empty_flush_buf.vb) { + /* This shouldn't happen. Just in case. */ + mtk_v4l2_err("Invalid flush buffer."); + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + return; + } + + src_mem.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); + src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + src_mem.size = (size_t)src_buf->vb2_buf.planes[0].bytesused; + mtk_v4l2_debug(2, "[%d] buf id=%d va=%p dma=%pad size=%zx", ctx->id, + src_buf->vb2_buf.index, src_mem.va, &src_mem.dma_addr, + src_mem.size); + + ret = vdec_if_decode(ctx, &src_mem, NULL, &res_chg); + if (ret || !res_chg) { + /* + * fb == NULL means to parse SPS/PPS header or + * resolution info in src_mem. Decode can fail + * if there is no SPS header or picture info + * in bs + */ + + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + if (ret == -EIO) { + mtk_v4l2_err("[%d] Unrecoverable error in vdec_if_decode.", ctx->id); + ctx->state = MTK_STATE_ABORT; + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + } else { + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } + mtk_v4l2_debug(ret ? 0 : 1, + "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d", + ctx->id, src_buf->vb2_buf.index, src_mem.size, ret, res_chg); + return; + } + + if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo)) { + mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", ctx->id); + return; + } + + ctx->last_decoded_picinfo = ctx->picinfo; + dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; + for (i = 0; i < dst_q_data->fmt->num_planes; i++) { + dst_q_data->sizeimage[i] = ctx->picinfo.fb_sz[i]; + dst_q_data->bytesperline[i] = ctx->picinfo.buf_w; + } + + mtk_v4l2_debug(2, "[%d] vdec_if_init() OK wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x", + ctx->id, ctx->picinfo.buf_w, ctx->picinfo.buf_h, ctx->picinfo.pic_w, + ctx->picinfo.pic_h, dst_q_data->sizeimage[0], dst_q_data->sizeimage[1]); + + ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); + if (dpbsize == 0) + mtk_v4l2_err("[%d] GET_PARAM_DPB_SIZE fail=%d", ctx->id, ret); + + ctx->dpb_size = dpbsize; + ctx->state = MTK_STATE_HEADER; + mtk_v4l2_debug(1, "[%d] dpbsize=%d", ctx->id, ctx->dpb_size); + + mtk_vdec_queue_res_chg_event(ctx); +} + +static int mtk_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mtk_vcodec_ctx *ctx = ctrl_to_ctx(ctrl); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: + if (ctx->state >= MTK_STATE_HEADER) { + ctrl->val = ctx->dpb_size; + } else { + mtk_v4l2_debug(0, "Seqinfo not ready"); + ctrl->val = 0; + } + break; + default: + ret = -EINVAL; + } + return ret; +} + +static const struct v4l2_ctrl_ops mtk_vcodec_dec_ctrl_ops = { + .g_volatile_ctrl = mtk_vdec_g_v_ctrl, +}; + +static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx) +{ + struct v4l2_ctrl *ctrl; + + v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 1); + + ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl, &mtk_vcodec_dec_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 0, 32, 1, 1); + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + v4l2_ctrl_new_std_menu(&ctx->ctrl_hdl, &mtk_vcodec_dec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + V4L2_MPEG_VIDEO_VP9_PROFILE_0, 0, + V4L2_MPEG_VIDEO_VP9_PROFILE_0); + /* + * H264. Baseline / Extended decoding is not supported. + */ + v4l2_ctrl_new_std_menu(&ctx->ctrl_hdl, &mtk_vcodec_dec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED), + V4L2_MPEG_VIDEO_H264_PROFILE_MAIN); + + if (ctx->ctrl_hdl.error) { + mtk_v4l2_err("Adding control failed %d", ctx->ctrl_hdl.error); + return ctx->ctrl_hdl.error; + } + + v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); + return 0; +} + +static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx) +{ +} + +static struct vb2_ops mtk_vdec_frame_vb2_ops = { + .queue_setup = vb2ops_vdec_queue_setup, + .buf_prepare = vb2ops_vdec_buf_prepare, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = vb2ops_vdec_start_streaming, + + .buf_queue = vb2ops_vdec_stateful_buf_queue, + .buf_init = vb2ops_vdec_buf_init, + .buf_finish = vb2ops_vdec_buf_finish, + .stop_streaming = vb2ops_vdec_stop_streaming, +}; + +const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = { + .init_vdec_params = mtk_init_vdec_params, + .ctrls_setup = mtk_vcodec_dec_ctrls_setup, + .vdec_vb2_ops = &mtk_vdec_frame_vb2_ops, + .vdec_formats = mtk_video_formats, + .num_formats = NUM_FORMATS, + .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX], + .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX], + .vdec_framesizes = mtk_vdec_framesizes, + .num_framesizes = NUM_SUPPORTED_FRAMESIZE, + .worker = mtk_vdec_worker, + .flush_decoder = mtk_vdec_flush_decoder, +}; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 09b8f05a5df8..71f0d353bedc 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -311,6 +311,45 @@ enum mtk_chip { MTK_MT8195, }; +/** + * struct mtk_vcodec_dec_pdata - compatible data for each IC + * @init_vdec_params: init vdec params + * @ctrls_setup: init vcodec dec ctrls + * @worker: worker to start a decode job + * @flush_decoder: function that flushes the decoder + * + * @vdec_vb2_ops: struct vb2_ops + * + * @vdec_formats: supported video decoder formats + * @num_formats: count of video decoder formats + * @default_out_fmt: default output buffer format + * @default_cap_fmt: default capture buffer format + * + * @vdec_framesizes: supported video decoder frame sizes + * @num_framesizes: count of video decoder frame sizes + * + * @uses_stateless_api: whether the decoder uses the stateless API with requests + */ + +struct mtk_vcodec_dec_pdata { + void (*init_vdec_params)(struct mtk_vcodec_ctx *ctx); + int (*ctrls_setup)(struct mtk_vcodec_ctx *ctx); + void (*worker)(struct work_struct *work); + int (*flush_decoder)(struct mtk_vcodec_ctx *ctx); + + struct vb2_ops *vdec_vb2_ops; + + const struct mtk_video_fmt *vdec_formats; + const int num_formats; + const struct mtk_video_fmt *default_out_fmt; + const struct mtk_video_fmt *default_cap_fmt; + + const struct mtk_codec_framesizes *vdec_framesizes; + const int num_framesizes; + + bool uses_stateless_api; +}; + /** * struct mtk_vcodec_enc_pdata - compatible data for each IC * @@ -354,6 +393,7 @@ struct mtk_vcodec_enc_pdata { * @curr_ctx: The context that is waiting for codec hardware * * @reg_base: Mapped address of MTK Vcodec registers. + * @vdec_pdata: decoder IC-specific data * @venc_pdata: encoder IC-specific data * * @fw_handler: used to communicate with the firmware. @@ -389,6 +429,7 @@ struct mtk_vcodec_dev { spinlock_t irqlock; struct mtk_vcodec_ctx *curr_ctx; void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE]; + const struct mtk_vcodec_dec_pdata *vdec_pdata; const struct mtk_vcodec_enc_pdata *venc_pdata; struct mtk_vcodec_fw *fw_handler; -- cgit v1.2.3 From 34754adb8eba715b054b2c6e243eec526a5e856c Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 6 Aug 2021 06:15:23 +0200 Subject: media: mtk-vcodec: vdec: handle firmware version field Firmwares for decoders newer than MT8173 will include an ABI version number in their initialization ack message. Add the capacity to manage it and make initialization fail if the firmware ABI is of a version that we don't support. For MT8173, this ABI version field does not exist ; thus ignore it on this chip. There should only be one firmware version available for it anyway. Signed-off-by: Alexandre Courbot Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../platform/mtk-vcodec/mtk_vcodec_dec_stateful.c | 1 + drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 4 ++++ drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h | 5 +++++ drivers/media/platform/mtk-vcodec/vdec_vpu_if.c | 21 +++++++++++++++++++-- 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c index d77a7688688a..bef49244e61b 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c @@ -613,6 +613,7 @@ static struct vb2_ops mtk_vdec_frame_vb2_ops = { }; const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = { + .chip = MTK_MT8173, .init_vdec_params = mtk_init_vdec_params, .ctrls_setup = mtk_vcodec_dec_ctrls_setup, .vdec_vb2_ops = &mtk_vdec_frame_vb2_ops, diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 71f0d353bedc..9edbc27ee004 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -328,6 +328,8 @@ enum mtk_chip { * @vdec_framesizes: supported video decoder frame sizes * @num_framesizes: count of video decoder frame sizes * + * @chip: chip this decoder is compatible with + * * @uses_stateless_api: whether the decoder uses the stateless API with requests */ @@ -347,6 +349,8 @@ struct mtk_vcodec_dec_pdata { const struct mtk_codec_framesizes *vdec_framesizes; const int num_framesizes; + enum mtk_chip chip; + bool uses_stateless_api; }; diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h index 68e8d5cb16d7..236bd32dcacc 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h +++ b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h @@ -83,12 +83,17 @@ struct vdec_ap_ipi_dec_start { * @status : VPU exeuction result * @ap_inst_addr : AP vcodec_vpu_inst instance address * @vpu_inst_addr : VPU decoder instance address + * @vdec_abi_version: ABI version of the firmware. Kernel can use it to + * ensure that it is compatible with the firmware. + * This field is not valid for MT8173 and must not be + * accessed for this chip. */ struct vdec_vpu_ipi_init_ack { uint32_t msg_id; int32_t status; uint64_t ap_inst_addr; uint32_t vpu_inst_addr; + uint32_t vdec_abi_version; }; #endif diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c index 58b0e6fa8fd2..203089213e67 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c @@ -24,6 +24,22 @@ static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg) vpu->inst_addr = msg->vpu_inst_addr; mtk_vcodec_debug(vpu, "- vpu_inst_addr = 0x%x", vpu->inst_addr); + + /* Firmware version field does not exist on MT8173. */ + if (vpu->ctx->dev->vdec_pdata->chip == MTK_MT8173) + return; + + /* Check firmware version. */ + mtk_vcodec_debug(vpu, "firmware version 0x%x\n", msg->vdec_abi_version); + switch (msg->vdec_abi_version) { + case 1: + break; + default: + mtk_vcodec_err(vpu, "unhandled firmware version 0x%x\n", + msg->vdec_abi_version); + vpu->failure = 1; + break; + } } /* @@ -44,6 +60,9 @@ static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv) mtk_vcodec_debug(vpu, "+ id=%X", msg->msg_id); + vpu->failure = msg->status; + vpu->signaled = 1; + if (msg->status == 0) { switch (msg->msg_id) { case VPU_IPIMSG_DEC_INIT_ACK: @@ -63,8 +82,6 @@ static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv) } mtk_vcodec_debug(vpu, "- id=%X", msg->msg_id); - vpu->failure = msg->status; - vpu->signaled = 1; } static int vcodec_vpu_send_msg(struct vdec_vpu_inst *vpu, void *msg, int len) -- cgit v1.2.3 From 741cc360df230f03fdba1161b90069e77432c73e Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 6 Aug 2021 06:15:24 +0200 Subject: media: mtk-vcodec: support version 2 of decoder firmware ABI Add support for decoder firmware version 2, which makes the kernel responsible for managing the VSI context and is used for stateless codecs. Signed-off-by: Alexandre Courbot Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h | 18 +++++++++++---- drivers/media/platform/mtk-vcodec/vdec_vpu_if.c | 28 +++++++++++++++++++----- drivers/media/platform/mtk-vcodec/vdec_vpu_if.h | 5 +++++ 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h index 236bd32dcacc..5f45a537beb4 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h +++ b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h @@ -29,11 +29,15 @@ enum vdec_ipi_msgid { /** * struct vdec_ap_ipi_cmd - generic AP to VPU ipi command format * @msg_id : vdec_ipi_msgid - * @vpu_inst_addr : VPU decoder instance address + * @vpu_inst_addr : VPU decoder instance address. Used if ABI version < 2. + * @inst_id : instance ID. Used if the ABI version >= 2. */ struct vdec_ap_ipi_cmd { uint32_t msg_id; - uint32_t vpu_inst_addr; + union { + uint32_t vpu_inst_addr; + uint32_t inst_id; + }; }; /** @@ -63,7 +67,8 @@ struct vdec_ap_ipi_init { /** * struct vdec_ap_ipi_dec_start - for AP_IPIMSG_DEC_START * @msg_id : AP_IPIMSG_DEC_START - * @vpu_inst_addr : VPU decoder instance address + * @vpu_inst_addr : VPU decoder instance address. Used if ABI version < 2. + * @inst_id : instance ID. Used if the ABI version >= 2. * @data : Header info * H264 decoder [0]:buf_sz [1]:nal_start * VP8 decoder [0]:width/height @@ -72,7 +77,10 @@ struct vdec_ap_ipi_init { */ struct vdec_ap_ipi_dec_start { uint32_t msg_id; - uint32_t vpu_inst_addr; + union { + uint32_t vpu_inst_addr; + uint32_t inst_id; + }; uint32_t data[3]; uint32_t reserved; }; @@ -87,6 +95,7 @@ struct vdec_ap_ipi_dec_start { * ensure that it is compatible with the firmware. * This field is not valid for MT8173 and must not be * accessed for this chip. + * @inst_id : instance ID. Valid only if the ABI version >= 2. */ struct vdec_vpu_ipi_init_ack { uint32_t msg_id; @@ -94,6 +103,7 @@ struct vdec_vpu_ipi_init_ack { uint64_t ap_inst_addr; uint32_t vpu_inst_addr; uint32_t vdec_abi_version; + uint32_t inst_id; }; #endif diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c index 203089213e67..5dffc459a33d 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c @@ -25,18 +25,30 @@ static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg) mtk_vcodec_debug(vpu, "- vpu_inst_addr = 0x%x", vpu->inst_addr); + /* Set default ABI version if dealing with unversioned firmware. */ + vpu->fw_abi_version = 0; + /* + * Instance ID is only used if ABI version >= 2. Initialize it with + * garbage by default. + */ + vpu->inst_id = 0xdeadbeef; + /* Firmware version field does not exist on MT8173. */ if (vpu->ctx->dev->vdec_pdata->chip == MTK_MT8173) return; /* Check firmware version. */ - mtk_vcodec_debug(vpu, "firmware version 0x%x\n", msg->vdec_abi_version); - switch (msg->vdec_abi_version) { + vpu->fw_abi_version = msg->vdec_abi_version; + mtk_vcodec_debug(vpu, "firmware version 0x%x\n", vpu->fw_abi_version); + switch (vpu->fw_abi_version) { case 1: break; + case 2: + vpu->inst_id = msg->inst_id; + break; default: mtk_vcodec_err(vpu, "unhandled firmware version 0x%x\n", - msg->vdec_abi_version); + vpu->fw_abi_version); vpu->failure = 1; break; } @@ -113,7 +125,10 @@ static int vcodec_send_ap_ipi(struct vdec_vpu_inst *vpu, unsigned int msg_id) memset(&msg, 0, sizeof(msg)); msg.msg_id = msg_id; - msg.vpu_inst_addr = vpu->inst_addr; + if (vpu->fw_abi_version < 2) + msg.vpu_inst_addr = vpu->inst_addr; + else + msg.inst_id = vpu->inst_id; err = vcodec_vpu_send_msg(vpu, &msg, sizeof(msg)); mtk_vcodec_debug(vpu, "- id=%X ret=%d", msg_id, err); @@ -163,7 +178,10 @@ int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len) memset(&msg, 0, sizeof(msg)); msg.msg_id = AP_IPIMSG_DEC_START; - msg.vpu_inst_addr = vpu->inst_addr; + if (vpu->fw_abi_version < 2) + msg.vpu_inst_addr = vpu->inst_addr; + else + msg.inst_id = vpu->inst_id; for (i = 0; i < len; i++) msg.data[i] = data[i]; diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h index 85224eb7e34b..c2ed5b6cab8b 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h @@ -18,6 +18,9 @@ struct mtk_vcodec_ctx; * for control and info share * @failure : VPU execution result status, 0: success, others: fail * @inst_addr : VPU decoder instance address + * @fw_abi_version : ABI version of the firmware. + * @inst_id : if fw_abi_version >= 2, contains the instance ID to be given + * in place of inst_addr in messages. * @signaled : 1 - Host has received ack message from VPU, 0 - not received * @ctx : context for v4l2 layer integration * @dev : platform device of VPU @@ -29,6 +32,8 @@ struct vdec_vpu_inst { void *vsi; int32_t failure; uint32_t inst_addr; + uint32_t fw_abi_version; + uint32_t inst_id; unsigned int signaled; struct mtk_vcodec_ctx *ctx; wait_queue_head_t wq; -- cgit v1.2.3 From ffe5350c016a0de8ac77d32d9d4ea378cc9ff402 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 6 Aug 2021 06:15:25 +0200 Subject: media: add Mediatek's MM21 format Add Mediatek's non-compressed 8 bit block video mode. This format is produced by the MT8183 codec and can be converted to a non-proprietary format by the MDP3 component. Signed-off-by: Alexandre Courbot Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/pixfmt-reserved.rst | 7 +++++++ drivers/media/v4l2-core/v4l2-ioctl.c | 1 + include/uapi/linux/videodev2.h | 1 + 3 files changed, 9 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst index adcad9454175..2f2133b4cd9c 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst @@ -238,6 +238,13 @@ please make a proposal on the linux-media mailing list. It is an opaque intermediate format and the MDP hardware must be used to convert ``V4L2_PIX_FMT_MT21C`` to ``V4L2_PIX_FMT_NV12M``, ``V4L2_PIX_FMT_YUV420M`` or ``V4L2_PIX_FMT_YVU420``. + * .. _V4L2-PIX-FMT-MM21: + + - ``V4L2_PIX_FMT_MM21`` + - 'MM21' + - Non-compressed, tiled two-planar format used by Mediatek MT8183. + This is an opaque intermediate format and the MDP3 hardware can be + used to convert it to other formats. .. raw:: latex diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index ec6fc1ef291e..d4f97ab1b237 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1348,6 +1348,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_TM6000: descr = "A/V + VBI Mux Packet"; break; case V4L2_PIX_FMT_CIT_YYVYUY: descr = "GSPCA CIT YYVYUY"; break; case V4L2_PIX_FMT_KONICA420: descr = "GSPCA KONICA420"; break; + case V4L2_PIX_FMT_MM21: descr = "Mediatek 8-bit Block Format"; break; case V4L2_PIX_FMT_HSV24: descr = "24-bit HSV 8-8-8"; break; case V4L2_PIX_FMT_HSV32: descr = "32-bit XHSV 8-8-8-8"; break; case V4L2_SDR_FMT_CU8: descr = "Complex U8"; break; diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 58392dcd3bf5..5cc9545feb40 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -739,6 +739,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_Y12I v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */ #define V4L2_PIX_FMT_Z16 v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */ #define V4L2_PIX_FMT_MT21C v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode */ +#define V4L2_PIX_FMT_MM21 v4l2_fourcc('M', 'M', '2', '1') /* Mediatek 8-bit block mode, two non-contiguous planes */ #define V4L2_PIX_FMT_INZI v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */ #define V4L2_PIX_FMT_CNF4 v4l2_fourcc('C', 'N', 'F', '4') /* Intel 4-bit packed depth confidence information */ #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* BTTV 8-bit dithered RGB */ -- cgit v1.2.3 From 8cdc3794b2e34b3ee11ddfccf4af3f64344a1a75 Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Fri, 6 Aug 2021 06:15:26 +0200 Subject: media: mtk-vcodec: vdec: support stateless API Support the stateless codec API that will be used by MT8183. [acourbot: refactor, cleanup and split] Signed-off-by: Yunfei Dong Co-developed-by: Alexandre Courbot Signed-off-by: Alexandre Courbot Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/Makefile | 1 + drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 66 +++- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h | 8 +- .../platform/mtk-vcodec/mtk_vcodec_dec_stateless.c | 360 +++++++++++++++++++++ drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 3 + 5 files changed, 434 insertions(+), 4 deletions(-) create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index 9c3cbb5b800e..4ba93d838ab6 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -12,6 +12,7 @@ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ vdec_vpu_if.o \ mtk_vcodec_dec.o \ mtk_vcodec_dec_stateful.o \ + mtk_vcodec_dec_stateless.o \ mtk_vcodec_dec_pm.o \ mtk-vcodec-enc-y := venc/venc_vp8_if.o \ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index a220532802f9..2b334a8a81c6 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -47,7 +47,14 @@ static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx, static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd); + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + + /* Use M2M stateless helper if relevant */ + if (ctx->dev->vdec_pdata->uses_stateless_api) + return v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv, + cmd); + else + return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd); } @@ -62,6 +69,10 @@ static int vidioc_decoder_cmd(struct file *file, void *priv, if (ret) return ret; + /* Use M2M stateless helper if relevant */ + if (ctx->dev->vdec_pdata->uses_stateless_api) + return v4l2_m2m_ioctl_stateless_decoder_cmd(file, priv, cmd); + mtk_v4l2_debug(1, "decoder cmd=%u", cmd->cmd); dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); @@ -401,7 +412,8 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, * Setting OUTPUT format after OUTPUT buffers are allocated is invalid * if using the stateful API. */ - if ((f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) && + if (!dec_pdata->uses_stateless_api && + f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && vb2_is_busy(&ctx->m2m_ctx->out_q_ctx.q)) { mtk_v4l2_err("out_q_ctx buffers already requested"); ret = -EBUSY; @@ -444,6 +456,7 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, ctx->quantization = pix_mp->quantization; ctx->xfer_func = pix_mp->xfer_func; + ctx->current_codec = fmt->fourcc; if (ctx->state == MTK_STATE_FREE) { ret = vdec_if_init(ctx, q_data->fmt->fourcc); if (ret) { @@ -455,6 +468,48 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, } } + /* + * If using the stateless API, S_FMT should have the effect of setting + * the CAPTURE queue resolution no matter which queue it was called on. + */ + if (dec_pdata->uses_stateless_api) { + ctx->picinfo.pic_w = pix_mp->width; + ctx->picinfo.pic_h = pix_mp->height; + + ret = vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo); + if (ret) { + mtk_v4l2_err("[%d]Error!! Get GET_PARAM_PICTURE_INFO Fail", + ctx->id); + return -EINVAL; + } + + ctx->last_decoded_picinfo = ctx->picinfo; + + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 1) { + ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] = + ctx->picinfo.fb_sz[0] + + ctx->picinfo.fb_sz[1]; + ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = + ctx->picinfo.buf_w; + } else { + ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] = + ctx->picinfo.fb_sz[0]; + ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = + ctx->picinfo.buf_w; + ctx->q_data[MTK_Q_DATA_DST].sizeimage[1] = + ctx->picinfo.fb_sz[1]; + ctx->q_data[MTK_Q_DATA_DST].bytesperline[1] = + ctx->picinfo.buf_w; + } + + ctx->q_data[MTK_Q_DATA_DST].coded_width = ctx->picinfo.buf_w; + ctx->q_data[MTK_Q_DATA_DST].coded_height = ctx->picinfo.buf_h; + mtk_v4l2_debug(2, "[%d] vdec_if_init() num_plane = %d wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x", + ctx->id, pix_mp->num_planes, ctx->picinfo.buf_w, ctx->picinfo.buf_h, + ctx->picinfo.pic_w, ctx->picinfo.pic_h, + ctx->q_data[MTK_Q_DATA_DST].sizeimage[0], + ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]); + } return 0; } @@ -746,9 +801,14 @@ void vb2ops_vdec_stop_streaming(struct vb2_queue *q) if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) { - if (src_buf != &ctx->empty_flush_buf.vb) + if (src_buf != &ctx->empty_flush_buf.vb) { + struct media_request *req = + src_buf->vb2_buf.req_obj.req; v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + if (req) + v4l2_ctrl_request_complete(req, &ctx->ctrl_hdl); + } } return; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h index 76856c0b2db8..9fbd24186c1a 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h @@ -44,6 +44,7 @@ struct vdec_fb { * queue yet * @error: An unrecoverable error occurs on this buffer. * @frame_buffer: Decode status, and buffer information of Capture buffer + * @bs_buffer: Output buffer info * * Note : These status information help us track and debug buffer state */ @@ -54,11 +55,16 @@ struct mtk_video_dec_buf { bool queued_in_vb2; bool queued_in_v4l2; bool error; - struct vdec_fb frame_buffer; + + union { + struct vdec_fb frame_buffer; + struct mtk_vcodec_mem bs_buffer; + }; }; extern const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops; extern const struct v4l2_m2m_ops mtk_vdec_m2m_ops; +extern const struct media_device_ops mtk_vcodec_media_ops; /* diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c new file mode 100644 index 000000000000..8f4a1f0a0769 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include + +#include "mtk_vcodec_drv.h" +#include "mtk_vcodec_dec.h" +#include "mtk_vcodec_intr.h" +#include "mtk_vcodec_util.h" +#include "mtk_vcodec_dec_pm.h" +#include "vdec_drv_if.h" + +/** + * struct mtk_stateless_control - CID control type + * @cfg: control configuration + * @codec_type: codec type (V4L2 pixel format) for CID control type + */ +struct mtk_stateless_control { + struct v4l2_ctrl_config cfg; + int codec_type; +}; + +static const struct mtk_stateless_control mtk_stateless_controls[] = { + { + .cfg = { + .id = V4L2_CID_STATELESS_H264_SPS, + }, + .codec_type = V4L2_PIX_FMT_H264_SLICE, + }, + { + .cfg = { + .id = V4L2_CID_STATELESS_H264_PPS, + }, + .codec_type = V4L2_PIX_FMT_H264_SLICE, + }, + { + .cfg = { + .id = V4L2_CID_STATELESS_H264_SCALING_MATRIX, + }, + .codec_type = V4L2_PIX_FMT_H264_SLICE, + }, + { + .cfg = { + .id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, + }, + .codec_type = V4L2_PIX_FMT_H264_SLICE, + }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .menu_skip_mask = + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED), + }, + .codec_type = V4L2_PIX_FMT_H264_SLICE, + }, + { + .cfg = { + .id = V4L2_CID_STATELESS_H264_DECODE_MODE, + .min = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + .def = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + .max = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + }, + .codec_type = V4L2_PIX_FMT_H264_SLICE, + }, + { + .cfg = { + .id = V4L2_CID_STATELESS_H264_START_CODE, + .min = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + .def = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + .max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + }, + .codec_type = V4L2_PIX_FMT_H264_SLICE, + } +}; + +#define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls) + +static const struct mtk_video_fmt mtk_video_formats[] = { + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .type = MTK_FMT_DEC, + .num_planes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_MM21, + .type = MTK_FMT_FRAME, + .num_planes = 2, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) +#define DEFAULT_OUT_FMT_IDX 0 +#define DEFAULT_CAP_FMT_IDX 1 + +static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, + }, +}; + +#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) + +static void mtk_vdec_stateless_set_dst_payload(struct mtk_vcodec_ctx *ctx, + struct vdec_fb *fb) +{ + struct mtk_video_dec_buf *vdec_frame_buf = + container_of(fb, struct mtk_video_dec_buf, frame_buffer); + struct vb2_v4l2_buffer *vb = &vdec_frame_buf->m2m_buf.vb; + unsigned int cap_y_size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0]; + + vb2_set_plane_payload(&vb->vb2_buf, 0, cap_y_size); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) { + unsigned int cap_c_size = + ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]; + + vb2_set_plane_payload(&vb->vb2_buf, 1, cap_c_size); + } +} + +static struct vdec_fb *vdec_get_cap_buffer(struct mtk_vcodec_ctx *ctx, + struct vb2_v4l2_buffer *vb2_v4l2) +{ + struct mtk_video_dec_buf *framebuf = + container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb); + struct vdec_fb *pfb = &framebuf->frame_buffer; + struct vb2_buffer *dst_buf = &vb2_v4l2->vb2_buf; + + pfb = &framebuf->frame_buffer; + pfb->base_y.va = NULL; + pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + pfb->base_y.size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0]; + + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) { + pfb->base_c.va = NULL; + pfb->base_c.dma_addr = + vb2_dma_contig_plane_dma_addr(dst_buf, 1); + pfb->base_c.size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]; + } + mtk_v4l2_debug(1, "id=%d Framebuf pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx frame_count = %d", + dst_buf->index, pfb, pfb->base_y.va, &pfb->base_y.dma_addr, + &pfb->base_c.dma_addr, pfb->base_y.size, ctx->decoded_frame_cnt); + + return pfb; +} + +static void vb2ops_vdec_buf_request_complete(struct vb2_buffer *vb) +{ + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->ctrl_hdl); +} + +static void mtk_vdec_worker(struct work_struct *work) +{ + struct mtk_vcodec_ctx *ctx = + container_of(work, struct mtk_vcodec_ctx, decode_work); + struct mtk_vcodec_dev *dev = ctx->dev; + struct vb2_v4l2_buffer *vb2_v4l2_src, *vb2_v4l2_dst; + struct vb2_buffer *vb2_src; + struct mtk_vcodec_mem *bs_src; + struct mtk_video_dec_buf *dec_buf_src; + struct media_request *src_buf_req; + struct vdec_fb *dst_buf; + bool res_chg = false; + int ret; + + vb2_v4l2_src = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + if (!vb2_v4l2_src) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_debug(1, "[%d] no available source buffer", ctx->id); + return; + } + + vb2_v4l2_dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + if (!vb2_v4l2_dst) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_debug(1, "[%d] no available destination buffer", ctx->id); + return; + } + + vb2_src = &vb2_v4l2_src->vb2_buf; + dec_buf_src = container_of(vb2_v4l2_src, struct mtk_video_dec_buf, + m2m_buf.vb); + bs_src = &dec_buf_src->bs_buffer; + + mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id, + vb2_src->vb2_queue->type, vb2_src->index, vb2_src); + + bs_src->va = NULL; + bs_src->dma_addr = vb2_dma_contig_plane_dma_addr(vb2_src, 0); + bs_src->size = (size_t)vb2_src->planes[0].bytesused; + + mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p", + ctx->id, bs_src->va, &bs_src->dma_addr, bs_src->size, vb2_src); + /* Apply request controls. */ + src_buf_req = vb2_src->req_obj.req; + if (src_buf_req) + v4l2_ctrl_request_setup(src_buf_req, &ctx->ctrl_hdl); + else + mtk_v4l2_err("vb2 buffer media request is NULL"); + + dst_buf = vdec_get_cap_buffer(ctx, vb2_v4l2_dst); + v4l2_m2m_buf_copy_metadata(vb2_v4l2_src, vb2_v4l2_dst, true); + ret = vdec_if_decode(ctx, bs_src, dst_buf, &res_chg); + if (ret) { + mtk_v4l2_err(" <===[%d], src_buf[%d] sz=0x%zx pts=%llu vdec_if_decode() ret=%d res_chg=%d===>", + ctx->id, vb2_src->index, bs_src->size, + vb2_src->timestamp, ret, res_chg); + if (ret == -EIO) { + mutex_lock(&ctx->lock); + dec_buf_src->error = true; + mutex_unlock(&ctx->lock); + } + } + + mtk_vdec_stateless_set_dst_payload(ctx, dst_buf); + + v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx, + ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + + v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl); +} + +static void vb2ops_vdec_stateless_buf_queue(struct vb2_buffer *vb) +{ + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vb2_v4l2 = to_vb2_v4l2_buffer(vb); + + mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id, vb->vb2_queue->type, vb->index, vb); + + mutex_lock(&ctx->lock); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2); + mutex_unlock(&ctx->lock); + if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return; + + /* If an OUTPUT buffer, we may need to update the state */ + if (ctx->state == MTK_STATE_INIT) { + ctx->state = MTK_STATE_HEADER; + mtk_v4l2_debug(1, "Init driver from init to header."); + } else { + mtk_v4l2_debug(3, "[%d] already init driver %d", ctx->id, ctx->state); + } +} + +static int mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx) +{ + bool res_chg; + + return vdec_if_decode(ctx, NULL, NULL, &res_chg); +} + +static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx) +{ + unsigned int i; + + v4l2_ctrl_handler_init(&ctx->ctrl_hdl, NUM_CTRLS); + if (ctx->ctrl_hdl.error) { + mtk_v4l2_err("v4l2_ctrl_handler_init failed\n"); + return ctx->ctrl_hdl.error; + } + + for (i = 0; i < NUM_CTRLS; i++) { + struct v4l2_ctrl_config cfg = mtk_stateless_controls[i].cfg; + + v4l2_ctrl_new_custom(&ctx->ctrl_hdl, &cfg, NULL); + if (ctx->ctrl_hdl.error) { + mtk_v4l2_err("Adding control %d failed %d", i, ctx->ctrl_hdl.error); + return ctx->ctrl_hdl.error; + } + } + + v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); + + return 0; +} + +static int fops_media_request_validate(struct media_request *mreq) +{ + const unsigned int buffer_cnt = vb2_request_buffer_cnt(mreq); + + switch (buffer_cnt) { + case 1: + /* We expect exactly one buffer with the request */ + break; + case 0: + mtk_v4l2_debug(1, "No buffer provided with the request"); + return -ENOENT; + default: + mtk_v4l2_debug(1, "Too many buffers (%d) provided with the request", + buffer_cnt); + return -EINVAL; + } + + return vb2_request_validate(mreq); +} + +const struct media_device_ops mtk_vcodec_media_ops = { + .req_validate = fops_media_request_validate, + .req_queue = v4l2_m2m_request_queue, +}; + +static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx) +{ + struct vb2_queue *src_vq; + + src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + + /* Support request api for output plane */ + src_vq->supports_requests = true; + src_vq->requires_requests = true; +} + +static int vb2ops_vdec_out_buf_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + vbuf->field = V4L2_FIELD_NONE; + return 0; +} + +static struct vb2_ops mtk_vdec_request_vb2_ops = { + .queue_setup = vb2ops_vdec_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = vb2ops_vdec_start_streaming, + .stop_streaming = vb2ops_vdec_stop_streaming, + + .buf_queue = vb2ops_vdec_stateless_buf_queue, + .buf_out_validate = vb2ops_vdec_out_buf_validate, + .buf_init = vb2ops_vdec_buf_init, + .buf_prepare = vb2ops_vdec_buf_prepare, + .buf_finish = vb2ops_vdec_buf_finish, + .buf_request_complete = vb2ops_vdec_buf_request_complete, +}; + +const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = { + .chip = MTK_MT8183, + .init_vdec_params = mtk_init_vdec_params, + .ctrls_setup = mtk_vcodec_dec_ctrls_setup, + .vdec_vb2_ops = &mtk_vdec_request_vb2_ops, + .vdec_formats = mtk_video_formats, + .num_formats = NUM_FORMATS, + .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX], + .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX], + .vdec_framesizes = mtk_vdec_framesizes, + .num_framesizes = NUM_SUPPORTED_FRAMESIZE, + .uses_stateless_api = true, + .worker = mtk_vdec_worker, + .flush_decoder = mtk_vdec_flush_decoder, +}; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 9edbc27ee004..cf4d56567b02 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -253,6 +253,7 @@ struct vdec_pic_info { * @empty_flush_buf: a fake size-0 capture buffer that indicates flush. Only * to be used with encoder and stateful decoder. * @is_flushing: set to true if flushing is in progress. + * @current_codec: current set input codec, in V4L2 pixel format * * @colorspace: enum v4l2_colorspace; supplemental to pixelformat * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding @@ -294,6 +295,8 @@ struct mtk_vcodec_ctx { struct v4l2_m2m_buffer empty_flush_buf; bool is_flushing; + u32 current_codec; + enum v4l2_colorspace colorspace; enum v4l2_ycbcr_encoding ycbcr_enc; enum v4l2_quantization quantization; -- cgit v1.2.3 From 06fa5f757dc5a5687e1cdd13097c3265735f60bf Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Fri, 6 Aug 2021 06:15:27 +0200 Subject: media: mtk-vcodec: vdec: support stateless H.264 decoding Add support for H.264 decoding using the stateless API, as supported by MT8183. This support takes advantage of the V4L2 H.264 reference list builders. [acourbot: refactor, cleanup and split] [tzungbi: fix missing kerneldoc issue] [hverkuil: fix trivial kerneldoc typo] Signed-off-by: Yunfei Dong Co-developed-by: Alexandre Courbot Signed-off-by: Alexandre Courbot Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 1 + drivers/media/platform/mtk-vcodec/Makefile | 1 + .../platform/mtk-vcodec/vdec/vdec_h264_req_if.c | 774 +++++++++++++++++++++ drivers/media/platform/mtk-vcodec/vdec_drv_if.c | 3 + drivers/media/platform/mtk-vcodec/vdec_drv_if.h | 1 + 5 files changed, 780 insertions(+) create mode 100644 drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 157c924686e4..ae1468aa1b4e 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -314,6 +314,7 @@ config VIDEO_MEDIATEK_VCODEC select V4L2_MEM2MEM_DEV select VIDEO_MEDIATEK_VCODEC_VPU if VIDEO_MEDIATEK_VPU select VIDEO_MEDIATEK_VCODEC_SCP if MTK_SCP + select V4L2_H264 help Mediatek video codec driver provides HW capability to encode and decode in a range of video formats on MT8173 diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index 4ba93d838ab6..ca8e9e7a9c4e 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ vdec/vdec_vp8_if.o \ vdec/vdec_vp9_if.o \ + vdec/vdec_h264_req_if.o \ mtk_vcodec_dec_drv.o \ vdec_drv_if.o \ vdec_vpu_if.o \ diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c new file mode 100644 index 000000000000..946c23088308 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c @@ -0,0 +1,774 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include + +#include "../mtk_vcodec_util.h" +#include "../mtk_vcodec_dec.h" +#include "../mtk_vcodec_intr.h" +#include "../vdec_drv_base.h" +#include "../vdec_drv_if.h" +#include "../vdec_vpu_if.h" + +#define BUF_PREDICTION_SZ (64 * 4096) +#define MB_UNIT_LEN 16 + +/* get used parameters for sps/pps */ +#define GET_MTK_VDEC_FLAG(cond, flag) \ + { dst_param->cond = ((src_param->flags & (flag)) ? (1) : (0)); } +#define GET_MTK_VDEC_PARAM(param) \ + { dst_param->param = src_param->param; } +/* motion vector size (bytes) for every macro block */ +#define HW_MB_STORE_SZ 64 + +#define H264_MAX_FB_NUM 17 +#define H264_MAX_MV_NUM 32 +#define HDR_PARSING_BUF_SZ 1024 + +/** + * struct mtk_h264_dpb_info - h264 dpb information + * @y_dma_addr: Y bitstream physical address + * @c_dma_addr: CbCr bitstream physical address + * @reference_flag: reference picture flag (short/long term reference picture) + * @field: field picture flag + */ +struct mtk_h264_dpb_info { + dma_addr_t y_dma_addr; + dma_addr_t c_dma_addr; + int reference_flag; + int field; +}; + +/* + * struct mtk_h264_sps_param - parameters for sps + */ +struct mtk_h264_sps_param { + unsigned char chroma_format_idc; + unsigned char bit_depth_luma_minus8; + unsigned char bit_depth_chroma_minus8; + unsigned char log2_max_frame_num_minus4; + unsigned char pic_order_cnt_type; + unsigned char log2_max_pic_order_cnt_lsb_minus4; + unsigned char max_num_ref_frames; + unsigned char separate_colour_plane_flag; + unsigned short pic_width_in_mbs_minus1; + unsigned short pic_height_in_map_units_minus1; + unsigned int max_frame_nums; + unsigned char qpprime_y_zero_transform_bypass_flag; + unsigned char delta_pic_order_always_zero_flag; + unsigned char frame_mbs_only_flag; + unsigned char mb_adaptive_frame_field_flag; + unsigned char direct_8x8_inference_flag; + unsigned char reserved[3]; +}; + +/* + * struct mtk_h264_pps_param - parameters for pps + */ +struct mtk_h264_pps_param { + unsigned char num_ref_idx_l0_default_active_minus1; + unsigned char num_ref_idx_l1_default_active_minus1; + unsigned char weighted_bipred_idc; + char pic_init_qp_minus26; + char chroma_qp_index_offset; + char second_chroma_qp_index_offset; + unsigned char entropy_coding_mode_flag; + unsigned char pic_order_present_flag; + unsigned char deblocking_filter_control_present_flag; + unsigned char constrained_intra_pred_flag; + unsigned char weighted_pred_flag; + unsigned char redundant_pic_cnt_present_flag; + unsigned char transform_8x8_mode_flag; + unsigned char scaling_matrix_present_flag; + unsigned char reserved[2]; +}; + +struct slice_api_h264_scaling_matrix { + unsigned char scaling_list_4x4[6][16]; + unsigned char scaling_list_8x8[6][64]; +}; + +struct slice_h264_dpb_entry { + unsigned long long reference_ts; + unsigned short frame_num; + unsigned short pic_num; + /* Note that field is indicated by v4l2_buffer.field */ + int top_field_order_cnt; + int bottom_field_order_cnt; + unsigned int flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */ +}; + +/* + * struct slice_api_h264_decode_param - parameters for decode. + */ +struct slice_api_h264_decode_param { + struct slice_h264_dpb_entry dpb[16]; + unsigned short num_slices; + unsigned short nal_ref_idc; + unsigned char ref_pic_list_p0[32]; + unsigned char ref_pic_list_b0[32]; + unsigned char ref_pic_list_b1[32]; + int top_field_order_cnt; + int bottom_field_order_cnt; + unsigned int flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */ +}; + +/* + * struct mtk_h264_dec_slice_param - parameters for decode current frame + */ +struct mtk_h264_dec_slice_param { + struct mtk_h264_sps_param sps; + struct mtk_h264_pps_param pps; + struct slice_api_h264_scaling_matrix scaling_matrix; + struct slice_api_h264_decode_param decode_params; + struct mtk_h264_dpb_info h264_dpb_info[16]; +}; + +/** + * struct h264_fb - h264 decode frame buffer information + * @vdec_fb_va : virtual address of struct vdec_fb + * @y_fb_dma : dma address of Y frame buffer (luma) + * @c_fb_dma : dma address of C frame buffer (chroma) + * @poc : picture order count of frame buffer + * @reserved : for 8 bytes alignment + */ +struct h264_fb { + u64 vdec_fb_va; + u64 y_fb_dma; + u64 c_fb_dma; + s32 poc; + u32 reserved; +}; + +/** + * struct vdec_h264_dec_info - decode information + * @dpb_sz : decoding picture buffer size + * @resolution_changed : resoltion change happen + * @realloc_mv_buf : flag to notify driver to re-allocate mv buffer + * @cap_num_planes : number planes of capture buffer + * @bs_dma : Input bit-stream buffer dma address + * @y_fb_dma : Y frame buffer dma address + * @c_fb_dma : C frame buffer dma address + * @vdec_fb_va : VDEC frame buffer struct virtual address + */ +struct vdec_h264_dec_info { + u32 dpb_sz; + u32 resolution_changed; + u32 realloc_mv_buf; + u32 cap_num_planes; + u64 bs_dma; + u64 y_fb_dma; + u64 c_fb_dma; + u64 vdec_fb_va; +}; + +/** + * struct vdec_h264_vsi - shared memory for decode information exchange + * between VPU and Host. + * The memory is allocated by VPU then mapping to Host + * in vpu_dec_init() and freed in vpu_dec_deinit() + * by VPU. + * AP-W/R : AP is writer/reader on this item + * VPU-W/R: VPU is write/reader on this item + * @pred_buf_dma : HW working predication buffer dma address (AP-W, VPU-R) + * @mv_buf_dma : HW working motion vector buffer dma address (AP-W, VPU-R) + * @dec : decode information (AP-R, VPU-W) + * @pic : picture information (AP-R, VPU-W) + * @crop : crop information (AP-R, VPU-W) + * @h264_slice_params : the parameters that hardware use to decode + */ +struct vdec_h264_vsi { + u64 pred_buf_dma; + u64 mv_buf_dma[H264_MAX_MV_NUM]; + struct vdec_h264_dec_info dec; + struct vdec_pic_info pic; + struct v4l2_rect crop; + struct mtk_h264_dec_slice_param h264_slice_params; +}; + +/** + * struct vdec_h264_slice_inst - h264 decoder instance + * @num_nalu : how many nalus be decoded + * @ctx : point to mtk_vcodec_ctx + * @pred_buf : HW working predication buffer + * @mv_buf : HW working motion vector buffer + * @vpu : VPU instance + * @vsi_ctx : Local VSI data for this decoding context + * @h264_slice_param : the parameters that hardware use to decode + * @dpb : decoded picture buffer used to store reference buffer information + */ +struct vdec_h264_slice_inst { + unsigned int num_nalu; + struct mtk_vcodec_ctx *ctx; + struct mtk_vcodec_mem pred_buf; + struct mtk_vcodec_mem mv_buf[H264_MAX_MV_NUM]; + struct vdec_vpu_inst vpu; + struct vdec_h264_vsi vsi_ctx; + struct mtk_h264_dec_slice_param h264_slice_param; + + struct v4l2_h264_dpb_entry dpb[16]; +}; + +static void *get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id) +{ + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, id); + + return ctrl->p_cur.p; +} + +static void get_h264_dpb_list(struct vdec_h264_slice_inst *inst, + struct mtk_h264_dec_slice_param *slice_param) +{ + struct vb2_queue *vq; + struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vb2_v4l2; + u64 index; + + vq = v4l2_m2m_get_vq(inst->ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + + for (index = 0; index < ARRAY_SIZE(slice_param->decode_params.dpb); index++) { + const struct slice_h264_dpb_entry *dpb; + int vb2_index; + + dpb = &slice_param->decode_params.dpb[index]; + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) { + slice_param->h264_dpb_info[index].reference_flag = 0; + continue; + } + + vb2_index = vb2_find_timestamp(vq, dpb->reference_ts, 0); + if (vb2_index < 0) { + mtk_vcodec_err(inst, "Reference invalid: dpb_index(%lld) reference_ts(%lld)", + index, dpb->reference_ts); + continue; + } + /* 1 for short term reference, 2 for long term reference */ + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) + slice_param->h264_dpb_info[index].reference_flag = 1; + else + slice_param->h264_dpb_info[index].reference_flag = 2; + + vb = vq->bufs[vb2_index]; + vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); + slice_param->h264_dpb_info[index].field = vb2_v4l2->field; + + slice_param->h264_dpb_info[index].y_dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 0); + if (inst->ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) { + slice_param->h264_dpb_info[index].c_dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 1); + } + } +} + +static void get_h264_sps_parameters(struct mtk_h264_sps_param *dst_param, + const struct v4l2_ctrl_h264_sps *src_param) +{ + GET_MTK_VDEC_PARAM(chroma_format_idc); + GET_MTK_VDEC_PARAM(bit_depth_luma_minus8); + GET_MTK_VDEC_PARAM(bit_depth_chroma_minus8); + GET_MTK_VDEC_PARAM(log2_max_frame_num_minus4); + GET_MTK_VDEC_PARAM(pic_order_cnt_type); + GET_MTK_VDEC_PARAM(log2_max_pic_order_cnt_lsb_minus4); + GET_MTK_VDEC_PARAM(max_num_ref_frames); + GET_MTK_VDEC_PARAM(pic_width_in_mbs_minus1); + GET_MTK_VDEC_PARAM(pic_height_in_map_units_minus1); + + GET_MTK_VDEC_FLAG(separate_colour_plane_flag, + V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE); + GET_MTK_VDEC_FLAG(qpprime_y_zero_transform_bypass_flag, + V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS); + GET_MTK_VDEC_FLAG(delta_pic_order_always_zero_flag, + V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO); + GET_MTK_VDEC_FLAG(frame_mbs_only_flag, + V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY); + GET_MTK_VDEC_FLAG(mb_adaptive_frame_field_flag, + V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD); + GET_MTK_VDEC_FLAG(direct_8x8_inference_flag, + V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE); +} + +static void get_h264_pps_parameters(struct mtk_h264_pps_param *dst_param, + const struct v4l2_ctrl_h264_pps *src_param) +{ + GET_MTK_VDEC_PARAM(num_ref_idx_l0_default_active_minus1); + GET_MTK_VDEC_PARAM(num_ref_idx_l1_default_active_minus1); + GET_MTK_VDEC_PARAM(weighted_bipred_idc); + GET_MTK_VDEC_PARAM(pic_init_qp_minus26); + GET_MTK_VDEC_PARAM(chroma_qp_index_offset); + GET_MTK_VDEC_PARAM(second_chroma_qp_index_offset); + + GET_MTK_VDEC_FLAG(entropy_coding_mode_flag, + V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE); + GET_MTK_VDEC_FLAG(pic_order_present_flag, + V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT); + GET_MTK_VDEC_FLAG(weighted_pred_flag, + V4L2_H264_PPS_FLAG_WEIGHTED_PRED); + GET_MTK_VDEC_FLAG(deblocking_filter_control_present_flag, + V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT); + GET_MTK_VDEC_FLAG(constrained_intra_pred_flag, + V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED); + GET_MTK_VDEC_FLAG(redundant_pic_cnt_present_flag, + V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT); + GET_MTK_VDEC_FLAG(transform_8x8_mode_flag, + V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE); + GET_MTK_VDEC_FLAG(scaling_matrix_present_flag, + V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT); +} + +static void +get_h264_scaling_matrix(struct slice_api_h264_scaling_matrix *dst_matrix, + const struct v4l2_ctrl_h264_scaling_matrix *src_matrix) +{ + memcpy(dst_matrix->scaling_list_4x4, src_matrix->scaling_list_4x4, + sizeof(dst_matrix->scaling_list_4x4)); + + memcpy(dst_matrix->scaling_list_8x8, src_matrix->scaling_list_8x8, + sizeof(dst_matrix->scaling_list_8x8)); +} + +static void +get_h264_decode_parameters(struct slice_api_h264_decode_param *dst_params, + const struct v4l2_ctrl_h264_decode_params *src_params, + const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dst_params->dpb); i++) { + struct slice_h264_dpb_entry *dst_entry = &dst_params->dpb[i]; + const struct v4l2_h264_dpb_entry *src_entry = &dpb[i]; + + dst_entry->reference_ts = src_entry->reference_ts; + dst_entry->frame_num = src_entry->frame_num; + dst_entry->pic_num = src_entry->pic_num; + dst_entry->top_field_order_cnt = src_entry->top_field_order_cnt; + dst_entry->bottom_field_order_cnt = + src_entry->bottom_field_order_cnt; + dst_entry->flags = src_entry->flags; + } + + /* + * num_slices is a leftover from the old H.264 support and is ignored + * by the firmware. + */ + dst_params->num_slices = 0; + dst_params->nal_ref_idc = src_params->nal_ref_idc; + dst_params->top_field_order_cnt = src_params->top_field_order_cnt; + dst_params->bottom_field_order_cnt = src_params->bottom_field_order_cnt; + dst_params->flags = src_params->flags; +} + +static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a, + const struct v4l2_h264_dpb_entry *b) +{ + return a->top_field_order_cnt == b->top_field_order_cnt && + a->bottom_field_order_cnt == b->bottom_field_order_cnt; +} + +/* + * Move DPB entries of dec_param that refer to a frame already existing in dpb + * into the already existing slot in dpb, and move other entries into new slots. + * + * This function is an adaptation of the similarly-named function in + * hantro_h264.c. + */ +static void update_dpb(const struct v4l2_ctrl_h264_decode_params *dec_param, + struct v4l2_h264_dpb_entry *dpb) +{ + DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + DECLARE_BITMAP(in_use, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + DECLARE_BITMAP(used, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + unsigned int i, j; + + /* Disable all entries by default, and mark the ones in use. */ + for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + set_bit(i, in_use); + dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; + } + + /* Try to match new DPB entries with existing ones by their POCs. */ + for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + + if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + + /* + * To cut off some comparisons, iterate only on target DPB + * entries were already used. + */ + for_each_set_bit(j, in_use, ARRAY_SIZE(dec_param->dpb)) { + struct v4l2_h264_dpb_entry *cdpb; + + cdpb = &dpb[j]; + if (!dpb_entry_match(cdpb, ndpb)) + continue; + + *cdpb = *ndpb; + set_bit(j, used); + /* Don't reiterate on this one. */ + clear_bit(j, in_use); + break; + } + + if (j == ARRAY_SIZE(dec_param->dpb)) + set_bit(i, new); + } + + /* For entries that could not be matched, use remaining free slots. */ + for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + struct v4l2_h264_dpb_entry *cdpb; + + /* + * Both arrays are of the same sizes, so there is no way + * we can end up with no space in target array, unless + * something is buggy. + */ + j = find_first_zero_bit(used, ARRAY_SIZE(dec_param->dpb)); + if (WARN_ON(j >= ARRAY_SIZE(dec_param->dpb))) + return; + + cdpb = &dpb[j]; + *cdpb = *ndpb; + set_bit(j, used); + } +} + +/* + * The firmware expects unused reflist entries to have the value 0x20. + */ +static void fixup_ref_list(u8 *ref_list, size_t num_valid) +{ + memset(&ref_list[num_valid], 0x20, 32 - num_valid); +} + +static void get_vdec_decode_parameters(struct vdec_h264_slice_inst *inst) +{ + const struct v4l2_ctrl_h264_decode_params *dec_params = + get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + const struct v4l2_ctrl_h264_sps *sps = + get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SPS); + const struct v4l2_ctrl_h264_pps *pps = + get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_PPS); + const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix = + get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX); + struct mtk_h264_dec_slice_param *slice_param = &inst->h264_slice_param; + struct v4l2_h264_reflist_builder reflist_builder; + u8 *p0_reflist = slice_param->decode_params.ref_pic_list_p0; + u8 *b0_reflist = slice_param->decode_params.ref_pic_list_b0; + u8 *b1_reflist = slice_param->decode_params.ref_pic_list_b1; + + update_dpb(dec_params, inst->dpb); + + get_h264_sps_parameters(&slice_param->sps, sps); + get_h264_pps_parameters(&slice_param->pps, pps); + get_h264_scaling_matrix(&slice_param->scaling_matrix, scaling_matrix); + get_h264_decode_parameters(&slice_param->decode_params, dec_params, + inst->dpb); + get_h264_dpb_list(inst, slice_param); + + /* Build the reference lists */ + v4l2_h264_init_reflist_builder(&reflist_builder, dec_params, sps, + inst->dpb); + v4l2_h264_build_p_ref_list(&reflist_builder, p0_reflist); + v4l2_h264_build_b_ref_lists(&reflist_builder, b0_reflist, b1_reflist); + /* Adapt the built lists to the firmware's expectations */ + fixup_ref_list(p0_reflist, reflist_builder.num_valid); + fixup_ref_list(b0_reflist, reflist_builder.num_valid); + fixup_ref_list(b1_reflist, reflist_builder.num_valid); + + memcpy(&inst->vsi_ctx.h264_slice_params, slice_param, + sizeof(inst->vsi_ctx.h264_slice_params)); +} + +static unsigned int get_mv_buf_size(unsigned int width, unsigned int height) +{ + int unit_size = (width / MB_UNIT_LEN) * (height / MB_UNIT_LEN) + 8; + + return HW_MB_STORE_SZ * unit_size; +} + +static int allocate_predication_buf(struct vdec_h264_slice_inst *inst) +{ + int err; + + inst->pred_buf.size = BUF_PREDICTION_SZ; + err = mtk_vcodec_mem_alloc(inst->ctx, &inst->pred_buf); + if (err) { + mtk_vcodec_err(inst, "failed to allocate ppl buf"); + return err; + } + + inst->vsi_ctx.pred_buf_dma = inst->pred_buf.dma_addr; + return 0; +} + +static void free_predication_buf(struct vdec_h264_slice_inst *inst) +{ + struct mtk_vcodec_mem *mem = &inst->pred_buf; + + mtk_vcodec_debug_enter(inst); + + inst->vsi_ctx.pred_buf_dma = 0; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); +} + +static int alloc_mv_buf(struct vdec_h264_slice_inst *inst, + struct vdec_pic_info *pic) +{ + int i; + int err; + struct mtk_vcodec_mem *mem = NULL; + unsigned int buf_sz = get_mv_buf_size(pic->buf_w, pic->buf_h); + + mtk_v4l2_debug(3, "size = 0x%lx", buf_sz); + for (i = 0; i < H264_MAX_MV_NUM; i++) { + mem = &inst->mv_buf[i]; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + mem->size = buf_sz; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "failed to allocate mv buf"); + return err; + } + inst->vsi_ctx.mv_buf_dma[i] = mem->dma_addr; + } + + return 0; +} + +static void free_mv_buf(struct vdec_h264_slice_inst *inst) +{ + int i; + struct mtk_vcodec_mem *mem; + + for (i = 0; i < H264_MAX_MV_NUM; i++) { + inst->vsi_ctx.mv_buf_dma[i] = 0; + mem = &inst->mv_buf[i]; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + } +} + +static void get_pic_info(struct vdec_h264_slice_inst *inst, + struct vdec_pic_info *pic) +{ + struct mtk_vcodec_ctx *ctx = inst->ctx; + + ctx->picinfo.buf_w = (ctx->picinfo.pic_w + 15) & 0xFFFFFFF0; + ctx->picinfo.buf_h = (ctx->picinfo.pic_h + 31) & 0xFFFFFFE0; + ctx->picinfo.fb_sz[0] = ctx->picinfo.buf_w * ctx->picinfo.buf_h; + ctx->picinfo.fb_sz[1] = ctx->picinfo.fb_sz[0] >> 1; + inst->vsi_ctx.dec.cap_num_planes = + ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes; + + *pic = ctx->picinfo; + mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", + ctx->picinfo.pic_w, ctx->picinfo.pic_h, + ctx->picinfo.buf_w, ctx->picinfo.buf_h); + mtk_vcodec_debug(inst, "Y/C(%d, %d)", ctx->picinfo.fb_sz[0], + ctx->picinfo.fb_sz[1]); + + if (ctx->last_decoded_picinfo.pic_w != ctx->picinfo.pic_w || + ctx->last_decoded_picinfo.pic_h != ctx->picinfo.pic_h) { + inst->vsi_ctx.dec.resolution_changed = true; + if (ctx->last_decoded_picinfo.buf_w != ctx->picinfo.buf_w || + ctx->last_decoded_picinfo.buf_h != ctx->picinfo.buf_h) + inst->vsi_ctx.dec.realloc_mv_buf = true; + + mtk_v4l2_debug(1, "ResChg: (%d %d) : old(%d, %d) -> new(%d, %d)", + inst->vsi_ctx.dec.resolution_changed, + inst->vsi_ctx.dec.realloc_mv_buf, + ctx->last_decoded_picinfo.pic_w, + ctx->last_decoded_picinfo.pic_h, + ctx->picinfo.pic_w, ctx->picinfo.pic_h); + } +} + +static void get_crop_info(struct vdec_h264_slice_inst *inst, struct v4l2_rect *cr) +{ + cr->left = inst->vsi_ctx.crop.left; + cr->top = inst->vsi_ctx.crop.top; + cr->width = inst->vsi_ctx.crop.width; + cr->height = inst->vsi_ctx.crop.height; + + mtk_vcodec_debug(inst, "l=%d, t=%d, w=%d, h=%d", + cr->left, cr->top, cr->width, cr->height); +} + +static void get_dpb_size(struct vdec_h264_slice_inst *inst, unsigned int *dpb_sz) +{ + *dpb_sz = inst->vsi_ctx.dec.dpb_sz; + mtk_vcodec_debug(inst, "sz=%d", *dpb_sz); +} + +static int vdec_h264_slice_init(struct mtk_vcodec_ctx *ctx) +{ + struct vdec_h264_slice_inst *inst; + int err; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->ctx = ctx; + + inst->vpu.id = SCP_IPI_VDEC_H264; + inst->vpu.ctx = ctx; + + err = vpu_dec_init(&inst->vpu); + if (err) { + mtk_vcodec_err(inst, "vdec_h264 init err=%d", err); + goto error_free_inst; + } + + memcpy(&inst->vsi_ctx, inst->vpu.vsi, sizeof(inst->vsi_ctx)); + inst->vsi_ctx.dec.resolution_changed = true; + inst->vsi_ctx.dec.realloc_mv_buf = true; + + err = allocate_predication_buf(inst); + if (err) + goto error_deinit; + + mtk_vcodec_debug(inst, "struct size = %d,%d,%d,%d\n", + sizeof(struct mtk_h264_sps_param), + sizeof(struct mtk_h264_pps_param), + sizeof(struct mtk_h264_dec_slice_param), + sizeof(struct mtk_h264_dpb_info)); + + mtk_vcodec_debug(inst, "H264 Instance >> %p", inst); + + ctx->drv_handle = inst; + return 0; + +error_deinit: + vpu_dec_deinit(&inst->vpu); + +error_free_inst: + kfree(inst); + return err; +} + +static void vdec_h264_slice_deinit(void *h_vdec) +{ + struct vdec_h264_slice_inst *inst = h_vdec; + + mtk_vcodec_debug_enter(inst); + + vpu_dec_deinit(&inst->vpu); + free_predication_buf(inst); + free_mv_buf(inst); + + kfree(inst); +} + +static int vdec_h264_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_h264_slice_inst *inst = h_vdec; + const struct v4l2_ctrl_h264_decode_params *dec_params = + get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + struct vdec_vpu_inst *vpu = &inst->vpu; + u32 data[2]; + u64 y_fb_dma; + u64 c_fb_dma; + int err; + + /* bs NULL means flush decoder */ + if (!bs) + return vpu_dec_reset(vpu); + + y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0; + c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0; + + mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx va=%p", + ++inst->num_nalu, y_fb_dma, c_fb_dma, fb); + + inst->vsi_ctx.dec.bs_dma = (uint64_t)bs->dma_addr; + inst->vsi_ctx.dec.y_fb_dma = y_fb_dma; + inst->vsi_ctx.dec.c_fb_dma = c_fb_dma; + inst->vsi_ctx.dec.vdec_fb_va = (u64)(uintptr_t)fb; + + get_vdec_decode_parameters(inst); + data[0] = bs->size; + /* + * Reconstruct the first byte of the NAL unit, as the firmware requests + * that information to be passed even though it is present in the stream + * itself... + */ + data[1] = (dec_params->nal_ref_idc << 5) | + ((dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC) + ? 0x5 : 0x1); + + *res_chg = inst->vsi_ctx.dec.resolution_changed; + if (*res_chg) { + mtk_vcodec_debug(inst, "- resolution changed -"); + if (inst->vsi_ctx.dec.realloc_mv_buf) { + err = alloc_mv_buf(inst, &inst->ctx->picinfo); + inst->vsi_ctx.dec.realloc_mv_buf = false; + if (err) + goto err_free_fb_out; + } + *res_chg = false; + } + + memcpy(inst->vpu.vsi, &inst->vsi_ctx, sizeof(inst->vsi_ctx)); + err = vpu_dec_start(vpu, data, 2); + if (err) + goto err_free_fb_out; + + /* wait decoder done interrupt */ + err = mtk_vcodec_wait_for_done_ctx(inst->ctx, + MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS); + if (err) + goto err_free_fb_out; + vpu_dec_end(vpu); + + memcpy(&inst->vsi_ctx, inst->vpu.vsi, sizeof(inst->vsi_ctx)); + mtk_vcodec_debug(inst, "\n - NALU[%d]", inst->num_nalu); + return 0; + +err_free_fb_out: + mtk_vcodec_err(inst, "\n - NALU[%d] err=%d -\n", inst->num_nalu, err); + return err; +} + +static int vdec_h264_slice_get_param(void *h_vdec, enum vdec_get_param_type type, void *out) +{ + struct vdec_h264_slice_inst *inst = h_vdec; + + switch (type) { + case GET_PARAM_PIC_INFO: + get_pic_info(inst, out); + break; + + case GET_PARAM_DPB_SIZE: + get_dpb_size(inst, out); + break; + + case GET_PARAM_CROP_INFO: + get_crop_info(inst, out); + break; + + default: + mtk_vcodec_err(inst, "invalid get parameter type=%d", type); + return -EINVAL; + } + + return 0; +} + +const struct vdec_common_if vdec_h264_slice_if = { + .init = vdec_h264_slice_init, + .decode = vdec_h264_slice_decode, + .get_param = vdec_h264_slice_get_param, + .deinit = vdec_h264_slice_deinit, +}; diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c index b18743b906ea..42008243ceac 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -19,6 +19,9 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) int ret = 0; switch (fourcc) { + case V4L2_PIX_FMT_H264_SLICE: + ctx->dec_if = &vdec_h264_slice_if; + break; case V4L2_PIX_FMT_H264: ctx->dec_if = &vdec_h264_if; break; diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h index ec8f4e8d3d23..d467e8af4a84 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h @@ -55,6 +55,7 @@ struct vdec_fb_node { }; extern const struct vdec_common_if vdec_h264_if; +extern const struct vdec_common_if vdec_h264_slice_if; extern const struct vdec_common_if vdec_vp8_if; extern const struct vdec_common_if vdec_vp9_if; -- cgit v1.2.3 From 118add98f80eb5b508eacc1456774c5fd0dc24f4 Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Fri, 6 Aug 2021 06:15:28 +0200 Subject: media: mtk-vcodec: vdec: add media device if using stateless api The stateless API requires a media device for issuing requests. Add one if we are being instantiated as a stateless decoder. [acourbot: refactor, cleanup and split] [tzungbi: fix wrong device minor number reference] Signed-off-by: Yunfei Dong Co-developed-by: Alexandre Courbot Signed-off-by: Alexandre Courbot Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 2 ++ .../media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 41 ++++++++++++++++++++-- drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 2 ++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index ae1468aa1b4e..aa277a19e275 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -315,6 +315,8 @@ config VIDEO_MEDIATEK_VCODEC select VIDEO_MEDIATEK_VCODEC_VPU if VIDEO_MEDIATEK_VPU select VIDEO_MEDIATEK_VCODEC_SCP if MTK_SCP select V4L2_H264 + select MEDIA_CONTROLLER + select MEDIA_CONTROLLER_REQUEST_API help Mediatek video codec driver provides HW capability to encode and decode in a range of video formats on MT8173 diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index 1460951f302c..fe345aab9853 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "mtk_vcodec_drv.h" #include "mtk_vcodec_dec.h" @@ -316,18 +317,47 @@ static int mtk_vcodec_probe(struct platform_device *pdev) goto err_event_workq; } + if (dev->vdec_pdata->uses_stateless_api) { + dev->mdev_dec.dev = &pdev->dev; + strscpy(dev->mdev_dec.model, MTK_VCODEC_DEC_NAME, + sizeof(dev->mdev_dec.model)); + + media_device_init(&dev->mdev_dec); + dev->mdev_dec.ops = &mtk_vcodec_media_ops; + dev->v4l2_dev.mdev = &dev->mdev_dec; + + ret = v4l2_m2m_register_media_controller(dev->m2m_dev_dec, dev->vfd_dec, + MEDIA_ENT_F_PROC_VIDEO_DECODER); + if (ret) { + mtk_v4l2_err("Failed to register media controller"); + goto err_reg_cont; + } + + ret = media_device_register(&dev->mdev_dec); + if (ret) { + mtk_v4l2_err("Failed to register media device"); + goto err_media_reg; + } + + mtk_v4l2_debug(0, "media registered as /dev/media%d", vfd_dec->minor); + } ret = video_register_device(vfd_dec, VFL_TYPE_VIDEO, 0); if (ret) { mtk_v4l2_err("Failed to register video device"); goto err_dec_reg; } - mtk_v4l2_debug(0, "decoder registered as /dev/video%d", - vfd_dec->num); + mtk_v4l2_debug(0, "decoder registered as /dev/video%d", vfd_dec->minor); return 0; err_dec_reg: + if (dev->vdec_pdata->uses_stateless_api) + media_device_unregister(&dev->mdev_dec); +err_media_reg: + if (dev->vdec_pdata->uses_stateless_api) + v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec); +err_reg_cont: destroy_workqueue(dev->decode_workqueue); err_event_workq: v4l2_m2m_release(dev->m2m_dev_dec); @@ -360,6 +390,13 @@ static int mtk_vcodec_dec_remove(struct platform_device *pdev) flush_workqueue(dev->decode_workqueue); destroy_workqueue(dev->decode_workqueue); + + if (media_devnode_is_registered(dev->mdev_dec.devnode)) { + media_device_unregister(&dev->mdev_dec); + v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec); + media_device_cleanup(&dev->mdev_dec); + } + if (dev->m2m_dev_dec) v4l2_m2m_release(dev->m2m_dev_dec); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index cf4d56567b02..581522177308 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -390,6 +390,7 @@ struct mtk_vcodec_enc_pdata { * struct mtk_vcodec_dev - driver data * @v4l2_dev: V4L2 device to register video devices for. * @vfd_dec: Video device for decoder + * @mdev_dec: Media device for decoder * @vfd_enc: Video device for encoder. * * @m2m_dev_dec: m2m device for decoder @@ -427,6 +428,7 @@ struct mtk_vcodec_enc_pdata { struct mtk_vcodec_dev { struct v4l2_device v4l2_dev; struct video_device *vfd_dec; + struct media_device mdev_dec; struct video_device *vfd_enc; struct v4l2_m2m_dev *m2m_dev_dec; -- cgit v1.2.3 From dc02a307fd5b51a87de613d1bbe643306868505d Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 6 Aug 2021 06:15:29 +0200 Subject: media: dt-bindings: media: document mediatek,mt8183-vcodec-dec MT8183's decoder is instantiated similarly to MT8173's. Signed-off-by: Alexandre Courbot Acked-by: Rob Herring Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/mediatek-vcodec.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt index de961699ba0a..665a9508708e 100644 --- a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt +++ b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt @@ -10,6 +10,7 @@ Required properties: "mediatek,mt8183-vcodec-enc" for MT8183 encoder. "mediatek,mt8173-vcodec-dec" for MT8173 decoder. "mediatek,mt8192-vcodec-enc" for MT8192 encoder. + "mediatek,mt8183-vcodec-dec" for MT8183 decoder. "mediatek,mt8195-vcodec-enc" for MT8195 encoder. - reg : Physical base address of the video codec registers and length of memory mapped region. -- cgit v1.2.3 From 3766d0d83873d971707d33ccc323d9e6935f031d Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Fri, 6 Aug 2021 06:15:30 +0200 Subject: media: mtk-vcodec: enable MT8183 decoder Now that all the supporting blocks are present, enable decoder for MT8183. [acourbot: refactor, cleanup and split] Signed-off-by: Yunfei Dong Co-developed-by: Alexandre Courbot Signed-off-by: Alexandre Courbot Signed-off-by: Tzung-Bi Shih Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index fe345aab9853..36ae3e6017f0 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -373,12 +373,17 @@ err_dec_pm: } extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata; +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata; static const struct of_device_id mtk_vcodec_match[] = { { .compatible = "mediatek,mt8173-vcodec-dec", .data = &mtk_vdec_8173_pdata, }, + { + .compatible = "mediatek,mt8183-vcodec-dec", + .data = &mtk_vdec_8183_pdata, + }, {}, }; -- cgit v1.2.3 From 6f53b05b8b60bca99fd1ca00609c6d05dfa09231 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 9 Aug 2021 15:19:40 +0200 Subject: media: mtk-vcodec: fix warnings: symbol XXX was not declared Fixes sparse warnings: - warning: symbol 'mtk_vdec_8173_pdata' was not declared. Should it be static? - warning: symbol 'mtk_vdec_8183_pdata' was not declared. Should it be static? Link: https://lore.kernel.org/linux-media/20210809131940.2890108-1-tzungbi@google.com Cc: linux-mediatek@lists.infradead.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, tzungbi@google.com # X-LSpam-Score: -10.7 (----------) Signed-off-by: Tzung-Bi Shih Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h | 2 ++ drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h index 9fbd24186c1a..46783516b84a 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h @@ -65,6 +65,8 @@ struct mtk_video_dec_buf { extern const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops; extern const struct v4l2_m2m_ops mtk_vdec_m2m_ops; extern const struct media_device_ops mtk_vcodec_media_ops; +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata; +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata; /* diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index 36ae3e6017f0..e6e6a8203eeb 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -372,9 +372,6 @@ err_dec_pm: return ret; } -extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata; -extern const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata; - static const struct of_device_id mtk_vcodec_match[] = { { .compatible = "mediatek,mt8173-vcodec-dec", -- cgit v1.2.3 From 8bff1386d62d9406513a4806624d7cedefcb1ef9 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 10 Aug 2021 20:08:01 +0200 Subject: media: ir_toy: allow tx carrier to be set The ir_toy allows the transmit carrier to be specified. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir_toy.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c index 3e729a17b35f..b0dc19d36ac9 100644 --- a/drivers/media/rc/ir_toy.c +++ b/drivers/media/rc/ir_toy.c @@ -4,7 +4,9 @@ * Infrared Toy and IR Droid RC core driver * * Copyright (C) 2020 Sean Young - + * + * http://dangerousprototypes.com/docs/USB_IR_Toy:_Sampling_mode + * * This driver is based on the lirc driver which can be found here: * https://sourceforge.net/p/lirc/git/ci/master/tree/plugins/irtoy.c * Copyright (C) 2011 Peter Kooiman @@ -45,7 +47,7 @@ static const u8 COMMAND_TXSTART[] = { 0x26, 0x24, 0x25, 0x03 }; enum state { STATE_IRDATA, - STATE_RESET, + STATE_COMMAND_NO_RESP, STATE_COMMAND, STATE_TX, }; @@ -192,7 +194,7 @@ static void irtoy_response(struct irtoy *irtoy, u32 len) irtoy->tx_len -= buf_len; } break; - case STATE_RESET: + case STATE_COMMAND_NO_RESP: dev_err(irtoy->dev, "unexpected response to reset: %*phN\n", len, irtoy->in); } @@ -203,7 +205,7 @@ static void irtoy_out_callback(struct urb *urb) struct irtoy *irtoy = urb->context; if (urb->status == 0) { - if (irtoy->state == STATE_RESET) + if (irtoy->state == STATE_COMMAND_NO_RESP) complete(&irtoy->command_done); } else { dev_warn(irtoy->dev, "out urb status: %d\n", urb->status); @@ -255,7 +257,7 @@ static int irtoy_setup(struct irtoy *irtoy) int err; err = irtoy_command(irtoy, COMMAND_RESET, sizeof(COMMAND_RESET), - STATE_RESET); + STATE_COMMAND_NO_RESP); if (err != 0) { dev_err(irtoy->dev, "could not write reset command: %d\n", err); @@ -338,6 +340,27 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count) return count; } +static int irtoy_tx_carrier(struct rc_dev *rc, uint32_t carrier) +{ + struct irtoy *irtoy = rc->priv; + u8 buf[3]; + int err; + + if (carrier < 11800) + return -EINVAL; + + buf[0] = 0x06; + buf[1] = DIV_ROUND_CLOSEST(48000000, 16 * carrier) - 1; + buf[2] = 0; + + err = irtoy_command(irtoy, buf, sizeof(buf), STATE_COMMAND_NO_RESP); + if (err) + dev_err(irtoy->dev, "could not write carrier command: %d\n", + err); + + return err; +} + static int irtoy_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -436,6 +459,7 @@ static int irtoy_probe(struct usb_interface *intf, rc->dev.parent = &intf->dev; rc->priv = irtoy; rc->tx_ir = irtoy_tx; + rc->s_tx_carrier = irtoy_tx_carrier; rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rc->map_name = RC_MAP_RC6_MCE; rc->rx_resolution = UNIT_US; -- cgit v1.2.3 From 7efc14b8658a512bb2d90e9e64362e55625eb705 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 27 Jul 2021 07:39:03 +0200 Subject: media: c8sectpfe-dvb: Remove unused including Remove including that don't need it. Signed-off-by: Cai Huoqing Reviewed-by: Patrice Chotard Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c | 1 - drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index 338b205ae3a7..02dc78bd7fab 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c index 0560a9cb004b..feb48cb546d7 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c @@ -11,7 +11,6 @@ #include #include #include -#include #include -- cgit v1.2.3 From afae4ef7d5ad913cab1316137854a36bea6268a5 Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Fri, 13 Aug 2021 16:34:20 +0200 Subject: media: dvb-usb: fix ununit-value in az6027_rc_query Syzbot reported ununit-value bug in az6027_rc_query(). The problem was in missing state pointer initialization. Since this function does nothing we can simply initialize state to REMOTE_NO_KEY_PRESSED. Reported-and-tested-by: syzbot+2cd8c5db4a85f0a04142@syzkaller.appspotmail.com Fixes: 76f9a820c867 ("V4L/DVB: AZ6027: Initial import of the driver") Signed-off-by: Pavel Skripkin Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/az6027.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c index 1c39b61cde29..86788771175b 100644 --- a/drivers/media/usb/dvb-usb/az6027.c +++ b/drivers/media/usb/dvb-usb/az6027.c @@ -391,6 +391,7 @@ static struct rc_map_table rc_map_az6027_table[] = { /* remote control stuff (does not work with my box) */ static int az6027_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { + *state = REMOTE_NO_KEY_PRESSED; return 0; } -- cgit v1.2.3 From c9458c6f8a8f9c8b09fef0e2a4d5798ded993ef8 Mon Sep 17 00:00:00 2001 From: Nil Yi Date: Sat, 14 Aug 2021 12:29:39 +0200 Subject: media: rc: clean the freed urb pointer to avoid double free After freed rx_urb, we should set the second interface urb to NULL, otherwise a double free would happen when the driver is removed from the first interface. Signed-off-by: Nil Yi Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 2ca4e86c7b9f..54da6f60079b 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -2358,8 +2358,10 @@ urb_submit_failed: touch_setup_failed: find_endpoint_failed: usb_put_dev(ictx->usbdev_intf1); + ictx->usbdev_intf1 = NULL; mutex_unlock(&ictx->lock); usb_free_urb(rx_urb); + ictx->rx_urb_intf1 = NULL; rx_urb_alloc_failed: dev_err(ictx->dev, "unable to initialize intf1, err %d\n", ret); -- cgit v1.2.3 From 39ad5b4a5ae74242d9bd5ce3e395b3f676bba715 Mon Sep 17 00:00:00 2001 From: Muhammad Usama Anjum Date: Mon, 5 Apr 2021 22:52:19 +0200 Subject: media: siano: use DEFINE_MUTEX() for mutex lock mutex lock can be initialized with DEFINE_MUTEX() rather than explicitly calling mutex_init(). Signed-off-by: Muhammad Usama Anjum Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index bceaf91faa15..7d4bc2733f2b 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -414,10 +414,10 @@ struct smscore_registry_entry_t { static struct list_head g_smscore_notifyees; static struct list_head g_smscore_devices; -static struct mutex g_smscore_deviceslock; +static DEFINE_MUTEX(g_smscore_deviceslock); static struct list_head g_smscore_registry; -static struct mutex g_smscore_registrylock; +static DEFINE_MUTEX(g_smscore_registrylock); static int default_mode = DEVICE_MODE_NONE; @@ -2119,10 +2119,7 @@ static int __init smscore_module_init(void) { INIT_LIST_HEAD(&g_smscore_notifyees); INIT_LIST_HEAD(&g_smscore_devices); - mutex_init(&g_smscore_deviceslock); - INIT_LIST_HEAD(&g_smscore_registry); - mutex_init(&g_smscore_registrylock); return 0; } -- cgit v1.2.3 From d3bb03ec08fdd93ddcf0f61c86d0d07bd5099cd5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 17 Aug 2021 01:20:01 +0200 Subject: media: cxd2820r: include the right header This driver is just using so include that and not the legacy header. Cc: Antti Palosaari Signed-off-by: Linus Walleij Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2820r_priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h index 7baf0162424f..09c42bcef971 100644 --- a/drivers/media/dvb-frontends/cxd2820r_priv.h +++ b/drivers/media/dvb-frontends/cxd2820r_priv.h @@ -13,7 +13,7 @@ #include #include #include "cxd2820r.h" -#include +#include /* For gpio_chip */ #include #include -- cgit v1.2.3 From dbb4cfea6efe979ed153bd59a6a527a90d3d0ab3 Mon Sep 17 00:00:00 2001 From: Zheyu Ma Date: Wed, 23 Jun 2021 08:01:05 +0200 Subject: media: netup_unidvb: handle interrupt properly according to the firmware The interrupt handling should be related to the firmware version. If the driver matches an old firmware, then the driver should not handle interrupt such as i2c or dma, otherwise it will cause some errors. This log reveals it: [ 27.708641] INFO: trying to register non-static key. [ 27.710851] The code is fine but needs lockdep annotation, or maybe [ 27.712010] you didn't initialize this object before use? [ 27.712396] turning off the locking correctness validator. [ 27.712787] CPU: 2 PID: 0 Comm: swapper/2 Not tainted 5.12.4-g70e7f0549188-dirty #169 [ 27.713349] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014 [ 27.714149] Call Trace: [ 27.714329] [ 27.714480] dump_stack+0xba/0xf5 [ 27.714737] register_lock_class+0x873/0x8f0 [ 27.715052] ? __lock_acquire+0x323/0x1930 [ 27.715353] __lock_acquire+0x75/0x1930 [ 27.715636] lock_acquire+0x1dd/0x3e0 [ 27.715905] ? netup_i2c_interrupt+0x19/0x310 [ 27.716226] _raw_spin_lock_irqsave+0x4b/0x60 [ 27.716544] ? netup_i2c_interrupt+0x19/0x310 [ 27.716863] netup_i2c_interrupt+0x19/0x310 [ 27.717178] netup_unidvb_isr+0xd3/0x160 [ 27.717467] __handle_irq_event_percpu+0x53/0x3e0 [ 27.717808] handle_irq_event_percpu+0x35/0x90 [ 27.718129] handle_irq_event+0x39/0x60 [ 27.718409] handle_fasteoi_irq+0xc2/0x1d0 [ 27.718707] __common_interrupt+0x7f/0x150 [ 27.719008] common_interrupt+0xb4/0xd0 [ 27.719289] [ 27.719446] asm_common_interrupt+0x1e/0x40 [ 27.719747] RIP: 0010:native_safe_halt+0x17/0x20 [ 27.720084] Code: 07 0f 00 2d 8b ee 4c 00 f4 5d c3 0f 1f 84 00 00 00 00 00 8b 05 72 95 17 02 55 48 89 e5 85 c0 7e 07 0f 00 2d 6b ee 4c 00 fb f4 <5d> c3 cc cc cc cc cc cc cc 55 48 89 e5 e8 67 53 ff ff 8b 0d 29 f6 [ 27.721386] RSP: 0018:ffffc9000008fe90 EFLAGS: 00000246 [ 27.721758] RAX: 0000000000000000 RBX: 0000000000000002 RCX: 0000000000000000 [ 27.722262] RDX: 0000000000000000 RSI: ffffffff85f7c054 RDI: ffffffff85ded4e6 [ 27.722770] RBP: ffffc9000008fe90 R08: 0000000000000001 R09: 0000000000000001 [ 27.723277] R10: 0000000000000000 R11: 0000000000000001 R12: ffffffff86a75408 [ 27.723781] R13: 0000000000000000 R14: 0000000000000000 R15: ffff888100260000 [ 27.724289] default_idle+0x9/0x10 [ 27.724537] arch_cpu_idle+0xa/0x10 [ 27.724791] default_idle_call+0x6e/0x250 [ 27.725082] do_idle+0x1f0/0x2d0 [ 27.725326] cpu_startup_entry+0x18/0x20 [ 27.725613] start_secondary+0x11f/0x160 [ 27.725902] secondary_startup_64_no_verify+0xb0/0xbb [ 27.726272] BUG: kernel NULL pointer dereference, address: 0000000000000002 [ 27.726768] #PF: supervisor read access in kernel mode [ 27.727138] #PF: error_code(0x0000) - not-present page [ 27.727507] PGD 8000000118688067 P4D 8000000118688067 PUD 10feab067 PMD 0 [ 27.727999] Oops: 0000 [#1] PREEMPT SMP PTI [ 27.728302] CPU: 2 PID: 0 Comm: swapper/2 Not tainted 5.12.4-g70e7f0549188-dirty #169 [ 27.728861] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014 [ 27.729660] RIP: 0010:netup_i2c_interrupt+0x23/0x310 [ 27.730019] Code: 0f 1f 80 00 00 00 00 55 48 89 e5 41 55 41 54 53 48 89 fb e8 af 6e 95 fd 48 89 df e8 e7 9f 1c 01 49 89 c5 48 8b 83 48 08 00 00 <66> 44 8b 60 02 44 89 e0 48 8b 93 48 08 00 00 83 e0 f8 66 89 42 02 [ 27.731339] RSP: 0018:ffffc90000118e90 EFLAGS: 00010046 [ 27.731716] RAX: 0000000000000000 RBX: ffff88810803c4d8 RCX: 0000000000000000 [ 27.732223] RDX: 0000000000000001 RSI: ffffffff85d37b94 RDI: ffff88810803c4d8 [ 27.732727] RBP: ffffc90000118ea8 R08: 0000000000000000 R09: 0000000000000001 [ 27.733239] R10: ffff88810803c4f0 R11: 61646e6f63657320 R12: 0000000000000000 [ 27.733745] R13: 0000000000000046 R14: ffff888101041000 R15: ffff8881081b2400 [ 27.734251] FS: 0000000000000000(0000) GS:ffff88817bc80000(0000) knlGS:0000000000000000 [ 27.734821] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 27.735228] CR2: 0000000000000002 CR3: 0000000108194000 CR4: 00000000000006e0 [ 27.735735] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 27.736241] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 27.736744] Call Trace: [ 27.736924] [ 27.737074] netup_unidvb_isr+0xd3/0x160 [ 27.737363] __handle_irq_event_percpu+0x53/0x3e0 [ 27.737706] handle_irq_event_percpu+0x35/0x90 [ 27.738028] handle_irq_event+0x39/0x60 [ 27.738306] handle_fasteoi_irq+0xc2/0x1d0 [ 27.738602] __common_interrupt+0x7f/0x150 [ 27.738899] common_interrupt+0xb4/0xd0 [ 27.739176] [ 27.739331] asm_common_interrupt+0x1e/0x40 [ 27.739633] RIP: 0010:native_safe_halt+0x17/0x20 [ 27.739967] Code: 07 0f 00 2d 8b ee 4c 00 f4 5d c3 0f 1f 84 00 00 00 00 00 8b 05 72 95 17 02 55 48 89 e5 85 c0 7e 07 0f 00 2d 6b ee 4c 00 fb f4 <5d> c3 cc cc cc cc cc cc cc 55 48 89 e5 e8 67 53 ff ff 8b 0d 29 f6 [ 27.741275] RSP: 0018:ffffc9000008fe90 EFLAGS: 00000246 [ 27.741647] RAX: 0000000000000000 RBX: 0000000000000002 RCX: 0000000000000000 [ 27.742148] RDX: 0000000000000000 RSI: ffffffff85f7c054 RDI: ffffffff85ded4e6 [ 27.742652] RBP: ffffc9000008fe90 R08: 0000000000000001 R09: 0000000000000001 [ 27.743154] R10: 0000000000000000 R11: 0000000000000001 R12: ffffffff86a75408 [ 27.743652] R13: 0000000000000000 R14: 0000000000000000 R15: ffff888100260000 [ 27.744157] default_idle+0x9/0x10 [ 27.744405] arch_cpu_idle+0xa/0x10 [ 27.744658] default_idle_call+0x6e/0x250 [ 27.744948] do_idle+0x1f0/0x2d0 [ 27.745190] cpu_startup_entry+0x18/0x20 [ 27.745475] start_secondary+0x11f/0x160 [ 27.745761] secondary_startup_64_no_verify+0xb0/0xbb [ 27.746123] Modules linked in: [ 27.746348] Dumping ftrace buffer: [ 27.746596] (ftrace buffer empty) [ 27.746852] CR2: 0000000000000002 [ 27.747094] ---[ end trace ebafd46f83ab946d ]--- [ 27.747424] RIP: 0010:netup_i2c_interrupt+0x23/0x310 [ 27.747778] Code: 0f 1f 80 00 00 00 00 55 48 89 e5 41 55 41 54 53 48 89 fb e8 af 6e 95 fd 48 89 df e8 e7 9f 1c 01 49 89 c5 48 8b 83 48 08 00 00 <66> 44 8b 60 02 44 89 e0 48 8b 93 48 08 00 00 83 e0 f8 66 89 42 02 [ 27.749082] RSP: 0018:ffffc90000118e90 EFLAGS: 00010046 [ 27.749461] RAX: 0000000000000000 RBX: ffff88810803c4d8 RCX: 0000000000000000 [ 27.749966] RDX: 0000000000000001 RSI: ffffffff85d37b94 RDI: ffff88810803c4d8 [ 27.750471] RBP: ffffc90000118ea8 R08: 0000000000000000 R09: 0000000000000001 [ 27.750976] R10: ffff88810803c4f0 R11: 61646e6f63657320 R12: 0000000000000000 [ 27.751480] R13: 0000000000000046 R14: ffff888101041000 R15: ffff8881081b2400 [ 27.751986] FS: 0000000000000000(0000) GS:ffff88817bc80000(0000) knlGS:0000000000000000 [ 27.752560] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 27.752970] CR2: 0000000000000002 CR3: 0000000108194000 CR4: 00000000000006e0 [ 27.753481] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 27.753984] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 27.754487] Kernel panic - not syncing: Fatal exception in interrupt [ 27.755033] Dumping ftrace buffer: [ 27.755279] (ftrace buffer empty) [ 27.755534] Kernel Offset: disabled [ 27.755785] Rebooting in 1 seconds.. Signed-off-by: Zheyu Ma Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/netup_unidvb/netup_unidvb_core.c | 27 +++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index 6f3125c2d097..77bae1468551 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -258,19 +258,24 @@ static irqreturn_t netup_unidvb_isr(int irq, void *dev_id) if ((reg40 & AVL_IRQ_ASSERTED) != 0) { /* IRQ is being signaled */ reg_isr = readw(ndev->bmmio0 + REG_ISR); - if (reg_isr & NETUP_UNIDVB_IRQ_I2C0) { - iret = netup_i2c_interrupt(&ndev->i2c[0]); - } else if (reg_isr & NETUP_UNIDVB_IRQ_I2C1) { - iret = netup_i2c_interrupt(&ndev->i2c[1]); - } else if (reg_isr & NETUP_UNIDVB_IRQ_SPI) { + if (reg_isr & NETUP_UNIDVB_IRQ_SPI) iret = netup_spi_interrupt(ndev->spi); - } else if (reg_isr & NETUP_UNIDVB_IRQ_DMA1) { - iret = netup_dma_interrupt(&ndev->dma[0]); - } else if (reg_isr & NETUP_UNIDVB_IRQ_DMA2) { - iret = netup_dma_interrupt(&ndev->dma[1]); - } else if (reg_isr & NETUP_UNIDVB_IRQ_CI) { - iret = netup_ci_interrupt(ndev); + else if (!ndev->old_fw) { + if (reg_isr & NETUP_UNIDVB_IRQ_I2C0) { + iret = netup_i2c_interrupt(&ndev->i2c[0]); + } else if (reg_isr & NETUP_UNIDVB_IRQ_I2C1) { + iret = netup_i2c_interrupt(&ndev->i2c[1]); + } else if (reg_isr & NETUP_UNIDVB_IRQ_DMA1) { + iret = netup_dma_interrupt(&ndev->dma[0]); + } else if (reg_isr & NETUP_UNIDVB_IRQ_DMA2) { + iret = netup_dma_interrupt(&ndev->dma[1]); + } else if (reg_isr & NETUP_UNIDVB_IRQ_CI) { + iret = netup_ci_interrupt(ndev); + } else { + goto err; + } } else { +err: dev_err(&pci_dev->dev, "%s(): unknown interrupt 0x%x\n", __func__, reg_isr); -- cgit v1.2.3 From bbe54b1a75a397b62dd528100cfb2ffe558d92ee Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 2 Aug 2021 16:38:14 +0200 Subject: media: atomisp: restore missing 'return' statement The input_system_configure_channel_sensor() function lost its final return code in a previous patch: drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c: In function 'input_system_configure_channel_sensor': drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c:1649:1: error: control reaches end of non-void function [-Werror=return-type] Restore what was there originally. Link: https://lore.kernel.org/linux-media/20210802143820.1150099-1-arnd@kernel.org Fixes: 728a5c64ae5f ("media: atomisp: remove dublicate code") Signed-off-by: Arnd Bergmann Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c index 8e085dda0c18..712e01c37870 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c @@ -1646,6 +1646,8 @@ static input_system_err_t input_system_configure_channel_sensor( default: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; } + + return INPUT_SYSTEM_ERR_NO_ERROR; } // Test flags and set structure. -- cgit v1.2.3 From e16f5e39acd6d10cc63ae39bc0a77188ed828f22 Mon Sep 17 00:00:00 2001 From: Evgeny Novikov Date: Tue, 10 Aug 2021 18:29:43 +0200 Subject: media: atomisp: Fix error handling in probe There were several issues with handling errors in lm3554_probe(): - Probe did not set the error code when v4l2_ctrl_handler_init() failed. - It intermixed gotos for handling errors of v4l2_ctrl_handler_init() and media_entity_pads_init(). - It did not set the error code for failures of v4l2_ctrl_new_custom(). - Probe did not free resources in case of failures of atomisp_register_i2c_module(). The patch fixes all these issues. Found by Linux Driver Verification project (linuxtesting.org). Link: https://lore.kernel.org/linux-media/20210810162943.19852-1-novikov@ispras.ru Signed-off-by: Evgeny Novikov Reviewed-by: Dan Carpenter Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-lm3554.c | 37 ++++++++++++++-------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c index 362ed44b4eff..e046489cd253 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c @@ -835,7 +835,6 @@ static int lm3554_probe(struct i2c_client *client) int err = 0; struct lm3554 *flash; unsigned int i; - int ret; flash = kzalloc(sizeof(*flash), GFP_KERNEL); if (!flash) @@ -844,7 +843,7 @@ static int lm3554_probe(struct i2c_client *client) flash->pdata = lm3554_platform_data_func(client); if (IS_ERR(flash->pdata)) { err = PTR_ERR(flash->pdata); - goto fail1; + goto free_flash; } v4l2_i2c_subdev_init(&flash->sd, client, &lm3554_ops); @@ -852,12 +851,12 @@ static int lm3554_probe(struct i2c_client *client) flash->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; flash->mode = ATOMISP_FLASH_MODE_OFF; flash->timeout = LM3554_MAX_TIMEOUT / LM3554_TIMEOUT_STEPSIZE - 1; - ret = + err = v4l2_ctrl_handler_init(&flash->ctrl_handler, ARRAY_SIZE(lm3554_controls)); - if (ret) { + if (err) { dev_err(&client->dev, "error initialize a ctrl_handler.\n"); - goto fail3; + goto unregister_subdev; } for (i = 0; i < ARRAY_SIZE(lm3554_controls); i++) @@ -866,14 +865,15 @@ static int lm3554_probe(struct i2c_client *client) if (flash->ctrl_handler.error) { dev_err(&client->dev, "ctrl_handler error.\n"); - goto fail3; + err = flash->ctrl_handler.error; + goto free_handler; } flash->sd.ctrl_handler = &flash->ctrl_handler; err = media_entity_pads_init(&flash->sd.entity, 0, NULL); if (err) { dev_err(&client->dev, "error initialize a media entity.\n"); - goto fail2; + goto free_handler; } flash->sd.entity.function = MEDIA_ENT_F_FLASH; @@ -884,16 +884,27 @@ static int lm3554_probe(struct i2c_client *client) err = lm3554_gpio_init(client); if (err) { - dev_err(&client->dev, "gpio request/direction_output fail"); - goto fail3; + dev_err(&client->dev, "gpio request/direction_output fail.\n"); + goto cleanup_media; + } + + err = atomisp_register_i2c_module(&flash->sd, NULL, LED_FLASH); + if (err) { + dev_err(&client->dev, "fail to register atomisp i2c module.\n"); + goto uninit_gpio; } - return atomisp_register_i2c_module(&flash->sd, NULL, LED_FLASH); -fail3: + + return 0; + +uninit_gpio: + lm3554_gpio_uninit(client); +cleanup_media: media_entity_cleanup(&flash->sd.entity); +free_handler: v4l2_ctrl_handler_free(&flash->ctrl_handler); -fail2: +unregister_subdev: v4l2_device_unregister_subdev(&flash->sd); -fail1: +free_flash: kfree(flash); return err; -- cgit v1.2.3 From 5ba9c067b5ed1ccfec58acae07c6582f16b9d44b Mon Sep 17 00:00:00 2001 From: Yizhuo Date: Sun, 11 Jul 2021 22:23:32 +0200 Subject: media: staging: atomisp: fix the uninitialized use in gc2235_detect() Inside function gc2235_detect(), variable "low" could be uninitialized if ov5693_read_reg() returns error, however, it affects the value of variable "id". The "id" is used in the later if statement, which is potentially unsafe. Link: https://lore.kernel.org/linux-media/20210711202334.27959-1-yzhai003@ucr.edu Signed-off-by: Yizhuo Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index 5e3670c4fc29..6c95f57a52e9 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -1714,6 +1714,8 @@ static int ov5693_detect(struct i2c_client *client) } ret = ov5693_read_reg(client, OV5693_8BIT, OV5693_SC_CMMN_CHIP_ID_L, &low); + if (ret) + return ret; id = ((((u16)high) << 8) | (u16)low); if (id != OV5693_ID) { -- cgit v1.2.3 From f2a7fc8cc8073fad1ed3eb5cebde8748ec54e158 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 1 Jul 2021 13:56:34 +0200 Subject: media: dt-bindings: media: renesas,imr: Convert to json-schema Convert the Renesas R-Car Image Renderer Device Tree binding documentation to json-schema. Signed-off-by: Geert Uytterhoeven Reviewed-by: Laurent Pinchart Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/renesas,imr.txt | 31 ---------- .../devicetree/bindings/media/renesas,imr.yaml | 67 ++++++++++++++++++++++ 2 files changed, 67 insertions(+), 31 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/renesas,imr.txt create mode 100644 Documentation/devicetree/bindings/media/renesas,imr.yaml diff --git a/Documentation/devicetree/bindings/media/renesas,imr.txt b/Documentation/devicetree/bindings/media/renesas,imr.txt deleted file mode 100644 index b0614153ed36..000000000000 --- a/Documentation/devicetree/bindings/media/renesas,imr.txt +++ /dev/null @@ -1,31 +0,0 @@ -Renesas R-Car Image Renderer (Distortion Correction Engine) ------------------------------------------------------------ - -The image renderer, or the distortion correction engine, is a drawing processor -with a simple instruction system capable of referencing video capture data or -data in an external memory as 2D texture data and performing texture mapping -and drawing with respect to any shape that is split into triangular objects. - -Required properties: - -- compatible: "renesas,-imr-lx4", "renesas,imr-lx4" as a fallback for - the image renderer light extended 4 (IMR-LX4) found in the R-Car gen3 SoCs, - where the examples with are: - - "renesas,r8a7795-imr-lx4" for R-Car H3, - - "renesas,r8a7796-imr-lx4" for R-Car M3-W. -- reg: offset and length of the register block; -- interrupts: single interrupt specifier; -- clocks: single clock phandle/specifier pair; -- power-domains: power domain phandle/specifier pair; -- resets: reset phandle/specifier pair. - -Example: - - imr-lx4@fe860000 { - compatible = "renesas,r8a7795-imr-lx4", "renesas,imr-lx4"; - reg = <0 0xfe860000 0 0x2000>; - interrupts = ; - clocks = <&cpg CPG_MOD 823>; - power-domains = <&sysc R8A7795_PD_A3VC>; - resets = <&cpg 823>; - }; diff --git a/Documentation/devicetree/bindings/media/renesas,imr.yaml b/Documentation/devicetree/bindings/media/renesas,imr.yaml new file mode 100644 index 000000000000..512f57417fd8 --- /dev/null +++ b/Documentation/devicetree/bindings/media/renesas,imr.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/renesas,imr.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas R-Car Image Renderer (Distortion Correction Engine) + +maintainers: + - Sergei Shtylyov + +description: | + The image renderer, or the distortion correction engine, is a drawing + processor with a simple instruction system capable of referencing video + capture data or data in an external memory as 2D texture data and performing + texture mapping and drawing with respect to any shape that is split into + triangular objects. + + The image renderer light extended 4 (IMR-LX4) is found in R-Car Gen3 SoCs. + +properties: + compatible: + items: + - enum: + - renesas,r8a7795-imr-lx4 # R-Car H3 + - renesas,r8a7796-imr-lx4 # R-Car M3-W + - const: renesas,imr-lx4 # R-Car Gen3 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - power-domains + - resets + +additionalProperties: false + +examples: + - | + #include + #include + #include + + imr-lx4@fe860000 { + compatible = "renesas,r8a7795-imr-lx4", "renesas,imr-lx4"; + reg = <0xfe860000 0x2000>; + interrupts = ; + clocks = <&cpg CPG_MOD 823>; + power-domains = <&sysc R8A7795_PD_A3VC>; + resets = <&cpg 823>; + }; -- cgit v1.2.3 From 44bc61991508461925e988a41e0b19477c1c1012 Mon Sep 17 00:00:00 2001 From: Shaokun Zhang Date: Mon, 24 May 2021 13:13:12 +0200 Subject: media: m5602_ov7660: remove the repeated declaration Function 'ov7660_init' is declared twice, remove the repeated declaration. Cc: Erik Andren Signed-off-by: Shaokun Zhang Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/m5602/m5602_ov7660.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/gspca/m5602/m5602_ov7660.h b/drivers/media/usb/gspca/m5602/m5602_ov7660.h index d60247e10c2c..6146e8ef17c0 100644 --- a/drivers/media/usb/gspca/m5602/m5602_ov7660.h +++ b/drivers/media/usb/gspca/m5602/m5602_ov7660.h @@ -86,7 +86,6 @@ extern bool dump_sensor; int ov7660_probe(struct sd *sd); int ov7660_init(struct sd *sd); -int ov7660_init(struct sd *sd); int ov7660_init_controls(struct sd *sd); int ov7660_start(struct sd *sd); int ov7660_stop(struct sd *sd); -- cgit v1.2.3 From 548fa43a58696450c15b8f5564e99589c5144664 Mon Sep 17 00:00:00 2001 From: Dmitriy Ulitin Date: Thu, 27 May 2021 17:06:26 +0200 Subject: media: stm32: Potential NULL pointer dereference in dcmi_irq_thread() At the moment of enabling irq handling: 1922 ret = devm_request_threaded_irq(&pdev->dev, irq, dcmi_irq_callback, 1923 dcmi_irq_thread, IRQF_ONESHOT, 1924 dev_name(&pdev->dev), dcmi); there is still uninitialized field sd_format of struct stm32_dcmi *dcmi. If an interrupt occurs in the interval between the installation of the interrupt handler and the initialization of this field, NULL pointer dereference happens. This field is dereferenced in the handler function without any check: 457 if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG && 458 dcmi->misr & IT_FRAME) { The patch moves interrupt handler installation after initialization of the sd_format field that happens in dcmi_graph_notify_complete() via dcmi_set_default_fmt(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Dmitriy Ulitin Signed-off-by: Alexey Khoroshilov Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index e499841d76f0..e1b17c05229c 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -128,6 +128,7 @@ struct stm32_dcmi { int sequence; struct list_head buffers; struct dcmi_buf *active; + int irq; struct v4l2_device v4l2_dev; struct video_device *vdev; @@ -1759,6 +1760,14 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier) return ret; } + ret = devm_request_threaded_irq(dcmi->dev, dcmi->irq, dcmi_irq_callback, + dcmi_irq_thread, IRQF_ONESHOT, + dev_name(dcmi->dev), dcmi); + if (ret) { + dev_err(dcmi->dev, "Unable to request irq %d\n", dcmi->irq); + return ret; + } + return 0; } @@ -1914,6 +1923,8 @@ static int dcmi_probe(struct platform_device *pdev) if (irq <= 0) return irq ? irq : -ENXIO; + dcmi->irq = irq; + dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!dcmi->res) { dev_err(&pdev->dev, "Could not get resource\n"); @@ -1926,14 +1937,6 @@ static int dcmi_probe(struct platform_device *pdev) return PTR_ERR(dcmi->regs); } - ret = devm_request_threaded_irq(&pdev->dev, irq, dcmi_irq_callback, - dcmi_irq_thread, IRQF_ONESHOT, - dev_name(&pdev->dev), dcmi); - if (ret) { - dev_err(&pdev->dev, "Unable to request irq %d\n", irq); - return ret; - } - mclk = devm_clk_get(&pdev->dev, "mclk"); if (IS_ERR(mclk)) { if (PTR_ERR(mclk) != -EPROBE_DEFER) -- cgit v1.2.3 From 75821f810793efe6034b6798967772f360e4e49f Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Sat, 7 Aug 2021 00:30:22 +0200 Subject: media: ipu3.rst: Improve header formatting on tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the header-rows option of the flat-table directive in order to have the first row displayed as a header. Also capitalize these headers. These changes make the tables easier to read. Signed-off-by: Nícolas F. R. A. Prado Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/admin-guide/media/ipu3.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Documentation/admin-guide/media/ipu3.rst b/Documentation/admin-guide/media/ipu3.rst index 52c1c04173da..83b3cd03b35c 100644 --- a/Documentation/admin-guide/media/ipu3.rst +++ b/Documentation/admin-guide/media/ipu3.rst @@ -51,10 +51,11 @@ to userspace as a V4L2 sub-device node and has two pads: .. tabularcolumns:: |p{0.8cm}|p{4.0cm}|p{4.0cm}| .. flat-table:: + :header-rows: 1 - * - pad - - direction - - purpose + * - Pad + - Direction + - Purpose * - 0 - sink @@ -148,10 +149,11 @@ Each pipe has two sink pads and three source pads for the following purpose: .. tabularcolumns:: |p{0.8cm}|p{4.0cm}|p{4.0cm}| .. flat-table:: + :header-rows: 1 - * - pad - - direction - - purpose + * - Pad + - Direction + - Purpose * - 0 - sink -- cgit v1.2.3 From a44f9d6f9dc1fb314a3f1ed2dcd4fbbcc3d9f892 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 10 Aug 2021 19:09:55 +0200 Subject: media: staging/intel-ipu3: css: Fix wrong size comparison imgu_css_fw_init There is a wrong comparison of the total size of the loaded firmware css->fw->size with the size of a pointer to struct imgu_fw_header. Turn binary_header into a flexible-array member[1][2], use the struct_size() helper and fix the wrong size comparison. Notice that the loaded firmware needs to contain at least one 'struct imgu_fw_info' item in the binary_header[] array. It's also worth mentioning that "css->fw->size < struct_size(css->fwp, binary_header, 1)" with binary_header declared as a flexible-array member is equivalent to "css->fw->size < sizeof(struct imgu_fw_header)" with binary_header declared as a one-element array (as in the original code). The replacement of the one-element array with a flexible-array member also helps with the ongoing efforts to globally enable -Warray-bounds and get us closer to being able to tighten the FORTIFY_SOURCE routines on memcpy(). [1] https://en.wikipedia.org/wiki/Flexible_array_member [2] https://www.kernel.org/doc/html/v5.10/process/deprecated.html#zero-length-and-one-element-arrays Link: https://github.com/KSPP/linux/issues/79 Link: https://github.com/KSPP/linux/issues/109 Fixes: 09d290f0ba21 ("media: staging/intel-ipu3: css: Add support for firmware management") Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/ipu3/ipu3-css-fw.c | 7 +++---- drivers/staging/media/ipu3/ipu3-css-fw.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/staging/media/ipu3/ipu3-css-fw.c b/drivers/staging/media/ipu3/ipu3-css-fw.c index 45aff76198e2..981693eed815 100644 --- a/drivers/staging/media/ipu3/ipu3-css-fw.c +++ b/drivers/staging/media/ipu3/ipu3-css-fw.c @@ -124,12 +124,11 @@ int imgu_css_fw_init(struct imgu_css *css) /* Check and display fw header info */ css->fwp = (struct imgu_fw_header *)css->fw->data; - if (css->fw->size < sizeof(struct imgu_fw_header *) || + if (css->fw->size < struct_size(css->fwp, binary_header, 1) || css->fwp->file_header.h_size != sizeof(struct imgu_fw_bi_file_h)) goto bad_fw; - if (sizeof(struct imgu_fw_bi_file_h) + - css->fwp->file_header.binary_nr * sizeof(struct imgu_fw_info) > - css->fw->size) + if (struct_size(css->fwp, binary_header, + css->fwp->file_header.binary_nr) > css->fw->size) goto bad_fw; dev_info(dev, "loaded firmware version %.64s, %u binaries, %zu bytes\n", diff --git a/drivers/staging/media/ipu3/ipu3-css-fw.h b/drivers/staging/media/ipu3/ipu3-css-fw.h index 3c078f15a295..c0bc57fd678a 100644 --- a/drivers/staging/media/ipu3/ipu3-css-fw.h +++ b/drivers/staging/media/ipu3/ipu3-css-fw.h @@ -171,7 +171,7 @@ struct imgu_fw_bi_file_h { struct imgu_fw_header { struct imgu_fw_bi_file_h file_header; - struct imgu_fw_info binary_header[1]; /* binary_nr items */ + struct imgu_fw_info binary_header[]; /* binary_nr items */ }; /******************* Firmware functions *******************/ -- cgit v1.2.3 From ace64e5894bc7755283572f05a50d6ccd8d76739 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 13 Jul 2021 22:21:26 +0200 Subject: media: ipu3-cio2: Replace open-coded for_each_set_bit() Use for_each_set_bit() instead of open-coding it to simplify the code. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 75 +++++++++++++-------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index e84b8faf76a2..144e3138ee71 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -11,6 +11,7 @@ * et al. */ +#include #include #include #include @@ -612,6 +613,20 @@ static const char *const cio2_irq_errs[] = { "non-matching Long Packet stalled", }; +static void cio2_irq_log_irq_errs(struct device *dev, u8 port, u32 status) +{ + unsigned long csi2_status = status; + unsigned int i; + + for_each_set_bit(i, &csi2_status, ARRAY_SIZE(cio2_irq_errs)) + dev_err(dev, "CSI-2 receiver port %i: %s\n", + port, cio2_irq_errs[i]); + + if (fls_long(csi2_status) >= ARRAY_SIZE(cio2_irq_errs)) + dev_warn(dev, "unknown CSI2 error 0x%lx on port %i\n", + csi2_status, port); +} + static const char *const cio2_port_errs[] = { "ECC recoverable", "DPHY not recoverable", @@ -622,6 +637,15 @@ static const char *const cio2_port_errs[] = { "PKT2LONG", }; +static void cio2_irq_log_port_errs(struct device *dev, u8 port, u32 status) +{ + unsigned long port_status = status; + unsigned int i; + + for_each_set_bit(i, &port_status, ARRAY_SIZE(cio2_port_errs)) + dev_err(dev, "port %i error %s\n", port, cio2_port_errs[i]); +} + static void cio2_irq_handle_once(struct cio2_device *cio2, u32 int_status) { void __iomem *const base = cio2->base; @@ -687,59 +711,32 @@ static void cio2_irq_handle_once(struct cio2_device *cio2, u32 int_status) if (int_status & (CIO2_INT_IOIE | CIO2_INT_IOIRQ)) { /* CSI2 receiver (error) interrupt */ - u32 ie_status, ie_clear; unsigned int port; + u32 ie_status; - ie_clear = readl(base + CIO2_REG_INT_STS_EXT_IE); - ie_status = ie_clear; + ie_status = readl(base + CIO2_REG_INT_STS_EXT_IE); for (port = 0; port < CIO2_NUM_PORTS; port++) { u32 port_status = (ie_status >> (port * 8)) & 0xff; - u32 err_mask = BIT_MASK(ARRAY_SIZE(cio2_port_errs)) - 1; - void __iomem *const csi_rx_base = - base + CIO2_REG_PIPE_BASE(port); - unsigned int i; - - while (port_status & err_mask) { - i = ffs(port_status) - 1; - dev_err(dev, "port %i error %s\n", - port, cio2_port_errs[i]); - ie_status &= ~BIT(port * 8 + i); - port_status &= ~BIT(i); - } + + cio2_irq_log_port_errs(dev, port, port_status); if (ie_status & CIO2_INT_EXT_IE_IRQ(port)) { - u32 csi2_status, csi2_clear; + void __iomem *csi_rx_base = + base + CIO2_REG_PIPE_BASE(port); + u32 csi2_status; csi2_status = readl(csi_rx_base + CIO2_REG_IRQCTRL_STATUS); - csi2_clear = csi2_status; - err_mask = - BIT_MASK(ARRAY_SIZE(cio2_irq_errs)) - 1; - - while (csi2_status & err_mask) { - i = ffs(csi2_status) - 1; - dev_err(dev, - "CSI-2 receiver port %i: %s\n", - port, cio2_irq_errs[i]); - csi2_status &= ~BIT(i); - } - - writel(csi2_clear, - csi_rx_base + CIO2_REG_IRQCTRL_CLEAR); - if (csi2_status) - dev_warn(dev, - "unknown CSI2 error 0x%x on port %i\n", - csi2_status, port); - ie_status &= ~CIO2_INT_EXT_IE_IRQ(port); + cio2_irq_log_irq_errs(dev, port, csi2_status); + + writel(csi2_status, + csi_rx_base + CIO2_REG_IRQCTRL_CLEAR); } } - writel(ie_clear, base + CIO2_REG_INT_STS_EXT_IE); - if (ie_status) - dev_warn(dev, "unknown interrupt 0x%x on IE\n", - ie_status); + writel(ie_status, base + CIO2_REG_INT_STS_EXT_IE); int_status &= ~(CIO2_INT_IOIE | CIO2_INT_IOIRQ); } -- cgit v1.2.3 From cfd13612a5a70715299d2468f967334048ce52a7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 13 Jul 2021 22:21:27 +0200 Subject: media: ipu3-cio2: Use temporary storage for struct device pointer Use temporary storage for struct device pointer to simplify the code. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 138 +++++++++++++------------- 1 file changed, 67 insertions(+), 71 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index 144e3138ee71..5a92dd8268a8 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -103,26 +103,29 @@ static inline u32 cio2_bytesperline(const unsigned int width) static void cio2_fbpt_exit_dummy(struct cio2_device *cio2) { + struct device *dev = &cio2->pci_dev->dev; + if (cio2->dummy_lop) { - dma_free_coherent(&cio2->pci_dev->dev, PAGE_SIZE, - cio2->dummy_lop, cio2->dummy_lop_bus_addr); + dma_free_coherent(dev, PAGE_SIZE, cio2->dummy_lop, + cio2->dummy_lop_bus_addr); cio2->dummy_lop = NULL; } if (cio2->dummy_page) { - dma_free_coherent(&cio2->pci_dev->dev, PAGE_SIZE, - cio2->dummy_page, cio2->dummy_page_bus_addr); + dma_free_coherent(dev, PAGE_SIZE, cio2->dummy_page, + cio2->dummy_page_bus_addr); cio2->dummy_page = NULL; } } static int cio2_fbpt_init_dummy(struct cio2_device *cio2) { + struct device *dev = &cio2->pci_dev->dev; unsigned int i; - cio2->dummy_page = dma_alloc_coherent(&cio2->pci_dev->dev, PAGE_SIZE, + cio2->dummy_page = dma_alloc_coherent(dev, PAGE_SIZE, &cio2->dummy_page_bus_addr, GFP_KERNEL); - cio2->dummy_lop = dma_alloc_coherent(&cio2->pci_dev->dev, PAGE_SIZE, + cio2->dummy_lop = dma_alloc_coherent(dev, PAGE_SIZE, &cio2->dummy_lop_bus_addr, GFP_KERNEL); if (!cio2->dummy_page || !cio2->dummy_lop) { @@ -498,6 +501,7 @@ static int cio2_hw_init(struct cio2_device *cio2, struct cio2_queue *q) static void cio2_hw_exit(struct cio2_device *cio2, struct cio2_queue *q) { + struct device *dev = &cio2->pci_dev->dev; void __iomem *const base = cio2->base; unsigned int i; u32 value; @@ -515,8 +519,7 @@ static void cio2_hw_exit(struct cio2_device *cio2, struct cio2_queue *q) value, value & CIO2_CDMAC0_DMA_HALTED, 4000, 2000000); if (ret) - dev_err(&cio2->pci_dev->dev, - "DMA %i can not be halted\n", CIO2_DMA_CHAN); + dev_err(dev, "DMA %i can not be halted\n", CIO2_DMA_CHAN); for (i = 0; i < CIO2_NUM_PORTS; i++) { writel(readl(base + CIO2_REG_PXM_FRF_CFG(i)) | @@ -540,8 +543,7 @@ static void cio2_buffer_done(struct cio2_device *cio2, unsigned int dma_chan) entry = &q->fbpt[q->bufs_first * CIO2_MAX_LOPS]; if (entry->first_entry.ctrl & CIO2_FBPT_CTRL_VALID) { - dev_warn(&cio2->pci_dev->dev, - "no ready buffers found on DMA channel %u\n", + dev_warn(dev, "no ready buffers found on DMA channel %u\n", dma_chan); return; } @@ -558,8 +560,7 @@ static void cio2_buffer_done(struct cio2_device *cio2, unsigned int dma_chan) q->bufs[q->bufs_first] = NULL; atomic_dec(&q->bufs_queued); - dev_dbg(&cio2->pci_dev->dev, - "buffer %i done\n", b->vbb.vb2_buf.index); + dev_dbg(dev, "buffer %i done\n", b->vbb.vb2_buf.index); b->vbb.vb2_buf.timestamp = ns; b->vbb.field = V4L2_FIELD_NONE; @@ -648,8 +649,8 @@ static void cio2_irq_log_port_errs(struct device *dev, u8 port, u32 status) static void cio2_irq_handle_once(struct cio2_device *cio2, u32 int_status) { - void __iomem *const base = cio2->base; struct device *dev = &cio2->pci_dev->dev; + void __iomem *const base = cio2->base; if (int_status & CIO2_INT_IOOE) { /* @@ -792,6 +793,7 @@ static int cio2_vb2_queue_setup(struct vb2_queue *vq, struct device *alloc_devs[]) { struct cio2_device *cio2 = vb2_get_drv_priv(vq); + struct device *dev = &cio2->pci_dev->dev; struct cio2_queue *q = vb2q_to_cio2_queue(vq); unsigned int i; @@ -799,7 +801,7 @@ static int cio2_vb2_queue_setup(struct vb2_queue *vq, for (i = 0; i < *num_planes; ++i) { sizes[i] = q->format.plane_fmt[i].sizeimage; - alloc_devs[i] = &cio2->pci_dev->dev; + alloc_devs[i] = dev; } *num_buffers = clamp_val(*num_buffers, 1, CIO2_MAX_BUFFERS); @@ -876,6 +878,7 @@ fail: static void cio2_vb2_buf_queue(struct vb2_buffer *vb) { struct cio2_device *cio2 = vb2_get_drv_priv(vb->vb2_queue); + struct device *dev = &cio2->pci_dev->dev; struct cio2_queue *q = container_of(vb->vb2_queue, struct cio2_queue, vbq); struct cio2_buffer *b = @@ -886,7 +889,7 @@ static void cio2_vb2_buf_queue(struct vb2_buffer *vb) int bufs_queued = atomic_inc_return(&q->bufs_queued); u32 fbpt_rp; - dev_dbg(&cio2->pci_dev->dev, "queue buffer %d\n", vb->index); + dev_dbg(dev, "queue buffer %d\n", vb->index); /* * This code queues the buffer to the CIO2 DMA engine, which starts @@ -937,12 +940,12 @@ static void cio2_vb2_buf_queue(struct vb2_buffer *vb) return; } - dev_dbg(&cio2->pci_dev->dev, "entry %i was full!\n", next); + dev_dbg(dev, "entry %i was full!\n", next); next = (next + 1) % CIO2_MAX_BUFFERS; } local_irq_restore(flags); - dev_err(&cio2->pci_dev->dev, "error: all cio2 entries were full!\n"); + dev_err(dev, "error: all cio2 entries were full!\n"); atomic_dec(&q->bufs_queued); vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); } @@ -951,6 +954,7 @@ static void cio2_vb2_buf_queue(struct vb2_buffer *vb) static void cio2_vb2_buf_cleanup(struct vb2_buffer *vb) { struct cio2_device *cio2 = vb2_get_drv_priv(vb->vb2_queue); + struct device *dev = &cio2->pci_dev->dev; struct cio2_buffer *b = container_of(vb, struct cio2_buffer, vbb.vb2_buf); unsigned int i; @@ -958,7 +962,7 @@ static void cio2_vb2_buf_cleanup(struct vb2_buffer *vb) /* Free LOP table */ for (i = 0; i < CIO2_MAX_LOPS; i++) { if (b->lop[i]) - dma_free_coherent(&cio2->pci_dev->dev, PAGE_SIZE, + dma_free_coherent(dev, PAGE_SIZE, b->lop[i], b->lop_bus_addr[i]); } } @@ -967,14 +971,15 @@ static int cio2_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) { struct cio2_queue *q = vb2q_to_cio2_queue(vq); struct cio2_device *cio2 = vb2_get_drv_priv(vq); + struct device *dev = &cio2->pci_dev->dev; int r; cio2->cur_queue = q; atomic_set(&q->frame_sequence, 0); - r = pm_runtime_resume_and_get(&cio2->pci_dev->dev); + r = pm_runtime_resume_and_get(dev); if (r < 0) { - dev_info(&cio2->pci_dev->dev, "failed to set power %d\n", r); + dev_info(dev, "failed to set power %d\n", r); return r; } @@ -1000,9 +1005,9 @@ fail_csi2_subdev: fail_hw: media_pipeline_stop(&q->vdev.entity); fail_pipeline: - dev_dbg(&cio2->pci_dev->dev, "failed to start streaming (%d)\n", r); + dev_dbg(dev, "failed to start streaming (%d)\n", r); cio2_vb2_return_all_buffers(q, VB2_BUF_STATE_QUEUED); - pm_runtime_put(&cio2->pci_dev->dev); + pm_runtime_put(dev); return r; } @@ -1011,16 +1016,16 @@ static void cio2_vb2_stop_streaming(struct vb2_queue *vq) { struct cio2_queue *q = vb2q_to_cio2_queue(vq); struct cio2_device *cio2 = vb2_get_drv_priv(vq); + struct device *dev = &cio2->pci_dev->dev; if (v4l2_subdev_call(q->sensor, video, s_stream, 0)) - dev_err(&cio2->pci_dev->dev, - "failed to stop sensor streaming\n"); + dev_err(dev, "failed to stop sensor streaming\n"); cio2_hw_exit(cio2, q); synchronize_irq(cio2->pci_dev->irq); cio2_vb2_return_all_buffers(q, VB2_BUF_STATE_ERROR); media_pipeline_stop(&q->vdev.entity); - pm_runtime_put(&cio2->pci_dev->dev); + pm_runtime_put(dev); cio2->streaming = false; } @@ -1312,12 +1317,12 @@ static int cio2_video_link_validate(struct media_link *link) struct video_device, entity); struct cio2_queue *q = container_of(vd, struct cio2_queue, vdev); struct cio2_device *cio2 = video_get_drvdata(vd); + struct device *dev = &cio2->pci_dev->dev; struct v4l2_subdev_format source_fmt; int ret; if (!media_entity_remote_pad(link->sink->entity->pads)) { - dev_info(&cio2->pci_dev->dev, - "video node %s pad not connected\n", vd->name); + dev_info(dev, "video node %s pad not connected\n", vd->name); return -ENOTCONN; } @@ -1327,8 +1332,7 @@ static int cio2_video_link_validate(struct media_link *link) if (source_fmt.format.width != q->format.width || source_fmt.format.height != q->format.height) { - dev_err(&cio2->pci_dev->dev, - "Wrong width or height %ux%u (%ux%u expected)\n", + dev_err(dev, "Wrong width or height %ux%u (%ux%u expected)\n", q->format.width, q->format.height, source_fmt.format.width, source_fmt.format.height); return -EINVAL; @@ -1409,6 +1413,7 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier) { struct cio2_device *cio2 = container_of(notifier, struct cio2_device, notifier); + struct device *dev = &cio2->pci_dev->dev; struct sensor_async_subdev *s_asd; struct v4l2_async_subdev *asd; struct cio2_queue *q; @@ -1425,8 +1430,7 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier) break; if (pad == q->sensor->entity.num_pads) { - dev_err(&cio2->pci_dev->dev, - "failed to find src pad for %s\n", + dev_err(dev, "failed to find src pad for %s\n", q->sensor->name); return -ENXIO; } @@ -1436,8 +1440,7 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier) &q->subdev.entity, CIO2_PAD_SINK, 0); if (ret) { - dev_err(&cio2->pci_dev->dev, - "failed to create link for %s\n", + dev_err(dev, "failed to create link for %s\n", q->sensor->name); return ret; } @@ -1454,6 +1457,7 @@ static const struct v4l2_async_notifier_operations cio2_async_ops = { static int cio2_parse_firmware(struct cio2_device *cio2) { + struct device *dev = &cio2->pci_dev->dev; unsigned int i; int ret; @@ -1464,10 +1468,8 @@ static int cio2_parse_firmware(struct cio2_device *cio2) struct sensor_async_subdev *s_asd; struct fwnode_handle *ep; - ep = fwnode_graph_get_endpoint_by_id( - dev_fwnode(&cio2->pci_dev->dev), i, 0, - FWNODE_GRAPH_ENDPOINT_NEXT); - + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), i, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); if (!ep) continue; @@ -1502,8 +1504,7 @@ err_parse: cio2->notifier.ops = &cio2_async_ops; ret = v4l2_async_nf_register(&cio2->v4l2_dev, &cio2->notifier); if (ret) - dev_err(&cio2->pci_dev->dev, - "failed to register async notifier : %d\n", ret); + dev_err(dev, "failed to register async notifier : %d\n", ret); return ret; } @@ -1522,7 +1523,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) static const u32 default_width = 1936; static const u32 default_height = 1096; const struct ipu3_cio2_fmt dflt_fmt = formats[0]; - + struct device *dev = &cio2->pci_dev->dev; struct video_device *vdev = &q->vdev; struct vb2_queue *vbq = &q->vbq; struct v4l2_subdev *subdev = &q->subdev; @@ -1564,8 +1565,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) subdev->internal_ops = &cio2_subdev_internal_ops; r = media_entity_pads_init(&subdev->entity, CIO2_PADS, q->subdev_pads); if (r) { - dev_err(&cio2->pci_dev->dev, - "failed initialize subdev media entity (%d)\n", r); + dev_err(dev, "failed initialize subdev media entity (%d)\n", r); goto fail_subdev_media_entity; } @@ -1573,8 +1573,8 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) vdev->entity.ops = &cio2_video_entity_ops; r = media_entity_pads_init(&vdev->entity, 1, &q->vdev_pad); if (r) { - dev_err(&cio2->pci_dev->dev, - "failed initialize videodev media entity (%d)\n", r); + dev_err(dev, "failed initialize videodev media entity (%d)\n", + r); goto fail_vdev_media_entity; } @@ -1588,8 +1588,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) v4l2_set_subdevdata(subdev, cio2); r = v4l2_device_register_subdev(&cio2->v4l2_dev, subdev); if (r) { - dev_err(&cio2->pci_dev->dev, - "failed initialize subdev (%d)\n", r); + dev_err(dev, "failed initialize subdev (%d)\n", r); goto fail_subdev; } @@ -1605,8 +1604,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) vbq->lock = &q->lock; r = vb2_queue_init(vbq); if (r) { - dev_err(&cio2->pci_dev->dev, - "failed to initialize videobuf2 queue (%d)\n", r); + dev_err(dev, "failed to initialize videobuf2 queue (%d)\n", r); goto fail_subdev; } @@ -1623,8 +1621,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) video_set_drvdata(vdev, cio2); r = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (r) { - dev_err(&cio2->pci_dev->dev, - "failed to register video device (%d)\n", r); + dev_err(dev, "failed to register video device (%d)\n", r); goto fail_vdev; } @@ -1646,7 +1643,7 @@ fail_subdev: fail_vdev_media_entity: media_entity_cleanup(&subdev->entity); fail_subdev_media_entity: - cio2_fbpt_exit(q, &cio2->pci_dev->dev); + cio2_fbpt_exit(q, dev); fail_fbpt: mutex_destroy(&q->subdev_lock); mutex_destroy(&q->lock); @@ -1713,11 +1710,12 @@ static int cio2_check_fwnode_graph(struct fwnode_handle *fwnode) static int cio2_pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) { - struct fwnode_handle *fwnode = dev_fwnode(&pci_dev->dev); + struct device *dev = &pci_dev->dev; + struct fwnode_handle *fwnode = dev_fwnode(dev); struct cio2_device *cio2; int r; - cio2 = devm_kzalloc(&pci_dev->dev, sizeof(*cio2), GFP_KERNEL); + cio2 = devm_kzalloc(dev, sizeof(*cio2), GFP_KERNEL); if (!cio2) return -ENOMEM; cio2->pci_dev = pci_dev; @@ -1730,7 +1728,7 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, r = cio2_check_fwnode_graph(fwnode); if (r) { if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary)) { - dev_err(&pci_dev->dev, "fwnode graph has no endpoints connected\n"); + dev_err(dev, "fwnode graph has no endpoints connected\n"); return -EINVAL; } @@ -1741,16 +1739,16 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, r = pcim_enable_device(pci_dev); if (r) { - dev_err(&pci_dev->dev, "failed to enable device (%d)\n", r); + dev_err(dev, "failed to enable device (%d)\n", r); return r; } - dev_info(&pci_dev->dev, "device 0x%x (rev: 0x%x)\n", + dev_info(dev, "device 0x%x (rev: 0x%x)\n", pci_dev->device, pci_dev->revision); r = pcim_iomap_regions(pci_dev, 1 << CIO2_PCI_BAR, pci_name(pci_dev)); if (r) { - dev_err(&pci_dev->dev, "failed to remap I/O memory (%d)\n", r); + dev_err(dev, "failed to remap I/O memory (%d)\n", r); return -ENODEV; } @@ -1762,13 +1760,13 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, r = pci_set_dma_mask(pci_dev, CIO2_DMA_MASK); if (r) { - dev_err(&pci_dev->dev, "failed to set DMA mask (%d)\n", r); + dev_err(dev, "failed to set DMA mask (%d)\n", r); return -ENODEV; } r = pci_enable_msi(pci_dev); if (r) { - dev_err(&pci_dev->dev, "failed to enable MSI (%d)\n", r); + dev_err(dev, "failed to enable MSI (%d)\n", r); return r; } @@ -1778,7 +1776,7 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, mutex_init(&cio2->lock); - cio2->media_dev.dev = &cio2->pci_dev->dev; + cio2->media_dev.dev = dev; strscpy(cio2->media_dev.model, CIO2_DEVICE_NAME, sizeof(cio2->media_dev.model)); snprintf(cio2->media_dev.bus_info, sizeof(cio2->media_dev.bus_info), @@ -1791,10 +1789,9 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, goto fail_mutex_destroy; cio2->v4l2_dev.mdev = &cio2->media_dev; - r = v4l2_device_register(&pci_dev->dev, &cio2->v4l2_dev); + r = v4l2_device_register(dev, &cio2->v4l2_dev); if (r) { - dev_err(&pci_dev->dev, - "failed to register V4L2 device (%d)\n", r); + dev_err(dev, "failed to register V4L2 device (%d)\n", r); goto fail_media_device_unregister; } @@ -1809,15 +1806,15 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, if (r) goto fail_clean_notifier; - r = devm_request_irq(&pci_dev->dev, pci_dev->irq, cio2_irq, - IRQF_SHARED, CIO2_NAME, cio2); + r = devm_request_irq(dev, pci_dev->irq, cio2_irq, IRQF_SHARED, + CIO2_NAME, cio2); if (r) { - dev_err(&pci_dev->dev, "failed to request IRQ (%d)\n", r); + dev_err(dev, "failed to request IRQ (%d)\n", r); goto fail_clean_notifier; } - pm_runtime_put_noidle(&pci_dev->dev); - pm_runtime_allow(&pci_dev->dev); + pm_runtime_put_noidle(dev); + pm_runtime_allow(dev); return 0; @@ -2003,10 +2000,9 @@ static int __maybe_unused cio2_resume(struct device *dev) if (!cio2->streaming) return 0; /* Start stream */ - r = pm_runtime_force_resume(&cio2->pci_dev->dev); + r = pm_runtime_force_resume(dev); if (r < 0) { - dev_err(&cio2->pci_dev->dev, - "failed to set power %d\n", r); + dev_err(dev, "failed to set power %d\n", r); return r; } -- cgit v1.2.3 From 98508d683970992748c1c19543e866beaccd14ad Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 13 Jul 2021 22:21:28 +0200 Subject: media: ipu3-cio2: Switch to use media_entity_to_video_device() V4L2 provides a few helper macros, in particular media_entity_to_video_device(). Switch the driver to use it instead of open-coded variant. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index 5a92dd8268a8..0cf788cf0e5f 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -1313,15 +1313,15 @@ static int cio2_subdev_link_validate_get_format(struct media_pad *pad, static int cio2_video_link_validate(struct media_link *link) { - struct video_device *vd = container_of(link->sink->entity, - struct video_device, entity); + struct media_entity *entity = link->sink->entity; + struct video_device *vd = media_entity_to_video_device(entity); struct cio2_queue *q = container_of(vd, struct cio2_queue, vdev); struct cio2_device *cio2 = video_get_drvdata(vd); struct device *dev = &cio2->pci_dev->dev; struct v4l2_subdev_format source_fmt; int ret; - if (!media_entity_remote_pad(link->sink->entity->pads)) { + if (!media_entity_remote_pad(entity->pads)) { dev_info(dev, "video node %s pad not connected\n", vd->name); return -ENOTCONN; } -- cgit v1.2.3 From 66ec7a97d2f8098e7d0a60e966a58c1d2e4bdaef Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 13 Jul 2021 22:21:29 +0200 Subject: media: ipu3-cio2: Introduce to_sensor_asd() helper macro Provide to_sensor_asd() helper macro and convert users to make code easier to read. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index 0cf788cf0e5f..99ed632a81d3 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -1372,6 +1372,8 @@ struct sensor_async_subdev { struct csi2_bus_info csi2; }; +#define to_sensor_asd(asd) container_of(asd, struct sensor_async_subdev, asd) + /* The .bound() notifier callback when a match is found */ static int cio2_notifier_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd, @@ -1379,8 +1381,7 @@ static int cio2_notifier_bound(struct v4l2_async_notifier *notifier, { struct cio2_device *cio2 = container_of(notifier, struct cio2_device, notifier); - struct sensor_async_subdev *s_asd = container_of(asd, - struct sensor_async_subdev, asd); + struct sensor_async_subdev *s_asd = to_sensor_asd(asd); struct cio2_queue *q; if (cio2->queue[s_asd->csi2.port].sensor) @@ -1402,8 +1403,7 @@ static void cio2_notifier_unbind(struct v4l2_async_notifier *notifier, { struct cio2_device *cio2 = container_of(notifier, struct cio2_device, notifier); - struct sensor_async_subdev *s_asd = container_of(asd, - struct sensor_async_subdev, asd); + struct sensor_async_subdev *s_asd = to_sensor_asd(asd); cio2->queue[s_asd->csi2.port].sensor = NULL; } @@ -1421,7 +1421,7 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier) int ret; list_for_each_entry(asd, &cio2->notifier.asd_list, asd_list) { - s_asd = container_of(asd, struct sensor_async_subdev, asd); + s_asd = to_sensor_asd(asd); q = &cio2->queue[s_asd->csi2.port]; for (pad = 0; pad < q->sensor->entity.num_pads; pad++) -- cgit v1.2.3 From 8b0a8b1b612cdb6ed50fa3e07a87513fe6b3b627 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 13 Jul 2021 22:21:30 +0200 Subject: media: ipu3-cio2: Introduce to_cio2_buffer() helper macro Provide to_cio2_buffer() helper macro and convert users to make code easier to read. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 9 +++------ drivers/media/pci/intel/ipu3/ipu3-cio2.h | 2 ++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index 99ed632a81d3..0cb102e8dff1 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -823,8 +823,7 @@ static int cio2_vb2_buf_init(struct vb2_buffer *vb) { struct cio2_device *cio2 = vb2_get_drv_priv(vb->vb2_queue); struct device *dev = &cio2->pci_dev->dev; - struct cio2_buffer *b = - container_of(vb, struct cio2_buffer, vbb.vb2_buf); + struct cio2_buffer *b = to_cio2_buffer(vb); unsigned int pages = PFN_UP(vb->planes[0].length); unsigned int lops = DIV_ROUND_UP(pages + 1, CIO2_LOP_ENTRIES); struct sg_table *sg; @@ -881,8 +880,7 @@ static void cio2_vb2_buf_queue(struct vb2_buffer *vb) struct device *dev = &cio2->pci_dev->dev; struct cio2_queue *q = container_of(vb->vb2_queue, struct cio2_queue, vbq); - struct cio2_buffer *b = - container_of(vb, struct cio2_buffer, vbb.vb2_buf); + struct cio2_buffer *b = to_cio2_buffer(vb); struct cio2_fbpt_entry *entry; unsigned long flags; unsigned int i, j, next = q->bufs_next; @@ -955,8 +953,7 @@ static void cio2_vb2_buf_cleanup(struct vb2_buffer *vb) { struct cio2_device *cio2 = vb2_get_drv_priv(vb->vb2_queue); struct device *dev = &cio2->pci_dev->dev; - struct cio2_buffer *b = - container_of(vb, struct cio2_buffer, vbb.vb2_buf); + struct cio2_buffer *b = to_cio2_buffer(vb); unsigned int i; /* Free LOP table */ diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h index 3806d7f04d69..f82f9b2590b9 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h @@ -338,6 +338,8 @@ struct cio2_buffer { unsigned int offset; }; +#define to_cio2_buffer(vb) container_of(vb, struct cio2_buffer, vbb.vb2_buf) + struct csi2_bus_info { u32 port; u32 lanes; -- cgit v1.2.3 From 96d309a9330e0198e21b98487277935d9434ab6c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 13 Jul 2021 22:21:31 +0200 Subject: media: ipu3-cio2: Introduce to_cio2_device() helper macro Provide to_cio2_device() helper macro and convert users to make code easier to read. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 9 +++------ drivers/media/pci/intel/ipu3/ipu3-cio2.h | 2 ++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index 0cb102e8dff1..8bcba168cc57 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -1376,8 +1376,7 @@ static int cio2_notifier_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) { - struct cio2_device *cio2 = container_of(notifier, - struct cio2_device, notifier); + struct cio2_device *cio2 = to_cio2_device(notifier); struct sensor_async_subdev *s_asd = to_sensor_asd(asd); struct cio2_queue *q; @@ -1398,8 +1397,7 @@ static void cio2_notifier_unbind(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) { - struct cio2_device *cio2 = container_of(notifier, - struct cio2_device, notifier); + struct cio2_device *cio2 = to_cio2_device(notifier); struct sensor_async_subdev *s_asd = to_sensor_asd(asd); cio2->queue[s_asd->csi2.port].sensor = NULL; @@ -1408,8 +1406,7 @@ static void cio2_notifier_unbind(struct v4l2_async_notifier *notifier, /* .complete() is called after all subdevices have been located */ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier) { - struct cio2_device *cio2 = container_of(notifier, struct cio2_device, - notifier); + struct cio2_device *cio2 = to_cio2_device(notifier); struct device *dev = &cio2->pci_dev->dev; struct sensor_async_subdev *s_asd; struct v4l2_async_subdev *asd; diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h index f82f9b2590b9..3a1f394e05aa 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h @@ -401,6 +401,8 @@ struct cio2_device { dma_addr_t dummy_lop_bus_addr; }; +#define to_cio2_device(n) container_of(n, struct cio2_device, notifier) + /**************** Virtual channel ****************/ /* * This should come from sensor driver. No -- cgit v1.2.3 From d170b0ea1760989fe8ac053bef83e61f3bf87992 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 16 Aug 2021 15:08:59 +0200 Subject: media: imx258: Fix getting clock frequency Obtain the clock frequency by reading the clock-frequency property if there's no clock. Fixes: 9fda25332c4b ("media: i2c: imx258: get clock from device properties and enable it via runtime PM") Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx258.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c index 81cdf37216ca..c249507aa2db 100644 --- a/drivers/media/i2c/imx258.c +++ b/drivers/media/i2c/imx258.c @@ -1260,18 +1260,18 @@ static int imx258_probe(struct i2c_client *client) return -ENOMEM; imx258->clk = devm_clk_get_optional(&client->dev, NULL); + if (IS_ERR(imx258->clk)) + return dev_err_probe(&client->dev, PTR_ERR(imx258->clk), + "error getting clock\n"); if (!imx258->clk) { dev_dbg(&client->dev, "no clock provided, using clock-frequency property\n"); device_property_read_u32(&client->dev, "clock-frequency", &val); - if (val != IMX258_INPUT_CLOCK_FREQ) - return -EINVAL; - } else if (IS_ERR(imx258->clk)) { - return dev_err_probe(&client->dev, PTR_ERR(imx258->clk), - "error getting clock\n"); + } else { + val = clk_get_rate(imx258->clk); } - if (clk_get_rate(imx258->clk) != IMX258_INPUT_CLOCK_FREQ) { + if (val != IMX258_INPUT_CLOCK_FREQ) { dev_err(&client->dev, "input clock frequency not supported\n"); return -EINVAL; } -- cgit v1.2.3 From 7ee85054682299babdb32f597b11daeec2d3e9d9 Mon Sep 17 00:00:00 2001 From: Arec Kao Date: Tue, 17 Aug 2021 06:46:07 +0200 Subject: media: Add sensor driver support for the ov13b10 camera. This driver supports following features: - phase detection auto focus (PDAF) - manual exposure and analog/digital gain control - vblank/hblank control - test pattern - image vertical flip and horizontal mirror control - 4208x3120 at 30FPS - 2080x1170 at 60FPS Signed-off-by: Arec Kao Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 7 + drivers/media/i2c/Kconfig | 10 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/ov13b10.c | 1491 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1509 insertions(+) create mode 100644 drivers/media/i2c/ov13b10.c diff --git a/MAINTAINERS b/MAINTAINERS index 943b7bc93c93..f3761373e7c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13800,6 +13800,13 @@ S: Maintained T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/ov13858.c +OMNIVISION OV13B10 SENSOR DRIVER +M: Arec Kao +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: drivers/media/i2c/ov13b10.c + OMNIVISION OV2680 SENSOR DRIVER M: Rui Miguel Silva L: linux-media@vger.kernel.org diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index c26b05ed1f72..cfbcda1f7e48 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -1186,6 +1186,16 @@ config VIDEO_OV13858 This is a Video4Linux2 sensor driver for the OmniVision OV13858 camera. +config VIDEO_OV13B10 + tristate "OmniVision OV13B10 sensor support" + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the OmniVision + OV13B10 camera. + config VIDEO_VS6624 tristate "ST VS6624 sensor support" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 83268f20aa3a..5ac8d639e5ca 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_VIDEO_OV9640) += ov9640.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o obj-$(CONFIG_VIDEO_OV9734) += ov9734.o obj-$(CONFIG_VIDEO_OV13858) += ov13858.o +obj-$(CONFIG_VIDEO_OV13B10) += ov13b10.o obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o diff --git a/drivers/media/i2c/ov13b10.c b/drivers/media/i2c/ov13b10.c new file mode 100644 index 000000000000..7caeae641051 --- /dev/null +++ b/drivers/media/i2c/ov13b10.c @@ -0,0 +1,1491 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2021 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include + +#define OV13B10_REG_VALUE_08BIT 1 +#define OV13B10_REG_VALUE_16BIT 2 +#define OV13B10_REG_VALUE_24BIT 3 + +#define OV13B10_REG_MODE_SELECT 0x0100 +#define OV13B10_MODE_STANDBY 0x00 +#define OV13B10_MODE_STREAMING 0x01 + +#define OV13B10_REG_SOFTWARE_RST 0x0103 +#define OV13B10_SOFTWARE_RST 0x01 + +/* Chip ID */ +#define OV13B10_REG_CHIP_ID 0x300a +#define OV13B10_CHIP_ID 0x560d42 + +/* V_TIMING internal */ +#define OV13B10_REG_VTS 0x380e +#define OV13B10_VTS_30FPS 0x0c7c +#define OV13B10_VTS_60FPS 0x063e +#define OV13B10_VTS_MAX 0x7fff + +/* HBLANK control - read only */ +#define OV13B10_PPL_560MHZ 4704 + +/* Exposure control */ +#define OV13B10_REG_EXPOSURE 0x3500 +#define OV13B10_EXPOSURE_MIN 4 +#define OV13B10_EXPOSURE_STEP 1 +#define OV13B10_EXPOSURE_DEFAULT 0x40 + +/* Analog gain control */ +#define OV13B10_REG_ANALOG_GAIN 0x3508 +#define OV13B10_ANA_GAIN_MIN 0x80 +#define OV13B10_ANA_GAIN_MAX 0x07c0 +#define OV13B10_ANA_GAIN_STEP 1 +#define OV13B10_ANA_GAIN_DEFAULT 0x80 + +/* Digital gain control */ +#define OV13B10_REG_DGTL_GAIN_H 0x350a +#define OV13B10_REG_DGTL_GAIN_M 0x350b +#define OV13B10_REG_DGTL_GAIN_L 0x350c + +#define OV13B10_DGTL_GAIN_MIN 1024 /* Min = 1 X */ +#define OV13B10_DGTL_GAIN_MAX (4096 - 1) /* Max = 4 X */ +#define OV13B10_DGTL_GAIN_DEFAULT 2560 /* Default gain = 2.5 X */ +#define OV13B10_DGTL_GAIN_STEP 1 /* Each step = 1/1024 */ + +#define OV13B10_DGTL_GAIN_L_SHIFT 6 +#define OV13B10_DGTL_GAIN_L_MASK 0x3 +#define OV13B10_DGTL_GAIN_M_SHIFT 2 +#define OV13B10_DGTL_GAIN_M_MASK 0xff +#define OV13B10_DGTL_GAIN_H_SHIFT 10 +#define OV13B10_DGTL_GAIN_H_MASK 0x3 + +/* Test Pattern Control */ +#define OV13B10_REG_TEST_PATTERN 0x5080 +#define OV13B10_TEST_PATTERN_ENABLE BIT(7) +#define OV13B10_TEST_PATTERN_MASK 0xf3 +#define OV13B10_TEST_PATTERN_BAR_SHIFT 2 + +/* Flip Control */ +#define OV13B10_REG_FORMAT1 0x3820 +#define OV13B10_REG_FORMAT2 0x3821 + +/* Horizontal Window Offset */ +#define OV13B10_REG_H_WIN_OFFSET 0x3811 + +/* Vertical Window Offset */ +#define OV13B10_REG_V_WIN_OFFSET 0x3813 + +struct ov13b10_reg { + u16 address; + u8 val; +}; + +struct ov13b10_reg_list { + u32 num_of_regs; + const struct ov13b10_reg *regs; +}; + +/* Link frequency config */ +struct ov13b10_link_freq_config { + u32 pixels_per_line; + + /* registers for this link frequency */ + struct ov13b10_reg_list reg_list; +}; + +/* Mode : resolution and related config&values */ +struct ov13b10_mode { + /* Frame width */ + u32 width; + /* Frame height */ + u32 height; + + /* V-timing */ + u32 vts_def; + u32 vts_min; + + /* Index of Link frequency config to be used */ + u32 link_freq_index; + /* Default register values */ + struct ov13b10_reg_list reg_list; +}; + +/* 4208x3120 needs 1120Mbps/lane, 4 lanes */ +static const struct ov13b10_reg mipi_data_rate_1120mbps[] = { + {0x0103, 0x01}, + {0x0303, 0x04}, + {0x0305, 0xaf}, + {0x0321, 0x00}, + {0x0323, 0x04}, + {0x0324, 0x01}, + {0x0325, 0xa4}, + {0x0326, 0x81}, + {0x0327, 0x04}, + {0x3012, 0x07}, + {0x3013, 0x32}, + {0x3107, 0x23}, + {0x3501, 0x0c}, + {0x3502, 0x10}, + {0x3504, 0x08}, + {0x3508, 0x07}, + {0x3509, 0xc0}, + {0x3600, 0x16}, + {0x3601, 0x54}, + {0x3612, 0x4e}, + {0x3620, 0x00}, + {0x3621, 0x68}, + {0x3622, 0x66}, + {0x3623, 0x03}, + {0x3662, 0x92}, + {0x3666, 0xbb}, + {0x3667, 0x44}, + {0x366e, 0xff}, + {0x366f, 0xf3}, + {0x3675, 0x44}, + {0x3676, 0x00}, + {0x367f, 0xe9}, + {0x3681, 0x32}, + {0x3682, 0x1f}, + {0x3683, 0x0b}, + {0x3684, 0x0b}, + {0x3704, 0x0f}, + {0x3706, 0x40}, + {0x3708, 0x3b}, + {0x3709, 0x72}, + {0x370b, 0xa2}, + {0x3714, 0x24}, + {0x371a, 0x3e}, + {0x3725, 0x42}, + {0x3739, 0x12}, + {0x3767, 0x00}, + {0x377a, 0x0d}, + {0x3789, 0x18}, + {0x3790, 0x40}, + {0x3791, 0xa2}, + {0x37c2, 0x04}, + {0x37c3, 0xf1}, + {0x37d9, 0x0c}, + {0x37da, 0x02}, + {0x37dc, 0x02}, + {0x37e1, 0x04}, + {0x37e2, 0x0a}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x08}, + {0x3804, 0x10}, + {0x3805, 0x8f}, + {0x3806, 0x0c}, + {0x3807, 0x47}, + {0x3808, 0x10}, + {0x3809, 0x70}, + {0x380a, 0x0c}, + {0x380b, 0x30}, + {0x380c, 0x04}, + {0x380d, 0x98}, + {0x380e, 0x0c}, + {0x380f, 0x7c}, + {0x3811, 0x0f}, + {0x3813, 0x09}, + {0x3814, 0x01}, + {0x3815, 0x01}, + {0x3816, 0x01}, + {0x3817, 0x01}, + {0x381f, 0x08}, + {0x3820, 0x88}, + {0x3821, 0x00}, + {0x3822, 0x14}, + {0x382e, 0xe6}, + {0x3c80, 0x00}, + {0x3c87, 0x01}, + {0x3c8c, 0x19}, + {0x3c8d, 0x1c}, + {0x3ca0, 0x00}, + {0x3ca1, 0x00}, + {0x3ca2, 0x00}, + {0x3ca3, 0x00}, + {0x3ca4, 0x50}, + {0x3ca5, 0x11}, + {0x3ca6, 0x01}, + {0x3ca7, 0x00}, + {0x3ca8, 0x00}, + {0x4008, 0x02}, + {0x4009, 0x0f}, + {0x400a, 0x01}, + {0x400b, 0x19}, + {0x4011, 0x21}, + {0x4017, 0x08}, + {0x4019, 0x04}, + {0x401a, 0x58}, + {0x4032, 0x1e}, + {0x4050, 0x02}, + {0x4051, 0x09}, + {0x405e, 0x00}, + {0x4066, 0x02}, + {0x4501, 0x00}, + {0x4502, 0x10}, + {0x4505, 0x00}, + {0x4800, 0x64}, + {0x481b, 0x3e}, + {0x481f, 0x30}, + {0x4825, 0x34}, + {0x4837, 0x0e}, + {0x484b, 0x01}, + {0x4883, 0x02}, + {0x5000, 0xff}, + {0x5001, 0x0f}, + {0x5045, 0x20}, + {0x5046, 0x20}, + {0x5047, 0xa4}, + {0x5048, 0x20}, + {0x5049, 0xa4}, + {0x0100, 0x01}, +}; + +static const struct ov13b10_reg mode_4208x3120_regs[] = { + {0x0305, 0xaf}, + {0x3501, 0x0c}, + {0x3662, 0x92}, + {0x3714, 0x24}, + {0x3739, 0x12}, + {0x37c2, 0x04}, + {0x37d9, 0x0c}, + {0x37e2, 0x0a}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x08}, + {0x3804, 0x10}, + {0x3805, 0x8f}, + {0x3806, 0x0c}, + {0x3807, 0x47}, + {0x3808, 0x10}, + {0x3809, 0x70}, + {0x380a, 0x0c}, + {0x380b, 0x30}, + {0x380c, 0x04}, + {0x380d, 0x98}, + {0x380e, 0x0c}, + {0x380f, 0x7c}, + {0x3810, 0x00}, + {0x3811, 0x0f}, + {0x3812, 0x00}, + {0x3813, 0x09}, + {0x3814, 0x01}, + {0x3816, 0x01}, + {0x3820, 0x88}, + {0x3c8c, 0x19}, + {0x4008, 0x02}, + {0x4009, 0x0f}, + {0x4050, 0x02}, + {0x4051, 0x09}, + {0x4501, 0x00}, + {0x4505, 0x00}, + {0x4837, 0x0e}, + {0x5000, 0xff}, + {0x5001, 0x0f}, +}; + +static const struct ov13b10_reg mode_4160x3120_regs[] = { + {0x0305, 0xaf}, + {0x3501, 0x0c}, + {0x3662, 0x92}, + {0x3714, 0x24}, + {0x3739, 0x12}, + {0x37c2, 0x04}, + {0x37d9, 0x0c}, + {0x37e2, 0x0a}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x08}, + {0x3804, 0x10}, + {0x3805, 0x8f}, + {0x3806, 0x0c}, + {0x3807, 0x47}, + {0x3808, 0x10}, + {0x3809, 0x40}, + {0x380a, 0x0c}, + {0x380b, 0x30}, + {0x380c, 0x04}, + {0x380d, 0x98}, + {0x380e, 0x0c}, + {0x380f, 0x7c}, + {0x3810, 0x00}, + {0x3811, 0x27}, + {0x3812, 0x00}, + {0x3813, 0x09}, + {0x3814, 0x01}, + {0x3816, 0x01}, + {0x3820, 0x88}, + {0x3c8c, 0x19}, + {0x4008, 0x02}, + {0x4009, 0x0f}, + {0x4050, 0x02}, + {0x4051, 0x09}, + {0x4501, 0x00}, + {0x4505, 0x00}, + {0x4837, 0x0e}, + {0x5000, 0xff}, + {0x5001, 0x0f}, +}; + +static const struct ov13b10_reg mode_4160x2340_regs[] = { + {0x0305, 0xaf}, + {0x3501, 0x0c}, + {0x3662, 0x92}, + {0x3714, 0x24}, + {0x3739, 0x12}, + {0x37c2, 0x04}, + {0x37d9, 0x0c}, + {0x37e2, 0x0a}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x08}, + {0x3804, 0x10}, + {0x3805, 0x8f}, + {0x3806, 0x0c}, + {0x3807, 0x47}, + {0x3808, 0x10}, + {0x3809, 0x40}, + {0x380a, 0x09}, + {0x380b, 0x24}, + {0x380c, 0x04}, + {0x380d, 0x98}, + {0x380e, 0x0c}, + {0x380f, 0x7c}, + {0x3810, 0x00}, + {0x3811, 0x27}, + {0x3812, 0x01}, + {0x3813, 0x8f}, + {0x3814, 0x01}, + {0x3816, 0x01}, + {0x3820, 0x88}, + {0x3c8c, 0x19}, + {0x4008, 0x02}, + {0x4009, 0x0f}, + {0x4050, 0x02}, + {0x4051, 0x09}, + {0x4501, 0x00}, + {0x4505, 0x00}, + {0x4837, 0x0e}, + {0x5000, 0xff}, + {0x5001, 0x0f}, +}; + +static const struct ov13b10_reg mode_2104x1560_regs[] = { + {0x0305, 0xaf}, + {0x3501, 0x06}, + {0x3662, 0x88}, + {0x3714, 0x28}, + {0x3739, 0x10}, + {0x37c2, 0x14}, + {0x37d9, 0x06}, + {0x37e2, 0x0c}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x08}, + {0x3804, 0x10}, + {0x3805, 0x8f}, + {0x3806, 0x0c}, + {0x3807, 0x47}, + {0x3808, 0x08}, + {0x3809, 0x38}, + {0x380a, 0x06}, + {0x380b, 0x18}, + {0x380c, 0x04}, + {0x380d, 0x98}, + {0x380e, 0x06}, + {0x380f, 0x3e}, + {0x3810, 0x00}, + {0x3811, 0x07}, + {0x3812, 0x00}, + {0x3813, 0x05}, + {0x3814, 0x03}, + {0x3816, 0x03}, + {0x3820, 0x8b}, + {0x3c8c, 0x18}, + {0x4008, 0x00}, + {0x4009, 0x05}, + {0x4050, 0x00}, + {0x4051, 0x05}, + {0x4501, 0x08}, + {0x4505, 0x00}, + {0x4837, 0x0e}, + {0x5000, 0xfd}, + {0x5001, 0x0d}, +}; + +static const struct ov13b10_reg mode_2080x1170_regs[] = { + {0x0305, 0xaf}, + {0x3501, 0x06}, + {0x3662, 0x88}, + {0x3714, 0x28}, + {0x3739, 0x10}, + {0x37c2, 0x14}, + {0x37d9, 0x06}, + {0x37e2, 0x0c}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x08}, + {0x3804, 0x10}, + {0x3805, 0x8f}, + {0x3806, 0x0c}, + {0x3807, 0x47}, + {0x3808, 0x08}, + {0x3809, 0x20}, + {0x380a, 0x04}, + {0x380b, 0x92}, + {0x380c, 0x04}, + {0x380d, 0x98}, + {0x380e, 0x06}, + {0x380f, 0x3e}, + {0x3810, 0x00}, + {0x3811, 0x13}, + {0x3812, 0x00}, + {0x3813, 0xc9}, + {0x3814, 0x03}, + {0x3816, 0x03}, + {0x3820, 0x8b}, + {0x3c8c, 0x18}, + {0x4008, 0x00}, + {0x4009, 0x05}, + {0x4050, 0x00}, + {0x4051, 0x05}, + {0x4501, 0x08}, + {0x4505, 0x00}, + {0x4837, 0x0e}, + {0x5000, 0xfd}, + {0x5001, 0x0d}, +}; + +static const char * const ov13b10_test_pattern_menu[] = { + "Disabled", + "Vertical Color Bar Type 1", + "Vertical Color Bar Type 2", + "Vertical Color Bar Type 3", + "Vertical Color Bar Type 4" +}; + +/* Configurations for supported link frequencies */ +#define OV13B10_LINK_FREQ_560MHZ 560000000ULL +#define OV13B10_LINK_FREQ_INDEX_0 0 + +#define OV13B10_EXT_CLK 19200000 +#define OV13B10_DATA_LANES 4 + +/* + * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample + * data rate => double data rate; number of lanes => 4; bits per pixel => 10 + */ +static u64 link_freq_to_pixel_rate(u64 f) +{ + f *= 2 * OV13B10_DATA_LANES; + do_div(f, 10); + + return f; +} + +/* Menu items for LINK_FREQ V4L2 control */ +static const s64 link_freq_menu_items[] = { + OV13B10_LINK_FREQ_560MHZ +}; + +/* Link frequency configs */ +static const struct ov13b10_link_freq_config + link_freq_configs[] = { + { + .pixels_per_line = OV13B10_PPL_560MHZ, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mipi_data_rate_1120mbps), + .regs = mipi_data_rate_1120mbps, + } + } +}; + +/* Mode configs */ +static const struct ov13b10_mode supported_modes[] = { + { + .width = 4208, + .height = 3120, + .vts_def = OV13B10_VTS_30FPS, + .vts_min = OV13B10_VTS_30FPS, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_4208x3120_regs), + .regs = mode_4208x3120_regs, + }, + .link_freq_index = OV13B10_LINK_FREQ_INDEX_0, + }, + { + .width = 4160, + .height = 3120, + .vts_def = OV13B10_VTS_30FPS, + .vts_min = OV13B10_VTS_30FPS, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_4160x3120_regs), + .regs = mode_4160x3120_regs, + }, + .link_freq_index = OV13B10_LINK_FREQ_INDEX_0, + }, + { + .width = 4160, + .height = 2340, + .vts_def = OV13B10_VTS_30FPS, + .vts_min = OV13B10_VTS_30FPS, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_4160x2340_regs), + .regs = mode_4160x2340_regs, + }, + .link_freq_index = OV13B10_LINK_FREQ_INDEX_0, + }, + { + .width = 2104, + .height = 1560, + .vts_def = OV13B10_VTS_60FPS, + .vts_min = OV13B10_VTS_60FPS, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_2104x1560_regs), + .regs = mode_2104x1560_regs, + }, + .link_freq_index = OV13B10_LINK_FREQ_INDEX_0, + }, + { + .width = 2080, + .height = 1170, + .vts_def = OV13B10_VTS_60FPS, + .vts_min = OV13B10_VTS_60FPS, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_2080x1170_regs), + .regs = mode_2080x1170_regs, + }, + .link_freq_index = OV13B10_LINK_FREQ_INDEX_0, + } +}; + +struct ov13b10 { + struct v4l2_subdev sd; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrl_handler; + /* V4L2 Controls */ + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *exposure; + + /* Current mode */ + const struct ov13b10_mode *cur_mode; + + /* Mutex for serialized access */ + struct mutex mutex; + + /* Streaming on/off */ + bool streaming; +}; + +#define to_ov13b10(_sd) container_of(_sd, struct ov13b10, sd) + +/* Read registers up to 4 at a time */ +static int ov13b10_read_reg(struct ov13b10 *ov13b, + u16 reg, u32 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); + struct i2c_msg msgs[2]; + u8 *data_be_p; + int ret; + __be32 data_be = 0; + __be16 reg_addr_be = cpu_to_be16(reg); + + if (len > 4) + return -EINVAL; + + data_be_p = (u8 *)&data_be; + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = (u8 *)®_addr_be; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_be_p[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = be32_to_cpu(data_be); + + return 0; +} + +/* Write registers up to 4 at a time */ +static int ov13b10_write_reg(struct ov13b10 *ov13b, + u16 reg, u32 len, u32 __val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); + int buf_i, val_i; + u8 buf[6], *val_p; + __be32 val; + + if (len > 4) + return -EINVAL; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + + val = cpu_to_be32(__val); + val_p = (u8 *)&val; + buf_i = 2; + val_i = 4 - len; + + while (val_i < 4) + buf[buf_i++] = val_p[val_i++]; + + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +/* Write a list of registers */ +static int ov13b10_write_regs(struct ov13b10 *ov13b, + const struct ov13b10_reg *regs, u32 len) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); + int ret; + u32 i; + + for (i = 0; i < len; i++) { + ret = ov13b10_write_reg(ov13b, regs[i].address, 1, + regs[i].val); + if (ret) { + dev_err_ratelimited(&client->dev, + "Failed to write reg 0x%4.4x. error = %d\n", + regs[i].address, ret); + + return ret; + } + } + + return 0; +} + +static int ov13b10_write_reg_list(struct ov13b10 *ov13b, + const struct ov13b10_reg_list *r_list) +{ + return ov13b10_write_regs(ov13b, r_list->regs, r_list->num_of_regs); +} + +/* Open sub-device */ +static int ov13b10_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + const struct ov13b10_mode *default_mode = &supported_modes[0]; + struct ov13b10 *ov13b = to_ov13b10(sd); + struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd, + fh->state, + 0); + + mutex_lock(&ov13b->mutex); + + /* Initialize try_fmt */ + try_fmt->width = default_mode->width; + try_fmt->height = default_mode->height; + try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + try_fmt->field = V4L2_FIELD_NONE; + + /* No crop or compose */ + mutex_unlock(&ov13b->mutex); + + return 0; +} + +static int ov13b10_update_digital_gain(struct ov13b10 *ov13b, u32 d_gain) +{ + int ret; + u32 val; + + /* + * 0x350C[7:6], 0x350B[7:0], 0x350A[1:0] + */ + + val = (d_gain & OV13B10_DGTL_GAIN_L_MASK) << OV13B10_DGTL_GAIN_L_SHIFT; + ret = ov13b10_write_reg(ov13b, OV13B10_REG_DGTL_GAIN_L, + OV13B10_REG_VALUE_08BIT, val); + if (ret) + return ret; + + val = (d_gain >> OV13B10_DGTL_GAIN_M_SHIFT) & OV13B10_DGTL_GAIN_M_MASK; + ret = ov13b10_write_reg(ov13b, OV13B10_REG_DGTL_GAIN_M, + OV13B10_REG_VALUE_08BIT, val); + if (ret) + return ret; + + val = (d_gain >> OV13B10_DGTL_GAIN_H_SHIFT) & OV13B10_DGTL_GAIN_H_MASK; + ret = ov13b10_write_reg(ov13b, OV13B10_REG_DGTL_GAIN_H, + OV13B10_REG_VALUE_08BIT, val); + + return ret; +} + +static int ov13b10_enable_test_pattern(struct ov13b10 *ov13b, u32 pattern) +{ + int ret; + u32 val; + + ret = ov13b10_read_reg(ov13b, OV13B10_REG_TEST_PATTERN, + OV13B10_REG_VALUE_08BIT, &val); + if (ret) + return ret; + + if (pattern) { + val &= OV13B10_TEST_PATTERN_MASK; + val |= ((pattern - 1) << OV13B10_TEST_PATTERN_BAR_SHIFT) | + OV13B10_TEST_PATTERN_ENABLE; + } else { + val &= ~OV13B10_TEST_PATTERN_ENABLE; + } + + return ov13b10_write_reg(ov13b, OV13B10_REG_TEST_PATTERN, + OV13B10_REG_VALUE_08BIT, val); +} + +static int ov13b10_set_ctrl_hflip(struct ov13b10 *ov13b, u32 ctrl_val) +{ + int ret; + u32 val; + + ret = ov13b10_read_reg(ov13b, OV13B10_REG_FORMAT1, + OV13B10_REG_VALUE_08BIT, &val); + if (ret) + return ret; + + ret = ov13b10_write_reg(ov13b, OV13B10_REG_FORMAT1, + OV13B10_REG_VALUE_08BIT, + ctrl_val ? val & ~BIT(3) : val); + + if (ret) + return ret; + + ret = ov13b10_read_reg(ov13b, OV13B10_REG_H_WIN_OFFSET, + OV13B10_REG_VALUE_08BIT, &val); + if (ret) + return ret; + + /* + * Applying cropping offset to reverse the change of Bayer order + * after mirroring image + */ + return ov13b10_write_reg(ov13b, OV13B10_REG_H_WIN_OFFSET, + OV13B10_REG_VALUE_08BIT, + ctrl_val ? ++val : val); +} + +static int ov13b10_set_ctrl_vflip(struct ov13b10 *ov13b, u32 ctrl_val) +{ + int ret; + u32 val; + + ret = ov13b10_read_reg(ov13b, OV13B10_REG_FORMAT1, + OV13B10_REG_VALUE_08BIT, &val); + if (ret) + return ret; + + ret = ov13b10_write_reg(ov13b, OV13B10_REG_FORMAT1, + OV13B10_REG_VALUE_08BIT, + ctrl_val ? val | BIT(4) | BIT(5) : val); + + if (ret) + return ret; + + ret = ov13b10_read_reg(ov13b, OV13B10_REG_V_WIN_OFFSET, + OV13B10_REG_VALUE_08BIT, &val); + if (ret) + return ret; + + /* + * Applying cropping offset to reverse the change of Bayer order + * after flipping image + */ + return ov13b10_write_reg(ov13b, OV13B10_REG_V_WIN_OFFSET, + OV13B10_REG_VALUE_08BIT, + ctrl_val ? --val : val); +} + +static int ov13b10_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov13b10 *ov13b = container_of(ctrl->handler, + struct ov13b10, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); + s64 max; + int ret; + + /* Propagate change of current control to all related controls */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update max exposure while meeting expected vblanking */ + max = ov13b->cur_mode->height + ctrl->val - 8; + __v4l2_ctrl_modify_range(ov13b->exposure, + ov13b->exposure->minimum, + max, ov13b->exposure->step, max); + break; + } + + /* + * Applying V4L2 control value only happens + * when power is up for streaming + */ + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + ret = 0; + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = ov13b10_write_reg(ov13b, OV13B10_REG_ANALOG_GAIN, + OV13B10_REG_VALUE_16BIT, + ctrl->val << 1); + break; + case V4L2_CID_DIGITAL_GAIN: + ret = ov13b10_update_digital_gain(ov13b, ctrl->val); + break; + case V4L2_CID_EXPOSURE: + ret = ov13b10_write_reg(ov13b, OV13B10_REG_EXPOSURE, + OV13B10_REG_VALUE_24BIT, + ctrl->val); + break; + case V4L2_CID_VBLANK: + ret = ov13b10_write_reg(ov13b, OV13B10_REG_VTS, + OV13B10_REG_VALUE_16BIT, + ov13b->cur_mode->height + + ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov13b10_enable_test_pattern(ov13b, ctrl->val); + break; + case V4L2_CID_HFLIP: + ov13b10_set_ctrl_hflip(ov13b, ctrl->val); + break; + case V4L2_CID_VFLIP: + ov13b10_set_ctrl_vflip(ov13b, ctrl->val); + break; + default: + dev_info(&client->dev, + "ctrl(id:0x%x,val:0x%x) is not handled\n", + ctrl->id, ctrl->val); + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov13b10_ctrl_ops = { + .s_ctrl = ov13b10_set_ctrl, +}; + +static int ov13b10_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + /* Only one bayer order(GRBG) is supported */ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int ov13b10_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static void ov13b10_update_pad_format(const struct ov13b10_mode *mode, + struct v4l2_subdev_format *fmt) +{ + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; + fmt->format.field = V4L2_FIELD_NONE; +} + +static int ov13b10_do_get_pad_format(struct ov13b10 *ov13b, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *framefmt; + struct v4l2_subdev *sd = &ov13b->sd; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + fmt->format = *framefmt; + } else { + ov13b10_update_pad_format(ov13b->cur_mode, fmt); + } + + return 0; +} + +static int ov13b10_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct ov13b10 *ov13b = to_ov13b10(sd); + int ret; + + mutex_lock(&ov13b->mutex); + ret = ov13b10_do_get_pad_format(ov13b, sd_state, fmt); + mutex_unlock(&ov13b->mutex); + + return ret; +} + +static int +ov13b10_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct ov13b10 *ov13b = to_ov13b10(sd); + const struct ov13b10_mode *mode; + struct v4l2_mbus_framefmt *framefmt; + s32 vblank_def; + s32 vblank_min; + s64 h_blank; + s64 pixel_rate; + s64 link_freq; + + mutex_lock(&ov13b->mutex); + + /* Only one raw bayer(GRBG) order is supported */ + if (fmt->format.code != MEDIA_BUS_FMT_SGRBG10_1X10) + fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, + fmt->format.width, fmt->format.height); + ov13b10_update_pad_format(mode, fmt); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + *framefmt = fmt->format; + } else { + ov13b->cur_mode = mode; + __v4l2_ctrl_s_ctrl(ov13b->link_freq, mode->link_freq_index); + link_freq = link_freq_menu_items[mode->link_freq_index]; + pixel_rate = link_freq_to_pixel_rate(link_freq); + __v4l2_ctrl_s_ctrl_int64(ov13b->pixel_rate, pixel_rate); + + /* Update limits and set FPS to default */ + vblank_def = ov13b->cur_mode->vts_def - + ov13b->cur_mode->height; + vblank_min = ov13b->cur_mode->vts_min - + ov13b->cur_mode->height; + __v4l2_ctrl_modify_range(ov13b->vblank, vblank_min, + OV13B10_VTS_MAX + - ov13b->cur_mode->height, + 1, + vblank_def); + __v4l2_ctrl_s_ctrl(ov13b->vblank, vblank_def); + h_blank = + link_freq_configs[mode->link_freq_index].pixels_per_line + - ov13b->cur_mode->width; + __v4l2_ctrl_modify_range(ov13b->hblank, h_blank, + h_blank, 1, h_blank); + } + + mutex_unlock(&ov13b->mutex); + + return 0; +} + +static int ov13b10_start_streaming(struct ov13b10 *ov13b) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); + const struct ov13b10_reg_list *reg_list; + int ret, link_freq_index; + + /* Get out of from software reset */ + ret = ov13b10_write_reg(ov13b, OV13B10_REG_SOFTWARE_RST, + OV13B10_REG_VALUE_08BIT, OV13B10_SOFTWARE_RST); + if (ret) { + dev_err(&client->dev, "%s failed to set powerup registers\n", + __func__); + return ret; + } + + link_freq_index = ov13b->cur_mode->link_freq_index; + reg_list = &link_freq_configs[link_freq_index].reg_list; + ret = ov13b10_write_reg_list(ov13b, reg_list); + if (ret) { + dev_err(&client->dev, "%s failed to set plls\n", __func__); + return ret; + } + + /* Apply default values of current mode */ + reg_list = &ov13b->cur_mode->reg_list; + ret = ov13b10_write_reg_list(ov13b, reg_list); + if (ret) { + dev_err(&client->dev, "%s failed to set mode\n", __func__); + return ret; + } + + /* Apply customized values from user */ + ret = __v4l2_ctrl_handler_setup(ov13b->sd.ctrl_handler); + if (ret) + return ret; + + return ov13b10_write_reg(ov13b, OV13B10_REG_MODE_SELECT, + OV13B10_REG_VALUE_08BIT, + OV13B10_MODE_STREAMING); +} + +/* Stop streaming */ +static int ov13b10_stop_streaming(struct ov13b10 *ov13b) +{ + return ov13b10_write_reg(ov13b, OV13B10_REG_MODE_SELECT, + OV13B10_REG_VALUE_08BIT, OV13B10_MODE_STANDBY); +} + +static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov13b10 *ov13b = to_ov13b10(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + mutex_lock(&ov13b->mutex); + if (ov13b->streaming == enable) { + mutex_unlock(&ov13b->mutex); + return 0; + } + + if (enable) { + ret = pm_runtime_resume_and_get(&client->dev); + if (ret < 0) + goto err_unlock; + + /* + * Apply default & customized values + * and then start streaming. + */ + ret = ov13b10_start_streaming(ov13b); + if (ret) + goto err_rpm_put; + } else { + ov13b10_stop_streaming(ov13b); + pm_runtime_put(&client->dev); + } + + ov13b->streaming = enable; + mutex_unlock(&ov13b->mutex); + + return ret; + +err_rpm_put: + pm_runtime_put(&client->dev); +err_unlock: + mutex_unlock(&ov13b->mutex); + + return ret; +} + +static int __maybe_unused ov13b10_suspend(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov13b10 *ov13b = to_ov13b10(sd); + + if (ov13b->streaming) + ov13b10_stop_streaming(ov13b); + + return 0; +} + +static int __maybe_unused ov13b10_resume(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov13b10 *ov13b = to_ov13b10(sd); + int ret; + + if (ov13b->streaming) { + ret = ov13b10_start_streaming(ov13b); + if (ret) + goto error; + } + + return 0; + +error: + ov13b10_stop_streaming(ov13b); + ov13b->streaming = false; + return ret; +} + +/* Verify chip ID */ +static int ov13b10_identify_module(struct ov13b10 *ov13b) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); + int ret; + u32 val; + + ret = ov13b10_read_reg(ov13b, OV13B10_REG_CHIP_ID, + OV13B10_REG_VALUE_24BIT, &val); + if (ret) + return ret; + + if (val != OV13B10_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + OV13B10_CHIP_ID, val); + return -EIO; + } + + return 0; +} + +static const struct v4l2_subdev_video_ops ov13b10_video_ops = { + .s_stream = ov13b10_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ov13b10_pad_ops = { + .enum_mbus_code = ov13b10_enum_mbus_code, + .get_fmt = ov13b10_get_pad_format, + .set_fmt = ov13b10_set_pad_format, + .enum_frame_size = ov13b10_enum_frame_size, +}; + +static const struct v4l2_subdev_ops ov13b10_subdev_ops = { + .video = &ov13b10_video_ops, + .pad = &ov13b10_pad_ops, +}; + +static const struct media_entity_operations ov13b10_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_internal_ops ov13b10_internal_ops = { + .open = ov13b10_open, +}; + +/* Initialize control handlers */ +static int ov13b10_init_controls(struct ov13b10 *ov13b) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); + struct v4l2_fwnode_device_properties props; + struct v4l2_ctrl_handler *ctrl_hdlr; + s64 exposure_max; + s64 vblank_def; + s64 vblank_min; + s64 hblank; + s64 pixel_rate_min; + s64 pixel_rate_max; + const struct ov13b10_mode *mode; + u32 max; + int ret; + + ctrl_hdlr = &ov13b->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10); + if (ret) + return ret; + + mutex_init(&ov13b->mutex); + ctrl_hdlr->lock = &ov13b->mutex; + max = ARRAY_SIZE(link_freq_menu_items) - 1; + ov13b->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, + &ov13b10_ctrl_ops, + V4L2_CID_LINK_FREQ, + max, + 0, + link_freq_menu_items); + if (ov13b->link_freq) + ov13b->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]); + pixel_rate_min = 0; + /* By default, PIXEL_RATE is read only */ + ov13b->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops, + V4L2_CID_PIXEL_RATE, + pixel_rate_min, pixel_rate_max, + 1, pixel_rate_max); + + mode = ov13b->cur_mode; + vblank_def = mode->vts_def - mode->height; + vblank_min = mode->vts_min - mode->height; + ov13b->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops, + V4L2_CID_VBLANK, + vblank_min, + OV13B10_VTS_MAX - mode->height, 1, + vblank_def); + + hblank = link_freq_configs[mode->link_freq_index].pixels_per_line - + mode->width; + ov13b->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops, + V4L2_CID_HBLANK, + hblank, hblank, 1, hblank); + if (ov13b->hblank) + ov13b->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + exposure_max = mode->vts_def - 8; + ov13b->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops, + V4L2_CID_EXPOSURE, + OV13B10_EXPOSURE_MIN, + exposure_max, OV13B10_EXPOSURE_STEP, + exposure_max); + + v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + OV13B10_ANA_GAIN_MIN, OV13B10_ANA_GAIN_MAX, + OV13B10_ANA_GAIN_STEP, OV13B10_ANA_GAIN_DEFAULT); + + /* Digital gain */ + v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + OV13B10_DGTL_GAIN_MIN, OV13B10_DGTL_GAIN_MAX, + OV13B10_DGTL_GAIN_STEP, OV13B10_DGTL_GAIN_DEFAULT); + + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov13b10_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov13b10_test_pattern_menu) - 1, + 0, 0, ov13b10_test_pattern_menu); + + v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + if (ctrl_hdlr->error) { + ret = ctrl_hdlr->error; + dev_err(&client->dev, "%s control init failed (%d)\n", + __func__, ret); + goto error; + } + + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + goto error; + + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov13b10_ctrl_ops, + &props); + if (ret) + goto error; + + ov13b->sd.ctrl_handler = ctrl_hdlr; + + return 0; + +error: + v4l2_ctrl_handler_free(ctrl_hdlr); + mutex_destroy(&ov13b->mutex); + + return ret; +} + +static void ov13b10_free_controls(struct ov13b10 *ov13b) +{ + v4l2_ctrl_handler_free(ov13b->sd.ctrl_handler); + mutex_destroy(&ov13b->mutex); +} + +static int ov13b10_check_hwcfg(struct device *dev) +{ + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct fwnode_handle *ep; + struct fwnode_handle *fwnode = dev_fwnode(dev); + unsigned int i, j; + int ret; + u32 ext_clk; + + if (!fwnode) + return -ENXIO; + + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &ext_clk); + if (ret) { + dev_err(dev, "can't get clock frequency"); + return ret; + } + + if (ext_clk != OV13B10_EXT_CLK) { + dev_err(dev, "external clock %d is not supported", + ext_clk); + return -EINVAL; + } + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV13B10_DATA_LANES) { + dev_err(dev, "number of CSI2 data lanes %d is not supported", + bus_cfg.bus.mipi_csi2.num_data_lanes); + ret = -EINVAL; + goto out_err; + } + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "no link frequencies defined"); + ret = -EINVAL; + goto out_err; + } + + for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { + for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { + if (link_freq_menu_items[i] == + bus_cfg.link_frequencies[j]) + break; + } + + if (j == bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "no link frequency %lld supported", + link_freq_menu_items[i]); + ret = -EINVAL; + goto out_err; + } + } + +out_err: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int ov13b10_probe(struct i2c_client *client) +{ + struct ov13b10 *ov13b; + int ret; + + /* Check HW config */ + ret = ov13b10_check_hwcfg(&client->dev); + if (ret) { + dev_err(&client->dev, "failed to check hwcfg: %d", ret); + return ret; + } + + ov13b = devm_kzalloc(&client->dev, sizeof(*ov13b), GFP_KERNEL); + if (!ov13b) + return -ENOMEM; + + /* Initialize subdev */ + v4l2_i2c_subdev_init(&ov13b->sd, client, &ov13b10_subdev_ops); + + /* Check module identity */ + ret = ov13b10_identify_module(ov13b); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d\n", ret); + return ret; + } + + /* Set default mode to max resolution */ + ov13b->cur_mode = &supported_modes[0]; + + ret = ov13b10_init_controls(ov13b); + if (ret) + return ret; + + /* Initialize subdev */ + ov13b->sd.internal_ops = &ov13b10_internal_ops; + ov13b->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov13b->sd.entity.ops = &ov13b10_subdev_entity_ops; + ov13b->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + /* Initialize source pad */ + ov13b->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&ov13b->sd.entity, 1, &ov13b->pad); + if (ret) { + dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + goto error_handler_free; + } + + ret = v4l2_async_register_subdev_sensor(&ov13b->sd); + if (ret < 0) + goto error_media_entity; + + /* + * Device is already turned on by i2c-core with ACPI domain PM. + * Enable runtime PM and turn off the device. + */ + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + + return 0; + +error_media_entity: + media_entity_cleanup(&ov13b->sd.entity); + +error_handler_free: + ov13b10_free_controls(ov13b); + dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + + return ret; +} + +static int ov13b10_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov13b10 *ov13b = to_ov13b10(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + ov13b10_free_controls(ov13b); + + pm_runtime_disable(&client->dev); + + return 0; +} + +static const struct dev_pm_ops ov13b10_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ov13b10_suspend, ov13b10_resume) +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id ov13b10_acpi_ids[] = { + {"OVTIDB10"}, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(acpi, ov13b10_acpi_ids); +#endif + +static struct i2c_driver ov13b10_i2c_driver = { + .driver = { + .name = "ov13b10", + .pm = &ov13b10_pm_ops, + .acpi_match_table = ACPI_PTR(ov13b10_acpi_ids), + }, + .probe_new = ov13b10_probe, + .remove = ov13b10_remove, +}; + +module_i2c_driver(ov13b10_i2c_driver); + +MODULE_AUTHOR("Kao, Arec "); +MODULE_DESCRIPTION("Omnivision ov13b10 sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From f1363166f91efb99f815ac9833056c4a7e8ee2b2 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Wang Date: Mon, 5 Jul 2021 10:17:24 +0200 Subject: media: ov8856: Set default mbus format but allow caller to alter Setting the value of V_WIN_OFF (0x3818) from 0x02 to 0x01 to use GRBG format still results in wrong color output if data is tuned in BGGR mode before. Set default mbus format for the supported modes, but allow the caller of set(get)_fmt to change the bayer format between BGGR and GRBG. Set the default mbus format for 3264x2448 (and 1632x1224) to BGGR as the data sheet states the value of this reg should be 0x02 by default. If new modes are added in the future, they can add the mipi_data_mbus_{format} settings into bayer_offset_configs to adjust their offset regs. Fixes: 2984b0ddd557 ("media: ov8856: Configure sensor for GRBG Bayer for all modes") Signed-off-by: Hsin-Yi Wang Reviewed-by: Robert Foss Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov8856.c | 83 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 11 deletions(-) diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index aa74744b91c7..c6c6050cda1a 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -107,6 +107,11 @@ static const char * const ov8856_supply_names[] = { "dvdd", /* Digital core power */ }; +enum { + OV8856_MEDIA_BUS_FMT_SBGGR10_1X10, + OV8856_MEDIA_BUS_FMT_SGRBG10_1X10, +}; + struct ov8856_reg { u16 address; u8 val; @@ -145,6 +150,9 @@ struct ov8856_mode { /* Number of data lanes */ u8 data_lanes; + + /* Default MEDIA_BUS_FMT for this mode */ + u32 default_mbus_index; }; struct ov8856_mipi_data_rates { @@ -1055,7 +1063,7 @@ static const struct ov8856_reg lane_4_mode_3264x2448[] = { {0x3810, 0x00}, {0x3811, 0x04}, {0x3812, 0x00}, - {0x3813, 0x01}, + {0x3813, 0x02}, {0x3814, 0x01}, {0x3815, 0x01}, {0x3816, 0x00}, @@ -1259,7 +1267,7 @@ static const struct ov8856_reg lane_4_mode_1632x1224[] = { {0x3810, 0x00}, {0x3811, 0x02}, {0x3812, 0x00}, - {0x3813, 0x01}, + {0x3813, 0x02}, {0x3814, 0x03}, {0x3815, 0x01}, {0x3816, 0x00}, @@ -1372,6 +1380,19 @@ static const struct ov8856_reg lane_4_mode_1632x1224[] = { {0x5e10, 0xfc} }; +static const struct ov8856_reg mipi_data_mbus_sbggr10_1x10[] = { + {0x3813, 0x02}, +}; + +static const struct ov8856_reg mipi_data_mbus_sgrbg10_1x10[] = { + {0x3813, 0x01}, +}; + +static const u32 ov8856_mbus_codes[] = { + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10 +}; + static const char * const ov8856_test_pattern_menu[] = { "Disabled", "Standard Color Bar", @@ -1380,6 +1401,17 @@ static const char * const ov8856_test_pattern_menu[] = { "Bottom-Top Darker Color Bar" }; +static const struct ov8856_reg_list bayer_offset_configs[] = { + [OV8856_MEDIA_BUS_FMT_SBGGR10_1X10] = { + .num_of_regs = ARRAY_SIZE(mipi_data_mbus_sbggr10_1x10), + .regs = mipi_data_mbus_sbggr10_1x10, + }, + [OV8856_MEDIA_BUS_FMT_SGRBG10_1X10] = { + .num_of_regs = ARRAY_SIZE(mipi_data_mbus_sgrbg10_1x10), + .regs = mipi_data_mbus_sgrbg10_1x10, + } +}; + struct ov8856 { struct v4l2_subdev sd; struct media_pad pad; @@ -1399,6 +1431,9 @@ struct ov8856 { /* Current mode */ const struct ov8856_mode *cur_mode; + /* Application specified mbus format */ + u32 cur_mbus_index; + /* To serialize asynchronus callbacks */ struct mutex mutex; @@ -1450,6 +1485,7 @@ static const struct ov8856_lane_cfg lane_cfg_2 = { }, .link_freq_index = 0, .data_lanes = 2, + .default_mbus_index = OV8856_MEDIA_BUS_FMT_SGRBG10_1X10, }, { .width = 1640, @@ -1464,6 +1500,7 @@ static const struct ov8856_lane_cfg lane_cfg_2 = { }, .link_freq_index = 1, .data_lanes = 2, + .default_mbus_index = OV8856_MEDIA_BUS_FMT_SGRBG10_1X10, }} }; @@ -1499,6 +1536,7 @@ static const struct ov8856_lane_cfg lane_cfg_4 = { }, .link_freq_index = 0, .data_lanes = 4, + .default_mbus_index = OV8856_MEDIA_BUS_FMT_SGRBG10_1X10, }, { .width = 1640, @@ -1513,6 +1551,7 @@ static const struct ov8856_lane_cfg lane_cfg_4 = { }, .link_freq_index = 1, .data_lanes = 4, + .default_mbus_index = OV8856_MEDIA_BUS_FMT_SGRBG10_1X10, }, { .width = 3264, @@ -1527,6 +1566,7 @@ static const struct ov8856_lane_cfg lane_cfg_4 = { }, .link_freq_index = 0, .data_lanes = 4, + .default_mbus_index = OV8856_MEDIA_BUS_FMT_SBGGR10_1X10, }, { .width = 1632, @@ -1541,6 +1581,7 @@ static const struct ov8856_lane_cfg lane_cfg_4 = { }, .link_freq_index = 1, .data_lanes = 4, + .default_mbus_index = OV8856_MEDIA_BUS_FMT_SBGGR10_1X10, }} }; @@ -1904,12 +1945,21 @@ static int ov8856_init_controls(struct ov8856 *ov8856) return 0; } -static void ov8856_update_pad_format(const struct ov8856_mode *mode, +static void ov8856_update_pad_format(struct ov8856 *ov8856, + const struct ov8856_mode *mode, struct v4l2_mbus_framefmt *fmt) { + int index; + fmt->width = mode->width; fmt->height = mode->height; - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + for (index = 0; index < ARRAY_SIZE(ov8856_mbus_codes); ++index) + if (ov8856_mbus_codes[index] == fmt->code) + break; + if (index == ARRAY_SIZE(ov8856_mbus_codes)) + index = mode->default_mbus_index; + fmt->code = ov8856_mbus_codes[index]; + ov8856->cur_mbus_index = index; fmt->field = V4L2_FIELD_NONE; } @@ -1935,6 +1985,13 @@ static int ov8856_start_streaming(struct ov8856 *ov8856) return ret; } + reg_list = &bayer_offset_configs[ov8856->cur_mbus_index]; + ret = ov8856_write_reg_list(ov8856, reg_list); + if (ret) { + dev_err(&client->dev, "failed to set mbus format"); + return ret; + } + ret = __v4l2_ctrl_handler_setup(ov8856->sd.ctrl_handler); if (ret) return ret; @@ -2096,7 +2153,7 @@ static int ov8856_set_format(struct v4l2_subdev *sd, fmt->format.height); mutex_lock(&ov8856->mutex); - ov8856_update_pad_format(mode, &fmt->format); + ov8856_update_pad_format(ov8856, mode, &fmt->format); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format; } else { @@ -2140,7 +2197,7 @@ static int ov8856_get_format(struct v4l2_subdev *sd, sd_state, fmt->pad); else - ov8856_update_pad_format(ov8856->cur_mode, &fmt->format); + ov8856_update_pad_format(ov8856, ov8856->cur_mode, &fmt->format); mutex_unlock(&ov8856->mutex); @@ -2151,11 +2208,10 @@ static int ov8856_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - /* Only one bayer order GRBG is supported */ - if (code->index > 0) + if (code->index >= ARRAY_SIZE(ov8856_mbus_codes)) return -EINVAL; - code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + code->code = ov8856_mbus_codes[code->index]; return 0; } @@ -2165,11 +2221,15 @@ static int ov8856_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_frame_size_enum *fse) { struct ov8856 *ov8856 = to_ov8856(sd); + int index; if (fse->index >= ov8856->modes_size) return -EINVAL; - if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + for (index = 0; index < ARRAY_SIZE(ov8856_mbus_codes); ++index) + if (fse->code == ov8856_mbus_codes[index]) + break; + if (index == ARRAY_SIZE(ov8856_mbus_codes)) return -EINVAL; fse->min_width = ov8856->priv_lane->supported_modes[fse->index].width; @@ -2185,7 +2245,7 @@ static int ov8856_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) struct ov8856 *ov8856 = to_ov8856(sd); mutex_lock(&ov8856->mutex); - ov8856_update_pad_format(&ov8856->priv_lane->supported_modes[0], + ov8856_update_pad_format(ov8856, &ov8856->priv_lane->supported_modes[0], v4l2_subdev_get_try_format(sd, fh->state, 0)); mutex_unlock(&ov8856->mutex); @@ -2426,6 +2486,7 @@ static int ov8856_probe(struct i2c_client *client) mutex_init(&ov8856->mutex); ov8856->cur_mode = &ov8856->priv_lane->supported_modes[0]; + ov8856->cur_mbus_index = ov8856->cur_mode->default_mbus_index; ret = ov8856_init_controls(ov8856); if (ret) { dev_err(&client->dev, "failed to init controls: %d", ret); -- cgit v1.2.3 From a9c80593ff80ddb7c6496624e5384e1ea3460a72 Mon Sep 17 00:00:00 2001 From: David Plowman Date: Mon, 16 Aug 2021 13:39:08 +0200 Subject: media: v4l2-ctrls: Add V4L2_CID_NOTIFY_GAINS control We add a new control V4L2_CID_NOTIFY_GAINS which allows the sensor to be notified what gains will be applied to the different colour channels by subsequent processing (such as by an ISP), even though the sensor will not apply any of these gains itself. For Bayer sensors this will be an array control taking 4 values which are the 4 gains arranged in the fixed order B, Gb, Gr and R, irrespective of the exact Bayer order of the sensor itself. The use of an array makes it straightforward to extend this control to non-Bayer sensors (for example, sensors with an RGBW pattern) in future. The units are in all cases linear with the default value indicating a gain of exactly 1.0. For example, if the default value were reported as 128 then the value 192 would represent a gain of exactly 1.5. Signed-off-by: David Plowman Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls-defs.c | 1 + include/uapi/linux/v4l2-controls.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c index eae300c58274..ebe82b6ba6e6 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c @@ -1108,6 +1108,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_TEST_PATTERN_GREENR: return "Green (Red) Pixel Value"; case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value"; case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value"; + case V4L2_CID_NOTIFY_GAINS: return "Notify Gains"; /* Image processing controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 5532b5f68493..133e20444939 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -1118,6 +1118,7 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_TEST_PATTERN_BLUE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 6) #define V4L2_CID_TEST_PATTERN_GREENB (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7) #define V4L2_CID_UNIT_CELL_SIZE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 8) +#define V4L2_CID_NOTIFY_GAINS (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 9) /* Image processing controls */ -- cgit v1.2.3 From 311a839a1ad255ebcb7291fb4e0d2ec2f32312a7 Mon Sep 17 00:00:00 2001 From: David Plowman Date: Mon, 16 Aug 2021 13:39:09 +0200 Subject: media: v4l2-ctrls: Document V4L2_CID_NOTIFY_GAINS control Add documentation for the V4L2_CID_NOTIFY_GAINS control. This control is required by sensors that need to know what colour gains will be applied to pixels by downstream processing (such as by an ISP), though the sensor does not apply these gains itself. Signed-off-by: David Plowman Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../media/v4l/ext-ctrls-image-source.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst index de43f5c8486d..71f23f131f97 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst @@ -72,3 +72,23 @@ Image Source Control IDs * - __u32 - ``height`` - Height of the area. + +``V4L2_CID_NOTIFY_GAINS (integer array)`` + The sensor is notified what gains will be applied to the different + colour channels by subsequent processing (such as by an ISP). The + sensor is merely informed of these values in case it performs + processing that requires them, but it does not apply them itself to + the output pixels. + + Currently it is defined only for Bayer sensors, and is an array + control taking 4 gain values, being the gains for each of the + Bayer channels. The gains are always in the order B, Gb, Gr and R, + irrespective of the exact Bayer order of the sensor itself. + + The use of an array allows this control to be extended to sensors + with, for example, non-Bayer CFAs (colour filter arrays). + + The units for the gain values are linear, with the default value + representing a gain of exactly 1.0. For example, if this default value + is reported as being (say) 128, then a value of 192 would represent + a gain of exactly 1.5. -- cgit v1.2.3 From 3a7438c8ef86c9687d3978f56b4813ebd119c7b5 Mon Sep 17 00:00:00 2001 From: Bingbu Cao Date: Fri, 16 Jul 2021 10:06:28 +0200 Subject: media: staging: document that Imgu not output auto-exposure statistics Currently, Imgu can not support output the auto-exposure statistics into ae_raw_buffer in 3A stats buffer, this patch document it. Signed-off-by: Bingbu Cao Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/ipu3/include/uapi/intel-ipu3.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h b/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h index fa3d6ee5adf2..585f55981c86 100644 --- a/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h +++ b/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h @@ -234,7 +234,9 @@ struct ipu3_uapi_ae_ccm { * struct ipu3_uapi_ae_config - AE config * * @grid_cfg: config for auto exposure statistics grid. See struct - * &ipu3_uapi_ae_grid_config + * &ipu3_uapi_ae_grid_config, as Imgu did not support output + * auto exposure statistics, so user can ignore this configuration + * and use the RGB table in auto-whitebalance statistics instead. * @weights: &IPU3_UAPI_AE_WEIGHTS is based on 32x24 blocks in the grid. * Each grid cell has a corresponding value in weights LUT called * grid value, global histogram is updated based on grid value and @@ -534,6 +536,9 @@ struct ipu3_uapi_ff_status { * * @awb_raw_buffer: auto white balance meta data &ipu3_uapi_awb_raw_buffer * @ae_raw_buffer: auto exposure raw data &ipu3_uapi_ae_raw_buffer_aligned + * current Imgu does not output the auto exposure statistics + * to ae_raw_buffer, the user such as 3A algorithm can use the + * RGB table in &ipu3_uapi_awb_raw_buffer to do auto-exposure. * @af_raw_buffer: &ipu3_uapi_af_raw_buffer for auto focus meta data * @awb_fr_raw_buffer: value as specified by &ipu3_uapi_awb_fr_raw_buffer * @stats_4a_config: 4a statistics config as defined by &ipu3_uapi_4a_config. -- cgit v1.2.3 From ae0334e0cb737e1ddfcae9acdcf4d2adf005f329 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 27 Jul 2021 11:28:53 +0200 Subject: media: uvcvideo: Remove unused including Remove including that don't need it. V1->V2: Split the patch in two. Signed-off-by: Cai Huoqing Acked-by: Randy Dunlap Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_driver.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 9a791d8ef200..b1b055784f8d 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From 861f92cb9160b14beef0ada047384c2340701ee2 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:03 +0200 Subject: media: v4l2-ioctl: Fix check_ext_ctrls Drivers that do not use the ctrl-framework use this function instead. Fix the following issues: - Do not check for multiple classes when getting the DEF_VAL. - Return -EINVAL for request_api calls - Default value cannot be changed, return EINVAL as soon as possible. - Return the right error_idx [If an error is found when validating the list of controls passed with VIDIOC_G_EXT_CTRLS, then error_idx shall be set to ctrls->count to indicate to userspace that no actual hardware was touched. It would have been much nicer of course if error_idx could point to the control index that failed the validation, but sadly that's not how the API was designed.] Fixes v4l2-compliance: Control ioctls (Input 0): warn: v4l2-test-controls.cpp(834): error_idx should be equal to count warn: v4l2-test-controls.cpp(855): error_idx should be equal to count fail: v4l2-test-controls.cpp(813): doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL Buffer ioctls (Input 0): fail: v4l2-test-buffers.cpp(1994): ret != EINVAL && ret != EBADR && ret != ENOTTY test Requests: FAIL Cc: stable@vger.kernel.org Fixes: 6fa6f831f095 ("media: v4l2-ctrls: add core request support") Suggested-by: Hans Verkuil Reviewed-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 60 +++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index d4f97ab1b237..dc817f8ba9d7 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -869,7 +869,7 @@ static void v4l_print_default(const void *arg, bool write_only) pr_cont("driver-specific ioctl\n"); } -static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) +static bool check_ext_ctrls(struct v4l2_ext_controls *c, unsigned long ioctl) { __u32 i; @@ -878,23 +878,41 @@ static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) for (i = 0; i < c->count; i++) c->controls[i].reserved2[0] = 0; - /* V4L2_CID_PRIVATE_BASE cannot be used as control class - when using extended controls. - Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL - is it allowed for backwards compatibility. - */ - if (!allow_priv && c->which == V4L2_CID_PRIVATE_BASE) - return 0; - if (!c->which) - return 1; + switch (c->which) { + case V4L2_CID_PRIVATE_BASE: + /* + * V4L2_CID_PRIVATE_BASE cannot be used as control class + * when using extended controls. + * Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL + * is it allowed for backwards compatibility. + */ + if (ioctl == VIDIOC_G_CTRL || ioctl == VIDIOC_S_CTRL) + return false; + break; + case V4L2_CTRL_WHICH_DEF_VAL: + /* Default value cannot be changed */ + if (ioctl == VIDIOC_S_EXT_CTRLS || + ioctl == VIDIOC_TRY_EXT_CTRLS) { + c->error_idx = c->count; + return false; + } + return true; + case V4L2_CTRL_WHICH_CUR_VAL: + return true; + case V4L2_CTRL_WHICH_REQUEST_VAL: + c->error_idx = c->count; + return false; + } + /* Check that all controls are from the same control class. */ for (i = 0; i < c->count; i++) { if (V4L2_CTRL_ID2WHICH(c->controls[i].id) != c->which) { - c->error_idx = i; - return 0; + c->error_idx = ioctl == VIDIOC_TRY_EXT_CTRLS ? i : + c->count; + return false; } } - return 1; + return true; } static int check_fmt(struct file *file, enum v4l2_buf_type type) @@ -2189,7 +2207,7 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, ctrls.controls = &ctrl; ctrl.id = p->id; ctrl.value = p->value; - if (check_ext_ctrls(&ctrls, 1)) { + if (check_ext_ctrls(&ctrls, VIDIOC_G_CTRL)) { int ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls); if (ret == 0) @@ -2223,7 +2241,7 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, ctrls.controls = &ctrl; ctrl.id = p->id; ctrl.value = p->value; - if (check_ext_ctrls(&ctrls, 1)) + if (check_ext_ctrls(&ctrls, VIDIOC_S_CTRL)) return ops->vidioc_s_ext_ctrls(file, fh, &ctrls); return -EINVAL; } @@ -2245,8 +2263,8 @@ static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops, vfd, vfd->v4l2_dev->mdev, p); if (ops->vidioc_g_ext_ctrls == NULL) return -ENOTTY; - return check_ext_ctrls(p, 0) ? ops->vidioc_g_ext_ctrls(file, fh, p) : - -EINVAL; + return check_ext_ctrls(p, VIDIOC_G_EXT_CTRLS) ? + ops->vidioc_g_ext_ctrls(file, fh, p) : -EINVAL; } static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops, @@ -2266,8 +2284,8 @@ static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops, vfd, vfd->v4l2_dev->mdev, p); if (ops->vidioc_s_ext_ctrls == NULL) return -ENOTTY; - return check_ext_ctrls(p, 0) ? ops->vidioc_s_ext_ctrls(file, fh, p) : - -EINVAL; + return check_ext_ctrls(p, VIDIOC_S_EXT_CTRLS) ? + ops->vidioc_s_ext_ctrls(file, fh, p) : -EINVAL; } static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, @@ -2287,8 +2305,8 @@ static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, vfd, vfd->v4l2_dev->mdev, p); if (ops->vidioc_try_ext_ctrls == NULL) return -ENOTTY; - return check_ext_ctrls(p, 0) ? ops->vidioc_try_ext_ctrls(file, fh, p) : - -EINVAL; + return check_ext_ctrls(p, VIDIOC_TRY_EXT_CTRLS) ? + ops->vidioc_try_ext_ctrls(file, fh, p) : -EINVAL; } /* -- cgit v1.2.3 From e4ba563d4d4f14c3cda140ae47e0a4e2dcdd639c Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:04 +0200 Subject: media: pvrusb2: Do not check for V4L2_CTRL_WHICH_DEF_VAL The framework already checks for us if V4L2_CTRL_WHICH_DEF_VAL is written. Cc: Mike Isely Signed-off-by: Ricardo Ribalda Reviewed-by: Hans Verkuil Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 9657c1883311..c04ab7258d64 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -640,10 +640,6 @@ static int pvr2_s_ext_ctrls(struct file *file, void *priv, unsigned int idx; int ret; - /* Default value cannot be changed */ - if (ctls->which == V4L2_CTRL_WHICH_DEF_VAL) - return -EINVAL; - ret = 0; for (idx = 0; idx < ctls->count; idx++) { ctrl = ctls->controls + idx; -- cgit v1.2.3 From a2f8a484fbc96b8209a760cb3f2c95ca49c2cdb1 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:05 +0200 Subject: media: uvcvideo: Do not check for V4L2_CTRL_WHICH_DEF_VAL The framework already checks for us if V4L2_CTRL_WHICH_DEF_VAL is written. Reviewed-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_v4l2.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 6acb8013de08..102fa39a1615 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -1101,10 +1101,6 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, unsigned int i; int ret; - /* Default value cannot be changed */ - if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) - return -EINVAL; - ret = uvc_ctrl_begin(chain); if (ret < 0) return ret; -- cgit v1.2.3 From c87ed93574e3cd8346c05bd934c617596c12541b Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:06 +0200 Subject: media: v4l2-ioctl: S_CTRL output the right value If the driver does not implement s_ctrl, but it does implement s_ext_ctrls, we convert the call. When that happens we have also to convert back the response from s_ext_ctrls. Fixes v4l2_compliance: Control ioctls (Input 0): fail: v4l2-test-controls.cpp(411): returned control value out of range fail: v4l2-test-controls.cpp(507): invalid control 00980900 test VIDIOC_G/S_CTRL: FAIL Fixes: 35ea11ff8471 ("V4L/DVB (8430): videodev: move some functions from v4l2-dev.h to v4l2-common.h or v4l2-ioctl.h") Reviewed-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index dc817f8ba9d7..bc83d23ce25d 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2226,6 +2226,7 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; struct v4l2_ext_controls ctrls; struct v4l2_ext_control ctrl; + int ret; if (vfh && vfh->ctrl_handler) return v4l2_s_ctrl(vfh, vfh->ctrl_handler, p); @@ -2241,9 +2242,11 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, ctrls.controls = &ctrl; ctrl.id = p->id; ctrl.value = p->value; - if (check_ext_ctrls(&ctrls, VIDIOC_S_CTRL)) - return ops->vidioc_s_ext_ctrls(file, fh, &ctrls); - return -EINVAL; + if (!check_ext_ctrls(&ctrls, VIDIOC_S_CTRL)) + return -EINVAL; + ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls); + p->value = ctrl.value; + return ret; } static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops, -- cgit v1.2.3 From 0c6bcbdfefa83b8a1e9659b3c127758dce0fe7ac Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:07 +0200 Subject: media: uvcvideo: Remove s_ctrl and g_ctrl If we do not implement these callbacks the framework will call the ext_ctrl callbaks instead, which are a superset of this functions. Suggested-by: Hans Verkuil Reviewed-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_v4l2.c | 56 ---------------------------------------- 1 file changed, 56 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 102fa39a1615..ff97510b781b 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -995,60 +995,6 @@ static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh, return 0; } -static int uvc_ioctl_g_ctrl(struct file *file, void *fh, - struct v4l2_control *ctrl) -{ - struct uvc_fh *handle = fh; - struct uvc_video_chain *chain = handle->chain; - struct v4l2_ext_control xctrl; - int ret; - - memset(&xctrl, 0, sizeof(xctrl)); - xctrl.id = ctrl->id; - - ret = uvc_ctrl_begin(chain); - if (ret < 0) - return ret; - - ret = uvc_ctrl_get(chain, &xctrl); - uvc_ctrl_rollback(handle); - if (ret < 0) - return ret; - - ctrl->value = xctrl.value; - return 0; -} - -static int uvc_ioctl_s_ctrl(struct file *file, void *fh, - struct v4l2_control *ctrl) -{ - struct uvc_fh *handle = fh; - struct uvc_video_chain *chain = handle->chain; - struct v4l2_ext_control xctrl; - int ret; - - memset(&xctrl, 0, sizeof(xctrl)); - xctrl.id = ctrl->id; - xctrl.value = ctrl->value; - - ret = uvc_ctrl_begin(chain); - if (ret < 0) - return ret; - - ret = uvc_ctrl_set(handle, &xctrl); - if (ret < 0) { - uvc_ctrl_rollback(handle); - return ret; - } - - ret = uvc_ctrl_commit(handle, &xctrl, 1); - if (ret < 0) - return ret; - - ctrl->value = xctrl.value; - return 0; -} - static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *ctrls) { @@ -1534,8 +1480,6 @@ const struct v4l2_ioctl_ops uvc_ioctl_ops = { .vidioc_s_input = uvc_ioctl_s_input, .vidioc_queryctrl = uvc_ioctl_queryctrl, .vidioc_query_ext_ctrl = uvc_ioctl_query_ext_ctrl, - .vidioc_g_ctrl = uvc_ioctl_g_ctrl, - .vidioc_s_ctrl = uvc_ioctl_s_ctrl, .vidioc_g_ext_ctrls = uvc_ioctl_g_ext_ctrls, .vidioc_s_ext_ctrls = uvc_ioctl_s_ext_ctrls, .vidioc_try_ext_ctrls = uvc_ioctl_try_ext_ctrls, -- cgit v1.2.3 From 97a2777a96070afb7da5d587834086c0b586c8cc Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:08 +0200 Subject: media: uvcvideo: Set capability in s_param Fixes v4l2-compliance: Format ioctls (Input 0): warn: v4l2-test-formats.cpp(1339): S_PARM is supported but doesn't report V4L2_CAP_TIMEPERFRAME fail: v4l2-test-formats.cpp(1241): node->has_frmintervals && !cap->capability Reviewed-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_v4l2.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index ff97510b781b..60e3ac679ecb 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -472,10 +472,13 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, uvc_simplify_fraction(&timeperframe.numerator, &timeperframe.denominator, 8, 333); - if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { parm->parm.capture.timeperframe = timeperframe; - else + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + } else { parm->parm.output.timeperframe = timeperframe; + parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + } return 0; } -- cgit v1.2.3 From ffccdde5f0e17d2f0d788a9d831a027187890eaa Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:09 +0200 Subject: media: uvcvideo: Return -EIO for control errors The device is doing something unexpected with the control. Either because the protocol is not properly implemented or there has been a HW error. Fixes v4l2-compliance: Control ioctls (Input 0): fail: v4l2-test-controls.cpp(448): s_ctrl returned an error (22) test VIDIOC_G/S_CTRL: FAIL fail: v4l2-test-controls.cpp(698): s_ext_ctrls returned an error (22) test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL Reviewed-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_video.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index e16464606b14..9f37eaf28ce7 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -115,6 +115,11 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, case 5: /* Invalid unit */ case 6: /* Invalid control */ case 7: /* Invalid Request */ + /* + * The firmware has not properly implemented + * the control or there has been a HW error. + */ + return -EIO; case 8: /* Invalid value within range */ return -EINVAL; default: /* reserved or unknown */ -- cgit v1.2.3 From 866c6bdd5663d4df7cf384b381b6ef8ba9ffd0e4 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:10 +0200 Subject: media: uvcvideo: refactor __uvc_ctrl_add_mapping Pass the chain instead of the device. We want to keep the reference to the chain that controls belong to. We need to delay the initialization of the controls after the chains have been initialized. This is a cleanup needed for the next patches. Reviewed-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 41 ++++++++++++++++++++++++++------------ drivers/media/usb/uvc/uvc_driver.c | 8 ++++---- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index b3dde98499f4..b75da65115ef 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -2057,7 +2057,7 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl, /* * Add a control mapping to a given control. */ -static int __uvc_ctrl_add_mapping(struct uvc_device *dev, +static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, struct uvc_control *ctrl, const struct uvc_control_mapping *mapping) { struct uvc_control_mapping *map; @@ -2086,7 +2086,7 @@ static int __uvc_ctrl_add_mapping(struct uvc_device *dev, map->set = uvc_set_le_value; list_add_tail(&map->list, &ctrl->info.mappings); - uvc_dbg(dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n", + uvc_dbg(chain->dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n", map->name, ctrl->info.entity, ctrl->info.selector); return 0; @@ -2168,7 +2168,7 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, goto done; } - ret = __uvc_ctrl_add_mapping(dev, ctrl, mapping); + ret = __uvc_ctrl_add_mapping(chain, ctrl, mapping); if (ret < 0) atomic_dec(&dev->nmappings); @@ -2244,7 +2244,8 @@ static void uvc_ctrl_prune_entity(struct uvc_device *dev, * Add control information and hardcoded stock control mappings to the given * device. */ -static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl) +static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, + struct uvc_control *ctrl) { const struct uvc_control_info *info = uvc_ctrls; const struct uvc_control_info *iend = info + ARRAY_SIZE(uvc_ctrls); @@ -2263,14 +2264,14 @@ static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl) for (; info < iend; ++info) { if (uvc_entity_match_guid(ctrl->entity, info->entity) && ctrl->index == info->index) { - uvc_ctrl_add_info(dev, ctrl, info); + uvc_ctrl_add_info(chain->dev, ctrl, info); /* * Retrieve control flags from the device. Ignore errors * and work with default flag values from the uvc_ctrl * array when the device doesn't properly implement * GET_INFO on standard controls. */ - uvc_ctrl_get_flags(dev, ctrl, &ctrl->info); + uvc_ctrl_get_flags(chain->dev, ctrl, &ctrl->info); break; } } @@ -2281,22 +2282,20 @@ static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl) for (; mapping < mend; ++mapping) { if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && ctrl->info.selector == mapping->selector) - __uvc_ctrl_add_mapping(dev, ctrl, mapping); + __uvc_ctrl_add_mapping(chain, ctrl, mapping); } } /* * Initialize device controls. */ -int uvc_ctrl_init_device(struct uvc_device *dev) +static int uvc_ctrl_init_chain(struct uvc_video_chain *chain) { struct uvc_entity *entity; unsigned int i; - INIT_WORK(&dev->async_ctrl.work, uvc_ctrl_status_event_work); - /* Walk the entities list and instantiate controls */ - list_for_each_entry(entity, &dev->entities, list) { + list_for_each_entry(entity, &chain->entities, chain) { struct uvc_control *ctrl; unsigned int bControlSize = 0, ncontrols; u8 *bmControls = NULL; @@ -2316,7 +2315,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev) } /* Remove bogus/blacklisted controls */ - uvc_ctrl_prune_entity(dev, entity); + uvc_ctrl_prune_entity(chain->dev, entity); /* Count supported controls and allocate the controls array */ ncontrols = memweight(bmControls, bControlSize); @@ -2338,7 +2337,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev) ctrl->entity = entity; ctrl->index = i; - uvc_ctrl_init_ctrl(dev, ctrl); + uvc_ctrl_init_ctrl(chain, ctrl); ctrl++; } } @@ -2346,6 +2345,22 @@ int uvc_ctrl_init_device(struct uvc_device *dev) return 0; } +int uvc_ctrl_init_device(struct uvc_device *dev) +{ + struct uvc_video_chain *chain; + int ret; + + INIT_WORK(&dev->async_ctrl.work, uvc_ctrl_status_event_work); + + list_for_each_entry(chain, &dev->chains, list) { + ret = uvc_ctrl_init_chain(chain); + if (ret) + return ret; + } + + return 0; +} + /* * Cleanup device controls. */ diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index b1b055784f8d..058d28a0344b 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -2454,14 +2454,14 @@ static int uvc_probe(struct usb_interface *intf, if (v4l2_device_register(&intf->dev, &dev->vdev) < 0) goto error; - /* Initialize controls. */ - if (uvc_ctrl_init_device(dev) < 0) - goto error; - /* Scan the device for video chains. */ if (uvc_scan_device(dev) < 0) goto error; + /* Initialize controls. */ + if (uvc_ctrl_init_device(dev) < 0) + goto error; + /* Register video device nodes. */ if (uvc_register_chains(dev) < 0) goto error; -- cgit v1.2.3 From 9b31ea808a4468d5d606d1f82c58b7e7bfb99f66 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:11 +0200 Subject: media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS Create all the class controls for the device defined controls. Fixes v4l2-compliance: Control ioctls (Input 0): fail: v4l2-test-controls.cpp(216): missing control class for class 00980000 fail: v4l2-test-controls.cpp(216): missing control tclass for class 009a0000 test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: FAIL Reviewed-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 90 ++++++++++++++++++++++++++++++++++++++++ drivers/media/usb/uvc/uvcvideo.h | 1 + 2 files changed, 91 insertions(+) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index b75da65115ef..7c1d71782281 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -357,6 +357,11 @@ static const struct uvc_control_info uvc_ctrls[] = { }, }; +static const u32 uvc_control_classes[] = { + V4L2_CID_CAMERA_CLASS, + V4L2_CID_USER_CLASS, +}; + static const struct uvc_menu_info power_line_frequency_controls[] = { { 0, "Disabled" }, { 1, "50 Hz" }, @@ -1024,6 +1029,49 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain, return 0; } +static int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, + u32 found_id) +{ + bool find_next = req_id & V4L2_CTRL_FLAG_NEXT_CTRL; + unsigned int i; + + req_id &= V4L2_CTRL_ID_MASK; + + for (i = 0; i < ARRAY_SIZE(uvc_control_classes); i++) { + if (!(chain->ctrl_class_bitmap & BIT(i))) + continue; + if (!find_next) { + if (uvc_control_classes[i] == req_id) + return i; + continue; + } + if (uvc_control_classes[i] > req_id && + uvc_control_classes[i] < found_id) + return i; + } + + return -ENODEV; +} + +static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, + u32 found_id, struct v4l2_queryctrl *v4l2_ctrl) +{ + int idx; + + idx = __uvc_query_v4l2_class(chain, req_id, found_id); + if (idx < 0) + return -ENODEV; + + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); + v4l2_ctrl->id = uvc_control_classes[idx]; + strscpy(v4l2_ctrl->name, v4l2_ctrl_get_name(v4l2_ctrl->id), + sizeof(v4l2_ctrl->name)); + v4l2_ctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS; + v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY + | V4L2_CTRL_FLAG_READ_ONLY; + return 0; +} + static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, struct uvc_control *ctrl, struct uvc_control_mapping *mapping, @@ -1127,12 +1175,31 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, if (ret < 0) return -ERESTARTSYS; + /* Check if the ctrl is a know class */ + if (!(v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) { + ret = uvc_query_v4l2_class(chain, v4l2_ctrl->id, 0, v4l2_ctrl); + if (!ret) + goto done; + } + ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping); if (ctrl == NULL) { ret = -EINVAL; goto done; } + /* + * If we're enumerating control with V4L2_CTRL_FLAG_NEXT_CTRL, check if + * a class should be inserted between the previous control and the one + * we have just found. + */ + if (v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL) { + ret = uvc_query_v4l2_class(chain, v4l2_ctrl->id, mapping->id, + v4l2_ctrl); + if (!ret) + goto done; + } + ret = __uvc_query_v4l2_ctrl(chain, ctrl, mapping, v4l2_ctrl); done: mutex_unlock(&chain->ctrl_mutex); @@ -1426,6 +1493,11 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) if (ret < 0) return -ERESTARTSYS; + if (__uvc_query_v4l2_class(handle->chain, sev->id, 0) >= 0) { + ret = 0; + goto done; + } + ctrl = uvc_find_control(handle->chain, sev->id, &mapping); if (ctrl == NULL) { ret = -EINVAL; @@ -1459,7 +1531,10 @@ static void uvc_ctrl_del_event(struct v4l2_subscribed_event *sev) struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh); mutex_lock(&handle->chain->ctrl_mutex); + if (__uvc_query_v4l2_class(handle->chain, sev->id, 0) >= 0) + goto done; list_del(&sev->node); +done: mutex_unlock(&handle->chain->ctrl_mutex); } @@ -1577,6 +1652,9 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, struct uvc_control *ctrl; struct uvc_control_mapping *mapping; + if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0) + return -EACCES; + ctrl = uvc_find_control(chain, xctrl->id, &mapping); if (ctrl == NULL) return -EINVAL; @@ -1596,6 +1674,9 @@ int uvc_ctrl_set(struct uvc_fh *handle, s32 max; int ret; + if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0) + return -EACCES; + ctrl = uvc_find_control(chain, xctrl->id, &mapping); if (ctrl == NULL) return -EINVAL; @@ -2062,6 +2143,7 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, { struct uvc_control_mapping *map; unsigned int size; + unsigned int i; /* Most mappings come from static kernel data and need to be duplicated. * Mappings that come from userspace will be unnecessarily duplicated, @@ -2085,6 +2167,14 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, if (map->set == NULL) map->set = uvc_set_le_value; + for (i = 0; i < ARRAY_SIZE(uvc_control_classes); i++) { + if (V4L2_CTRL_ID2WHICH(uvc_control_classes[i]) == + V4L2_CTRL_ID2WHICH(map->id)) { + chain->ctrl_class_bitmap |= BIT(i); + break; + } + } + list_add_tail(&map->list, &ctrl->info.mappings); uvc_dbg(chain->dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n", map->name, ctrl->info.entity, ctrl->info.selector); diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index cce5e38133cd..5eb7e87f8430 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -476,6 +476,7 @@ struct uvc_video_chain { struct v4l2_prio_state prio; /* V4L2 priority state */ u32 caps; /* V4L2 chain-wide caps */ + u8 ctrl_class_bitmap; /* Bitmap of valid classes */ }; struct uvc_stats_frame { -- cgit v1.2.3 From 457e7911dfb81a31834c25ab7f13a4475350459b Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:12 +0200 Subject: media: uvcvideo: Use dev->name for querycap() Use the device name for the card name instead of vdev->name. That way all the devices have a different name instead of the common vdev->name. Signed-off-by: Hans Verkuil Suggested-by: Laurent Pinchart Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_metadata.c | 2 +- drivers/media/usb/uvc/uvc_v4l2.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c index b6279ad7ac84..82de7781f5b6 100644 --- a/drivers/media/usb/uvc/uvc_metadata.c +++ b/drivers/media/usb/uvc/uvc_metadata.c @@ -30,7 +30,7 @@ static int uvc_meta_v4l2_querycap(struct file *file, void *fh, struct uvc_video_chain *chain = stream->chain; strscpy(cap->driver, "uvcvideo", sizeof(cap->driver)); - strscpy(cap->card, vfh->vdev->name, sizeof(cap->card)); + strscpy(cap->card, stream->dev->name, sizeof(cap->card)); usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info)); cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING | chain->caps; diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 60e3ac679ecb..15974356b357 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -617,13 +617,12 @@ static int uvc_v4l2_release(struct file *file) static int uvc_ioctl_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); struct uvc_fh *handle = file->private_data; struct uvc_video_chain *chain = handle->chain; struct uvc_streaming *stream = handle->stream; strscpy(cap->driver, "uvcvideo", sizeof(cap->driver)); - strscpy(cap->card, vdev->name, sizeof(cap->card)); + strscpy(cap->card, handle->stream->dev->name, sizeof(cap->card)); usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info)); cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING | chain->caps; -- cgit v1.2.3 From e3f60e7e1a2b451f538f9926763432249bcf39c4 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:13 +0200 Subject: media: uvcvideo: Set unique vdev name based in type All the entities must have a unique name. We can have a descriptive and unique name by appending the function and the entity->id. This is even resilent to multi chain devices. Fixes v4l2-compliance: Media Controller ioctls: fail: v4l2-test-media.cpp(205): v2_entity_names_set.find(key) != v2_entity_names_set.end() test MEDIA_IOC_G_TOPOLOGY: FAIL fail: v4l2-test-media.cpp(394): num_data_links != num_links test MEDIA_IOC_ENUM_ENTITIES/LINKS: FAIL Signed-off-by: Ricardo Ribalda Reviewed-by: Hans Verkuil Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_driver.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 058d28a0344b..7c007426e082 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -2193,6 +2193,7 @@ int uvc_register_video_device(struct uvc_device *dev, const struct v4l2_file_operations *fops, const struct v4l2_ioctl_ops *ioctl_ops) { + const char *name; int ret; /* Initialize the video buffers queue. */ @@ -2221,16 +2222,20 @@ int uvc_register_video_device(struct uvc_device *dev, case V4L2_BUF_TYPE_VIDEO_CAPTURE: default: vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + name = "Video Capture"; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + name = "Video Output"; break; case V4L2_BUF_TYPE_META_CAPTURE: vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING; + name = "Metadata"; break; } - strscpy(vdev->name, dev->name, sizeof(vdev->name)); + snprintf(vdev->name, sizeof(vdev->name), "%s %u", name, + stream->header.bTerminalLink); /* * Set the driver data before calling video_register_device, otherwise -- cgit v1.2.3 From 8865c537037bb30b9e84c91e3386cc926f024f78 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:14 +0200 Subject: media: uvcvideo: Increase the size of UVC_METADATA_BUF_SIZE Hans has discovered that in his test device, for the H264 format bytesused goes up to about 570, for YUYV it will actually go up to a bit over 5000 bytes, and for MJPG up to about 2706 bytes. We should also, according to V4L2_META_FMT_UVC docs, drop headers when the buffer is full. Credit-to: Hans Verkuil Reviewed-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvcvideo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 5eb7e87f8430..37a092d717cf 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -524,7 +524,7 @@ struct uvc_stats_stream { unsigned int max_sof; /* Maximum STC.SOF value */ }; -#define UVC_METADATA_BUF_SIZE 1024 +#define UVC_METADATA_BUF_SIZE 10240 /** * struct uvc_copy_op: Context structure to schedule asynchronous memcpy -- cgit v1.2.3 From 70fa906d6fceb07a49198d2f31cadecc76787419 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:15 +0200 Subject: media: uvcvideo: Use control names from framework The framework already contains a map of IDs to names, lets use it when possible. Reviewed-by: Hans Verkuil Suggested-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 57 ++++++++++++++++------------------------ drivers/media/usb/uvc/uvc_v4l2.c | 8 +++++- drivers/media/usb/uvc/uvcvideo.h | 2 +- 3 files changed, 30 insertions(+), 37 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 7c1d71782281..2cc2ff0d0cae 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -432,7 +432,6 @@ static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping, static const struct uvc_control_mapping uvc_ctrl_mappings[] = { { .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_BRIGHTNESS_CONTROL, .size = 16, @@ -442,7 +441,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_CONTRAST, - .name = "Contrast", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_CONTRAST_CONTROL, .size = 16, @@ -452,7 +450,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_HUE, - .name = "Hue", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_HUE_CONTROL, .size = 16, @@ -464,7 +461,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_SATURATION, - .name = "Saturation", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_SATURATION_CONTROL, .size = 16, @@ -474,7 +470,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_SHARPNESS, - .name = "Sharpness", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_SHARPNESS_CONTROL, .size = 16, @@ -484,7 +479,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_GAMMA, - .name = "Gamma", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_GAMMA_CONTROL, .size = 16, @@ -494,7 +488,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_BACKLIGHT_COMPENSATION, - .name = "Backlight Compensation", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL, .size = 16, @@ -504,7 +497,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_GAIN, - .name = "Gain", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_GAIN_CONTROL, .size = 16, @@ -514,7 +506,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_POWER_LINE_FREQUENCY, - .name = "Power Line Frequency", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, .size = 2, @@ -526,7 +517,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_HUE_AUTO, - .name = "Hue, Auto", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_HUE_AUTO_CONTROL, .size = 1, @@ -537,7 +527,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_EXPOSURE_AUTO, - .name = "Exposure, Auto", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_AE_MODE_CONTROL, .size = 4, @@ -550,7 +539,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_EXPOSURE_AUTO_PRIORITY, - .name = "Exposure, Auto Priority", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_AE_PRIORITY_CONTROL, .size = 1, @@ -560,7 +548,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .name = "Exposure (Absolute)", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL, .size = 32, @@ -572,7 +559,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_AUTO_WHITE_BALANCE, - .name = "White Balance Temperature, Auto", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, .size = 1, @@ -583,7 +569,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, - .name = "White Balance Temperature", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL, .size = 16, @@ -595,7 +580,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_AUTO_WHITE_BALANCE, - .name = "White Balance Component, Auto", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL, .size = 1, @@ -607,7 +591,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_BLUE_BALANCE, - .name = "White Balance Blue Component", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL, .size = 16, @@ -619,7 +602,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_RED_BALANCE, - .name = "White Balance Red Component", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL, .size = 16, @@ -631,7 +613,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_FOCUS_ABSOLUTE, - .name = "Focus (absolute)", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL, .size = 16, @@ -643,7 +624,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_FOCUS_AUTO, - .name = "Focus, Auto", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_FOCUS_AUTO_CONTROL, .size = 1, @@ -654,7 +634,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_IRIS_ABSOLUTE, - .name = "Iris, Absolute", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_IRIS_ABSOLUTE_CONTROL, .size = 16, @@ -664,7 +643,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_IRIS_RELATIVE, - .name = "Iris, Relative", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_IRIS_RELATIVE_CONTROL, .size = 8, @@ -674,7 +652,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_ZOOM_ABSOLUTE, - .name = "Zoom, Absolute", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL, .size = 16, @@ -684,7 +661,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_ZOOM_CONTINUOUS, - .name = "Zoom, Continuous", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_ZOOM_RELATIVE_CONTROL, .size = 0, @@ -696,7 +672,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_PAN_ABSOLUTE, - .name = "Pan (Absolute)", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, .size = 32, @@ -706,7 +681,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_TILT_ABSOLUTE, - .name = "Tilt (Absolute)", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, .size = 32, @@ -716,7 +690,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_PAN_SPEED, - .name = "Pan (Speed)", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_PANTILT_RELATIVE_CONTROL, .size = 16, @@ -728,7 +701,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_TILT_SPEED, - .name = "Tilt (Speed)", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_PANTILT_RELATIVE_CONTROL, .size = 16, @@ -740,7 +712,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_PRIVACY, - .name = "Privacy", .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_PRIVACY_CONTROL, .size = 1, @@ -750,7 +721,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, { .id = V4L2_CID_PRIVACY, - .name = "Privacy", .entity = UVC_GUID_EXT_GPIO_CONTROLLER, .selector = UVC_CT_PRIVACY_CONTROL, .size = 1, @@ -1072,6 +1042,20 @@ static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, return 0; } +static const char *uvc_map_get_name(const struct uvc_control_mapping *map) +{ + const char *name; + + if (map->name) + return map->name; + + name = v4l2_ctrl_get_name(map->id); + if (name) + return name; + + return "Unknown Control"; +} + static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, struct uvc_control *ctrl, struct uvc_control_mapping *mapping, @@ -1085,7 +1069,8 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); v4l2_ctrl->id = mapping->id; v4l2_ctrl->type = mapping->v4l2_type; - strscpy(v4l2_ctrl->name, mapping->name, sizeof(v4l2_ctrl->name)); + strscpy(v4l2_ctrl->name, uvc_map_get_name(mapping), + sizeof(v4l2_ctrl->name)); v4l2_ctrl->flags = 0; if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) @@ -2177,7 +2162,8 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, list_add_tail(&map->list, &ctrl->info.mappings); uvc_dbg(chain->dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n", - map->name, ctrl->info.entity, ctrl->info.selector); + uvc_map_get_name(map), ctrl->info.entity, + ctrl->info.selector); return 0; } @@ -2195,7 +2181,7 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, if (mapping->id & ~V4L2_CTRL_ID_MASK) { uvc_dbg(dev, CONTROL, "Can't add mapping '%s', control id 0x%08x is invalid\n", - mapping->name, mapping->id); + uvc_map_get_name(mapping), mapping->id); return -EINVAL; } @@ -2242,7 +2228,7 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, if (mapping->id == map->id) { uvc_dbg(dev, CONTROL, "Can't add mapping '%s', control id 0x%08x already exists\n", - mapping->name, mapping->id); + uvc_map_get_name(mapping), mapping->id); ret = -EEXIST; goto done; } @@ -2253,7 +2239,7 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, atomic_dec(&dev->nmappings); uvc_dbg(dev, CONTROL, "Can't add mapping '%s', maximum mappings count (%u) exceeded\n", - mapping->name, UVC_MAX_CONTROL_MAPPINGS); + uvc_map_get_name(mapping), UVC_MAX_CONTROL_MAPPINGS); ret = -ENOMEM; goto done; } @@ -2462,6 +2448,7 @@ static void uvc_ctrl_cleanup_mappings(struct uvc_device *dev, list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) { list_del(&mapping->list); kfree(mapping->menu_info); + kfree(mapping->name); kfree(mapping); } } diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 15974356b357..c6ec7dc920e0 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -40,7 +40,13 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, return -ENOMEM; map->id = xmap->id; - memcpy(map->name, xmap->name, sizeof(map->name)); + /* Non standard control id. */ + if (v4l2_ctrl_get_name(map->id) == NULL) { + map->name = kmemdup(xmap->name, sizeof(xmap->name), + GFP_KERNEL); + if (!map->name) + return -ENOMEM; + } memcpy(map->entity, xmap->entity, sizeof(map->entity)); map->selector = xmap->selector; map->size = xmap->size; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 37a092d717cf..b044d9455b2c 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -241,7 +241,7 @@ struct uvc_control_mapping { struct list_head ev_subs; u32 id; - u8 name[32]; + char *name; u8 entity[16]; u8 selector; -- cgit v1.2.3 From ee929d5a10ca433a1c21b9aaeb70a67c5507c101 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:16 +0200 Subject: media: uvcvideo: Check controls flags before accessing them We can figure out if reading/writing a set of controls can fail without accessing them by checking their flags. This way we can honor the API closer: If an error is found when validating the list of controls passed with VIDIOC_G_EXT_CTRLS, then error_idx shall be set to ctrls->count to indicate to userspace that no actual hardware was touched. Fixes v4l2-compliance: Control ioctls (Input 0): warn: v4l2-test-controls.cpp(765): g_ext_ctrls(0) invalid error_idx 0 fail: v4l2-test-controls.cpp(645): invalid error index write only control test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL Reviewed-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 22 ++++++++++++++++++++++ drivers/media/usb/uvc/uvc_v4l2.c | 39 ++++++++++++++++++++++++++++++++++----- drivers/media/usb/uvc/uvcvideo.h | 2 ++ 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 2cc2ff0d0cae..18c315b52ef5 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1042,6 +1042,28 @@ static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, return 0; } +int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id, + bool read) +{ + struct uvc_control_mapping *mapping; + struct uvc_control *ctrl; + + if (__uvc_query_v4l2_class(chain, v4l2_id, 0) >= 0) + return -EACCES; + + ctrl = uvc_find_control(chain, v4l2_id, &mapping); + if (!ctrl) + return -EINVAL; + + if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) && read) + return -EACCES; + + if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) && !read) + return -EACCES; + + return 0; +} + static const char *uvc_map_get_name(const struct uvc_control_mapping *map) { const char *name; diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index c6ec7dc920e0..c10a638fff22 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -1003,6 +1003,26 @@ static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh, return 0; } +static int uvc_ctrl_check_access(struct uvc_video_chain *chain, + struct v4l2_ext_controls *ctrls, + unsigned long ioctl) +{ + struct v4l2_ext_control *ctrl = ctrls->controls; + unsigned int i; + int ret = 0; + + for (i = 0; i < ctrls->count; ++ctrl, ++i) { + ret = uvc_ctrl_is_accessible(chain, ctrl->id, + ioctl == VIDIOC_G_EXT_CTRLS); + if (ret) + break; + } + + ctrls->error_idx = ioctl == VIDIOC_TRY_EXT_CTRLS ? i : ctrls->count; + + return ret; +} + static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *ctrls) { @@ -1012,6 +1032,10 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, unsigned int i; int ret; + ret = uvc_ctrl_check_access(chain, ctrls, VIDIOC_G_EXT_CTRLS); + if (ret < 0) + return ret; + if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) { for (i = 0; i < ctrls->count; ++ctrl, ++i) { struct v4l2_queryctrl qc = { .id = ctrl->id }; @@ -1048,13 +1072,17 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, struct v4l2_ext_controls *ctrls, - bool commit) + unsigned long ioctl) { struct v4l2_ext_control *ctrl = ctrls->controls; struct uvc_video_chain *chain = handle->chain; unsigned int i; int ret; + ret = uvc_ctrl_check_access(chain, ctrls, ioctl); + if (ret < 0) + return ret; + ret = uvc_ctrl_begin(chain); if (ret < 0) return ret; @@ -1063,14 +1091,15 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, ret = uvc_ctrl_set(handle, ctrl); if (ret < 0) { uvc_ctrl_rollback(handle); - ctrls->error_idx = commit ? ctrls->count : i; + ctrls->error_idx = ioctl == VIDIOC_S_EXT_CTRLS ? + ctrls->count : i; return ret; } } ctrls->error_idx = 0; - if (commit) + if (ioctl == VIDIOC_S_EXT_CTRLS) return uvc_ctrl_commit(handle, ctrls->controls, ctrls->count); else return uvc_ctrl_rollback(handle); @@ -1081,7 +1110,7 @@ static int uvc_ioctl_s_ext_ctrls(struct file *file, void *fh, { struct uvc_fh *handle = fh; - return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, true); + return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_S_EXT_CTRLS); } static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh, @@ -1089,7 +1118,7 @@ static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh, { struct uvc_fh *handle = fh; - return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, false); + return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_TRY_EXT_CTRLS); } static int uvc_ioctl_querymenu(struct file *file, void *fh, diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index b044d9455b2c..4aa78591d9b0 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -901,6 +901,8 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle) int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl); int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl); +int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id, + bool read); int uvc_xu_ctrl_query(struct uvc_video_chain *chain, struct uvc_xu_control_query *xqry); -- cgit v1.2.3 From 6350d6a4ed487d16a3a021f76a7edcb9cb60fdbf Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:17 +0200 Subject: media: uvcvideo: Set error_idx during ctrl_commit errors If we have an error setting a control, return the affected control in the error_idx field. Reviewed-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 42 +++++++++++++++++++++++++++++++++------- drivers/media/usb/uvc/uvc_v4l2.c | 2 +- drivers/media/usb/uvc/uvcvideo.h | 10 ++++------ 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 18c315b52ef5..dd6ebcc7344a 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1582,7 +1582,7 @@ int uvc_ctrl_begin(struct uvc_video_chain *chain) } static int uvc_ctrl_commit_entity(struct uvc_device *dev, - struct uvc_entity *entity, int rollback) + struct uvc_entity *entity, int rollback, struct uvc_control **err_ctrl) { struct uvc_control *ctrl; unsigned int i; @@ -1624,31 +1624,59 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, ctrl->dirty = 0; - if (ret < 0) + if (ret < 0) { + if (err_ctrl) + *err_ctrl = ctrl; return ret; + } } return 0; } +static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity, + struct v4l2_ext_controls *ctrls, + struct uvc_control *uvc_control) +{ + struct uvc_control_mapping *mapping; + struct uvc_control *ctrl_found; + unsigned int i; + + if (!entity) + return ctrls->count; + + for (i = 0; i < ctrls->count; i++) { + __uvc_find_control(entity, ctrls->controls[i].id, &mapping, + &ctrl_found, 0); + if (uvc_control == ctrl_found) + return i; + } + + return ctrls->count; +} + int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, - const struct v4l2_ext_control *xctrls, - unsigned int xctrls_count) + struct v4l2_ext_controls *ctrls) { struct uvc_video_chain *chain = handle->chain; + struct uvc_control *err_ctrl; struct uvc_entity *entity; int ret = 0; /* Find the control. */ list_for_each_entry(entity, &chain->entities, chain) { - ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback); + ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback, + &err_ctrl); if (ret < 0) goto done; } if (!rollback) - uvc_ctrl_send_events(handle, xctrls, xctrls_count); + uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count); done: + if (ret < 0 && ctrls) + ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls, + err_ctrl); mutex_unlock(&chain->ctrl_mutex); return ret; } @@ -2106,7 +2134,7 @@ int uvc_ctrl_restore_values(struct uvc_device *dev) ctrl->dirty = 1; } - ret = uvc_ctrl_commit_entity(dev, entity, 0); + ret = uvc_ctrl_commit_entity(dev, entity, 0, NULL); if (ret < 0) return ret; } diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index c10a638fff22..f4e4aff8ddf7 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -1100,7 +1100,7 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, ctrls->error_idx = 0; if (ioctl == VIDIOC_S_EXT_CTRLS) - return uvc_ctrl_commit(handle, ctrls->controls, ctrls->count); + return uvc_ctrl_commit(handle, ctrls); else return uvc_ctrl_rollback(handle); } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 4aa78591d9b0..2e5366143b81 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -886,17 +886,15 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain, int uvc_ctrl_begin(struct uvc_video_chain *chain); int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, - const struct v4l2_ext_control *xctrls, - unsigned int xctrls_count); + struct v4l2_ext_controls *ctrls); static inline int uvc_ctrl_commit(struct uvc_fh *handle, - const struct v4l2_ext_control *xctrls, - unsigned int xctrls_count) + struct v4l2_ext_controls *ctrls) { - return __uvc_ctrl_commit(handle, 0, xctrls, xctrls_count); + return __uvc_ctrl_commit(handle, 0, ctrls); } static inline int uvc_ctrl_rollback(struct uvc_fh *handle) { - return __uvc_ctrl_commit(handle, 1, NULL, 0); + return __uvc_ctrl_commit(handle, 1, NULL); } int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl); -- cgit v1.2.3 From 8c42694150c27ea68a8d46996d943918c769d1d0 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 18 Jun 2021 14:29:18 +0200 Subject: media: docs: Document the behaviour of uvcvideo driver The uvc driver relies on the camera firmware to keep the control states and therefore is not capable of changing an inactive control. Allow returning -EACCES in those cases. Signed-off-by: Ricardo Ribalda Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/vidioc-g-ctrl.rst | 3 +++ Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ctrl.rst index 80e8c63d530f..fd09677f64f8 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ctrl.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ctrl.rst @@ -95,3 +95,6 @@ EBUSY EACCES Attempt to set a read-only control or to get a write-only control. + + Or if there is an attempt to set an inactive control and the driver is + not capable of caching the new value until the control is active again. diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst index 2d6bc8d94380..fdde0ae6d521 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -470,3 +470,6 @@ EACCES Or the ``which`` field was set to ``V4L2_CTRL_WHICH_REQUEST_VAL`` but the device does not support requests. + + Or if there is an attempt to set an inactive control and the driver is + not capable of caching the new value until the control is active again. -- cgit v1.2.3 From 15486e0934eb47ff4230f0f8908c2ec0f945a910 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 18 Jun 2021 14:29:21 +0200 Subject: media: uvcvideo: Don't spam the log in uvc_ctrl_restore_values() Don't report the restored controls with dev_info, use dev_dbg instead. This prevents a lot of noise in the kernel log. Reviewed-by: Ricardo Ribalda Signed-off-by: Hans Verkuil Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index dd6ebcc7344a..30bfe9069a1f 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -2127,10 +2127,10 @@ int uvc_ctrl_restore_values(struct uvc_device *dev) if (!ctrl->initialized || !ctrl->modified || (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0) continue; - dev_info(&dev->udev->dev, - "restoring control %pUl/%u/%u\n", - ctrl->info.entity, ctrl->info.index, - ctrl->info.selector); + dev_dbg(&dev->udev->dev, + "restoring control %pUl/%u/%u\n", + ctrl->info.entity, ctrl->info.index, + ctrl->info.selector); ctrl->dirty = 1; } -- cgit v1.2.3 From e4aa275f73103b619159d6ea7036985010dbf73a Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:07:24 +0200 Subject: media: am437x: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/am437x/am437x-vpfe.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 48bb0c93729c..2dfae9bc0bba 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -2393,7 +2393,6 @@ static int vpfe_probe(struct platform_device *pdev) struct vpfe_config *vpfe_cfg; struct vpfe_device *vpfe; struct vpfe_ccdc *ccdc; - struct resource *res; int ret; vpfe = devm_kzalloc(&pdev->dev, sizeof(*vpfe), GFP_KERNEL); @@ -2411,8 +2410,7 @@ static int vpfe_probe(struct platform_device *pdev) vpfe->cfg = vpfe_cfg; ccdc = &vpfe->ccdc; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ccdc->ccdc_cfg.base_addr = devm_ioremap_resource(&pdev->dev, res); + ccdc->ccdc_cfg.base_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ccdc->ccdc_cfg.base_addr)) { ret = PTR_ERR(ccdc->ccdc_cfg.base_addr); goto probe_out_cleanup; -- cgit v1.2.3 From f5aae241f9892bf48b44763a2dcf015ea8ea0baa Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:14:20 +0200 Subject: media: cadence: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Acked-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/cadence/cdns-csi2rx.c | 4 +--- drivers/media/platform/cadence/cdns-csi2tx.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 7b44ab2b8c9a..cc3ebb0d96f6 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -279,13 +279,11 @@ static const struct v4l2_async_notifier_operations csi2rx_notifier_ops = { static int csi2rx_get_resources(struct csi2rx_priv *csi2rx, struct platform_device *pdev) { - struct resource *res; unsigned char i; u32 dev_cfg; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - csi2rx->base = devm_ioremap_resource(&pdev->dev, res); + csi2rx->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(csi2rx->base)) return PTR_ERR(csi2rx->base); diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c index 5a67fba73ddd..8f8c36056354 100644 --- a/drivers/media/platform/cadence/cdns-csi2tx.c +++ b/drivers/media/platform/cadence/cdns-csi2tx.c @@ -433,13 +433,11 @@ static const struct v4l2_subdev_ops csi2tx_subdev_ops = { static int csi2tx_get_resources(struct csi2tx_priv *csi2tx, struct platform_device *pdev) { - struct resource *res; unsigned int i; u32 dev_cfg; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - csi2tx->base = devm_ioremap_resource(&pdev->dev, res); + csi2tx->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(csi2tx->base)) return PTR_ERR(csi2tx->base); -- cgit v1.2.3 From 97ef3b7f4fdf8ad6818aa2c8201c3b72cc635e16 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:45:35 +0200 Subject: media: cec: ao-cec: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Neil Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/platform/meson/ao-cec-g12a.c | 4 +--- drivers/media/cec/platform/meson/ao-cec.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/cec/platform/meson/ao-cec-g12a.c b/drivers/media/cec/platform/meson/ao-cec-g12a.c index 891533060d49..68fe6d6a8178 100644 --- a/drivers/media/cec/platform/meson/ao-cec-g12a.c +++ b/drivers/media/cec/platform/meson/ao-cec-g12a.c @@ -633,7 +633,6 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev) { struct meson_ao_cec_g12a_device *ao_cec; struct device *hdmi_dev; - struct resource *res; void __iomem *base; int ret, irq; @@ -664,8 +663,7 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev) ao_cec->adap->owner = THIS_MODULE; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) { ret = PTR_ERR(base); goto out_probe_adapter; diff --git a/drivers/media/cec/platform/meson/ao-cec.c b/drivers/media/cec/platform/meson/ao-cec.c index 09aff82c3773..6b440f0635d9 100644 --- a/drivers/media/cec/platform/meson/ao-cec.c +++ b/drivers/media/cec/platform/meson/ao-cec.c @@ -602,7 +602,6 @@ static int meson_ao_cec_probe(struct platform_device *pdev) { struct meson_ao_cec_device *ao_cec; struct device *hdmi_dev; - struct resource *res; int ret, irq; hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); @@ -626,8 +625,7 @@ static int meson_ao_cec_probe(struct platform_device *pdev) ao_cec->adap->owner = THIS_MODULE; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ao_cec->base = devm_ioremap_resource(&pdev->dev, res); + ao_cec->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ao_cec->base)) { ret = PTR_ERR(ao_cec->base); goto out_probe_adapter; -- cgit v1.2.3 From 399e0f9a0d6a77b45d72d3faaac6219a683132b2 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:48:42 +0200 Subject: media: cec: s5p_cec: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/platform/s5p/s5p_cec.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/cec/platform/s5p/s5p_cec.c b/drivers/media/cec/platform/s5p/s5p_cec.c index 028a09a7531e..ce9a9d922f11 100644 --- a/drivers/media/cec/platform/s5p/s5p_cec.c +++ b/drivers/media/cec/platform/s5p/s5p_cec.c @@ -178,7 +178,6 @@ static int s5p_cec_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device *hdmi_dev; - struct resource *res; struct s5p_cec_dev *cec; bool needs_hpd = of_property_read_bool(pdev->dev.of_node, "needs-hpd"); int ret; @@ -212,8 +211,7 @@ static int s5p_cec_probe(struct platform_device *pdev) if (IS_ERR(cec->pmu)) return -EPROBE_DEFER; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - cec->reg = devm_ioremap_resource(dev, res); + cec->reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(cec->reg)) return PTR_ERR(cec->reg); -- cgit v1.2.3 From 9caf7a0a095104496f7cddd9f67009c4c510cf74 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:51:08 +0200 Subject: media: coda: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/imx-vdoa.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/coda/imx-vdoa.c b/drivers/media/platform/coda/imx-vdoa.c index 8bc0d8371819..6996d4571e36 100644 --- a/drivers/media/platform/coda/imx-vdoa.c +++ b/drivers/media/platform/coda/imx-vdoa.c @@ -301,8 +301,7 @@ static int vdoa_probe(struct platform_device *pdev) return PTR_ERR(vdoa->vdoa_clk); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - vdoa->regs = devm_ioremap_resource(vdoa->dev, res); + vdoa->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(vdoa->regs)) return PTR_ERR(vdoa->regs); -- cgit v1.2.3 From bcbeade15a3078c7f4bcf2715b3e91264aa467b5 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:51:16 +0200 Subject: media: davinci: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe_venc.c | 9 ++------- drivers/media/platform/davinci/vpif.c | 5 ++--- drivers/media/platform/davinci/vpss.c | 10 ++-------- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c index bde241c26d79..4c8e31de12b1 100644 --- a/drivers/media/platform/davinci/vpbe_venc.c +++ b/drivers/media/platform/davinci/vpbe_venc.c @@ -621,7 +621,6 @@ static int venc_probe(struct platform_device *pdev) { const struct platform_device_id *pdev_id; struct venc_state *venc; - struct resource *res; if (!pdev->dev.platform_data) { dev_err(&pdev->dev, "No platform data for VENC sub device"); @@ -640,16 +639,12 @@ static int venc_probe(struct platform_device *pdev) venc->pdev = &pdev->dev; venc->pdata = pdev->dev.platform_data; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - venc->venc_base = devm_ioremap_resource(&pdev->dev, res); + venc->venc_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(venc->venc_base)) return PTR_ERR(venc->venc_base); if (venc->venc_type != VPBE_VERSION_1) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - - venc->vdaccfg_reg = devm_ioremap_resource(&pdev->dev, res); + venc->vdaccfg_reg = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(venc->vdaccfg_reg)) return PTR_ERR(venc->vdaccfg_reg); } diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c index f1ce10828b8e..5a89d885d0e3 100644 --- a/drivers/media/platform/davinci/vpif.c +++ b/drivers/media/platform/davinci/vpif.c @@ -425,12 +425,11 @@ EXPORT_SYMBOL(vpif_channel_getfid); static int vpif_probe(struct platform_device *pdev) { - static struct resource *res, *res_irq; + static struct resource *res_irq; struct platform_device *pdev_capture, *pdev_display; struct device_node *endpoint = NULL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - vpif_base = devm_ioremap_resource(&pdev->dev, res); + vpif_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(vpif_base)) return PTR_ERR(vpif_base); diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c index 7000f0bf0b35..d15b991ab17c 100644 --- a/drivers/media/platform/davinci/vpss.c +++ b/drivers/media/platform/davinci/vpss.c @@ -392,7 +392,6 @@ EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size); static int vpss_probe(struct platform_device *pdev) { - struct resource *res; char *platform_name; if (!pdev->dev.platform_data) { @@ -413,17 +412,12 @@ static int vpss_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "%s vpss probed\n", platform_name); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - oper_cfg.vpss_regs_base0 = devm_ioremap_resource(&pdev->dev, res); + oper_cfg.vpss_regs_base0 = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(oper_cfg.vpss_regs_base0)) return PTR_ERR(oper_cfg.vpss_regs_base0); if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - - oper_cfg.vpss_regs_base1 = devm_ioremap_resource(&pdev->dev, - res); + oper_cfg.vpss_regs_base1 = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(oper_cfg.vpss_regs_base1)) return PTR_ERR(oper_cfg.vpss_regs_base1); } -- cgit v1.2.3 From d9bd707c9de3d4b8cb8689205b1df5f0b64d2643 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:51:23 +0200 Subject: media: exynos-gsc: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index f49f3322f835..cfd6ae70b8d8 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1137,8 +1137,7 @@ static int gsc_probe(struct platform_device *pdev) spin_lock_init(&gsc->slock); mutex_init(&gsc->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - gsc->regs = devm_ioremap_resource(dev, res); + gsc->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(gsc->regs)) return PTR_ERR(gsc->regs); -- cgit v1.2.3 From f5202ccb67418dd230b7ccfe68ba4edef6ac31cd Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:51:31 +0200 Subject: media: exynos4-is: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/mipi-csis.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 32b23329b033..27a214936cb0 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -766,7 +766,6 @@ static int s5pcsis_probe(struct platform_device *pdev) const struct of_device_id *of_id; const struct csis_drvdata *drv_data; struct device *dev = &pdev->dev; - struct resource *mem_res; struct csis_state *state; int ret = -ENOMEM; int i; @@ -800,8 +799,7 @@ static int s5pcsis_probe(struct platform_device *pdev) if (IS_ERR(state->phy)) return PTR_ERR(state->phy); - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - state->regs = devm_ioremap_resource(dev, mem_res); + state->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(state->regs)) return PTR_ERR(state->regs); -- cgit v1.2.3 From a498a4e7af5022cd60511b2f732196a67a96b5e0 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:51:38 +0200 Subject: media: imx-jpeg: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/imx-jpeg/mxc-jpeg.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/imx-jpeg/mxc-jpeg.c index 755138063ee6..b3cc5199ef28 100644 --- a/drivers/media/platform/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.c @@ -1959,7 +1959,6 @@ static int mxc_jpeg_probe(struct platform_device *pdev) { struct mxc_jpeg_dev *jpeg; struct device *dev = &pdev->dev; - struct resource *res; int dec_irq; int ret; int mode; @@ -1982,8 +1981,7 @@ static int mxc_jpeg_probe(struct platform_device *pdev) goto err_irq; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - jpeg->base_reg = devm_ioremap_resource(&pdev->dev, res); + jpeg->base_reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(jpeg->base_reg)) return PTR_ERR(jpeg->base_reg); -- cgit v1.2.3 From 5f328fb58c373317d782084a0cb1e17f7374589b Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:51:46 +0200 Subject: media: imx-pxp: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/imx-pxp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/imx-pxp.c b/drivers/media/platform/imx-pxp.c index 4321edc0c23d..723b096fedd1 100644 --- a/drivers/media/platform/imx-pxp.c +++ b/drivers/media/platform/imx-pxp.c @@ -1636,7 +1636,6 @@ static int pxp_soft_reset(struct pxp_dev *dev) static int pxp_probe(struct platform_device *pdev) { struct pxp_dev *dev; - struct resource *res; struct video_device *vfd; int irq; int ret; @@ -1652,8 +1651,7 @@ static int pxp_probe(struct platform_device *pdev) return ret; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->mmio = devm_ioremap_resource(&pdev->dev, res); + dev->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->mmio)) return PTR_ERR(dev->mmio); -- cgit v1.2.3 From af2450254052e0da8c42501ee3e2801cc5a6c1f3 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:51:54 +0200 Subject: media: meson: ge2d: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Neil Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/meson/ge2d/ge2d.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/meson/ge2d/ge2d.c b/drivers/media/platform/meson/ge2d/ge2d.c index 9b1e973e78da..ccda18e5a377 100644 --- a/drivers/media/platform/meson/ge2d/ge2d.c +++ b/drivers/media/platform/meson/ge2d/ge2d.c @@ -922,7 +922,6 @@ static int ge2d_probe(struct platform_device *pdev) struct reset_control *rst; struct video_device *vfd; struct meson_ge2d *ge2d; - struct resource *res; void __iomem *regs; int ret = 0; int irq; @@ -937,8 +936,7 @@ static int ge2d_probe(struct platform_device *pdev) ge2d->dev = &pdev->dev; mutex_init(&ge2d->mutex); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(ge2d->dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); -- cgit v1.2.3 From 028ac5439f74dd1238a79aea9da035497fd94635 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:52:01 +0200 Subject: media: mtk-jpeg: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c index a89c7b206eef..af994b9913a6 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c @@ -1341,7 +1341,6 @@ static inline void mtk_jpeg_clk_release(struct mtk_jpeg_dev *jpeg) static int mtk_jpeg_probe(struct platform_device *pdev) { struct mtk_jpeg_dev *jpeg; - struct resource *res; int jpeg_irq; int ret; @@ -1355,8 +1354,7 @@ static int mtk_jpeg_probe(struct platform_device *pdev) jpeg->variant = of_device_get_match_data(jpeg->dev); INIT_DELAYED_WORK(&jpeg->job_timeout_work, mtk_jpeg_job_timeout_work); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - jpeg->reg_base = devm_ioremap_resource(&pdev->dev, res); + jpeg->reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(jpeg->reg_base)) { ret = PTR_ERR(jpeg->reg_base); return ret; -- cgit v1.2.3 From b2fb212d9e3070d0d457a39e29dcf61899c3a2c5 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:54:03 +0200 Subject: media: mx2_emmaprp: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mx2_emmaprp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index 08a5473b5610..3ce84d0f078c 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -804,7 +804,6 @@ static int emmaprp_probe(struct platform_device *pdev) { struct emmaprp_dev *pcdev; struct video_device *vfd; - struct resource *res; int irq, ret; pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL); @@ -822,8 +821,7 @@ static int emmaprp_probe(struct platform_device *pdev) if (IS_ERR(pcdev->clk_emma_ahb)) return PTR_ERR(pcdev->clk_emma_ahb); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pcdev->base_emma = devm_ioremap_resource(&pdev->dev, res); + pcdev->base_emma = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pcdev->base_emma)) return PTR_ERR(pcdev->base_emma); -- cgit v1.2.3 From b619c2ea32fb660181d738b35211e7cd79ee5143 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:54:20 +0200 Subject: media: rc: img-ir: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/img-ir-core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c index 094aa6a06315..6f8464872033 100644 --- a/drivers/media/rc/img-ir/img-ir-core.c +++ b/drivers/media/rc/img-ir/img-ir-core.c @@ -76,7 +76,6 @@ static void img_ir_ident(struct img_ir_priv *priv) static int img_ir_probe(struct platform_device *pdev) { struct img_ir_priv *priv; - struct resource *res_regs; int irq, error, error2; /* Get resources from platform device */ @@ -94,8 +93,7 @@ static int img_ir_probe(struct platform_device *pdev) spin_lock_init(&priv->lock); /* Ioremap the registers */ - res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->reg_base = devm_ioremap_resource(&pdev->dev, res_regs); + priv->reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->reg_base)) return PTR_ERR(priv->reg_base); -- cgit v1.2.3 From 890418523f511a281346497b42731d5ce4562736 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:54:27 +0200 Subject: media: rc: ir-hix5hd2: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-hix5hd2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index 4609fb4519e9..e0be6471afe5 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -249,7 +249,6 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) { struct rc_dev *rdev; struct device *dev = &pdev->dev; - struct resource *res; struct hix5hd2_ir_priv *priv; struct device_node *node = pdev->dev.of_node; const struct of_device_id *of_id; @@ -274,8 +273,7 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) priv->regmap = NULL; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(dev, res); + priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); -- cgit v1.2.3 From c533dabe496bcfec114c857e17e3a6f75e4aee95 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:54:39 +0200 Subject: media: rc: meson-ir: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Neil Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/meson-ir.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index dad55950dfc6..4b769111f78e 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -102,7 +102,6 @@ static int meson_ir_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; - struct resource *res; const char *map_name; struct meson_ir *ir; int irq, ret; @@ -111,8 +110,7 @@ static int meson_ir_probe(struct platform_device *pdev) if (!ir) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ir->reg = devm_ioremap_resource(dev, res); + ir->reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ir->reg)) return PTR_ERR(ir->reg); -- cgit v1.2.3 From dfa974f586049bb81b7f4bbf3dcf4ce8aba1d45d Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:54:47 +0200 Subject: media: rc: mtk-cir: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mtk-cir.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c index 65a136c0fac2..840e7aec5c21 100644 --- a/drivers/media/rc/mtk-cir.c +++ b/drivers/media/rc/mtk-cir.c @@ -292,7 +292,6 @@ static int mtk_ir_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *dn = dev->of_node; - struct resource *res; struct mtk_ir *ir; u32 val; int ret = 0; @@ -320,8 +319,7 @@ static int mtk_ir_probe(struct platform_device *pdev) ir->bus = ir->clk; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ir->base = devm_ioremap_resource(dev, res); + ir->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ir->base)) return PTR_ERR(ir->base); -- cgit v1.2.3 From 044a3571411370e042741a46543be66b74942ccd Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:54:54 +0200 Subject: media: rc: st_rc: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Patrice Chotard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/st_rc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index d79d1e3996b2..4e419dbbacd3 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -231,7 +231,6 @@ static int st_rc_probe(struct platform_device *pdev) int ret = -EINVAL; struct rc_dev *rdev; struct device *dev = &pdev->dev; - struct resource *res; struct st_rc_device *rc_dev; struct device_node *np = pdev->dev.of_node; const char *rx_mode; @@ -274,9 +273,7 @@ static int st_rc_probe(struct platform_device *pdev) goto err; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - rc_dev->base = devm_ioremap_resource(dev, res); + rc_dev->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(rc_dev->base)) { ret = PTR_ERR(rc_dev->base); goto err; -- cgit v1.2.3 From 1c9b885c1d31268ebaaef520f000ffb3be2a4681 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:55:02 +0200 Subject: media: rc: sunxi-cir: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Acked-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/sunxi-cir.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index 168e1d2c876a..391a591c1b75 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -255,7 +255,6 @@ static int sunxi_ir_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *dn = dev->of_node; const struct sunxi_ir_quirks *quirks; - struct resource *res; struct sunxi_ir *ir; u32 b_clk_freq = SUNXI_IR_BASE_CLK; @@ -301,8 +300,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) dev_dbg(dev, "set base clock frequency to %d Hz.\n", b_clk_freq); /* IO */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ir->base = devm_ioremap_resource(dev, res); + ir->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ir->base)) { return PTR_ERR(ir->base); } -- cgit v1.2.3 From 8ac79b3fbc70c8459af7608985b728c3ae416894 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:55:09 +0200 Subject: media: rcar-csi2: Make use of the helper function devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Kieran Bingham Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-csi2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index 711b52ba42b5..a4952711b7b1 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -1238,11 +1238,9 @@ static const struct media_entity_operations rcar_csi2_entity_ops = { static int rcsi2_probe_resources(struct rcar_csi2 *priv, struct platform_device *pdev) { - struct resource *res; int irq, ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(&pdev->dev, res); + priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); -- cgit v1.2.3 From 736cce12fa630e28705de06570d74f0513d948d5 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:55:24 +0200 Subject: media: rcar_fdp1: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Kieran Bingham Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar_fdp1.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c index 89aac60066d9..19de3c19bcca 100644 --- a/drivers/media/platform/rcar_fdp1.c +++ b/drivers/media/platform/rcar_fdp1.c @@ -2256,7 +2256,6 @@ static int fdp1_probe(struct platform_device *pdev) struct fdp1_dev *fdp1; struct video_device *vfd; struct device_node *fcp_node; - struct resource *res; struct clk *clk; unsigned int i; @@ -2283,8 +2282,7 @@ static int fdp1_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fdp1); /* Memory-mapped registers */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - fdp1->regs = devm_ioremap_resource(&pdev->dev, res); + fdp1->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(fdp1->regs)) return PTR_ERR(fdp1->regs); -- cgit v1.2.3 From 81a7cad85166b83e2460cc0b9cf71d8891c6b1e5 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:55:32 +0200 Subject: media: rcar_jpu: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Kieran Bingham Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar_jpu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c index f57158bf2b11..56bb464629ed 100644 --- a/drivers/media/platform/rcar_jpu.c +++ b/drivers/media/platform/rcar_jpu.c @@ -1590,7 +1590,6 @@ MODULE_DEVICE_TABLE(of, jpu_dt_ids); static int jpu_probe(struct platform_device *pdev) { struct jpu *jpu; - struct resource *res; int ret; unsigned int i; @@ -1603,8 +1602,7 @@ static int jpu_probe(struct platform_device *pdev) jpu->dev = &pdev->dev; /* memory-mapped registers */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - jpu->regs = devm_ioremap_resource(&pdev->dev, res); + jpu->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(jpu->regs)) return PTR_ERR(jpu->regs); -- cgit v1.2.3 From a7cba8c9d0a49e6a2ba69a95970d208d8bfc3503 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:55:39 +0200 Subject: media: renesas-ceu: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Kieran Bingham Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/renesas-ceu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c index 9376eb363748..2e8dbacc414e 100644 --- a/drivers/media/platform/renesas-ceu.c +++ b/drivers/media/platform/renesas-ceu.c @@ -1628,7 +1628,6 @@ static int ceu_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; const struct ceu_data *ceu_data; struct ceu_device *ceudev; - struct resource *res; unsigned int irq; int num_subdevs; int ret; @@ -1644,8 +1643,7 @@ static int ceu_probe(struct platform_device *pdev) spin_lock_init(&ceudev->lock); mutex_init(&ceudev->mlock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ceudev->base = devm_ioremap_resource(dev, res); + ceudev->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ceudev->base)) { ret = PTR_ERR(ceudev->base); goto error_free_ceudev; -- cgit v1.2.3 From 0748befbc3b56a001b1265e36b415ad36f97b6d9 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:55:46 +0200 Subject: media: rockchip: rga: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rga/rga.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 6759091b15e0..4de5e8d2b261 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -800,7 +800,6 @@ static int rga_probe(struct platform_device *pdev) { struct rockchip_rga *rga; struct video_device *vfd; - struct resource *res; int ret = 0; int irq; @@ -821,9 +820,7 @@ static int rga_probe(struct platform_device *pdev) pm_runtime_enable(rga->dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - rga->regs = devm_ioremap_resource(rga->dev, res); + rga->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(rga->regs)) { ret = PTR_ERR(rga->regs); goto err_put_clk; -- cgit v1.2.3 From 8db05a69f13c4f59f5f8c47b57914899870090a3 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:55:54 +0200 Subject: media: s3c-camif: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s3c-camif/camif-core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c index e1d51fd3e700..b6a03296c923 100644 --- a/drivers/media/platform/s3c-camif/camif-core.c +++ b/drivers/media/platform/s3c-camif/camif-core.c @@ -402,7 +402,6 @@ static int s3c_camif_probe(struct platform_device *pdev) struct s3c_camif_plat_data *pdata = dev->platform_data; struct s3c_camif_drvdata *drvdata; struct camif_dev *camif; - struct resource *mres; int ret = 0; camif = devm_kzalloc(dev, sizeof(*camif), GFP_KERNEL); @@ -423,9 +422,7 @@ static int s3c_camif_probe(struct platform_device *pdev) drvdata = (void *)platform_get_device_id(pdev)->driver_data; camif->variant = drvdata->variant; - mres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - camif->io_base = devm_ioremap_resource(dev, mres); + camif->io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(camif->io_base)) return PTR_ERR(camif->io_base); -- cgit v1.2.3 From beaa81f410ba97a032ae84b5c9c5472a8372ec1e Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:56:01 +0200 Subject: media: s5p-g2d: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-g2d/g2d.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 1cb5eaabf340..fa0bb31bd2b9 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -635,9 +635,7 @@ static int g2d_probe(struct platform_device *pdev) mutex_init(&dev->mutex); atomic_set(&dev->num_inst, 0); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - dev->regs = devm_ioremap_resource(&pdev->dev, res); + dev->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->regs)) return PTR_ERR(dev->regs); -- cgit v1.2.3 From d084438d237f85654e40e79d98bf0b44b7948362 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:56:09 +0200 Subject: media: s5p-jpeg: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Acked-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index d402e456f27d..1faff037cdf7 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -2850,7 +2850,6 @@ static void *jpeg_get_drv_data(struct device *dev); static int s5p_jpeg_probe(struct platform_device *pdev) { struct s5p_jpeg *jpeg; - struct resource *res; int i, ret; /* JPEG IP abstraction struct */ @@ -2867,9 +2866,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) jpeg->dev = &pdev->dev; /* memory-mapped registers */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - jpeg->regs = devm_ioremap_resource(&pdev->dev, res); + jpeg->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(jpeg->regs)) return PTR_ERR(jpeg->regs); -- cgit v1.2.3 From 5d3b9611d589d820639c1efaa9fb525c40a1841f Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:56:16 +0200 Subject: media: s5p-mfc: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index eba2b9f040df..e0ec24b39fd4 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1289,8 +1289,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) dev->variant = of_device_get_match_data(&pdev->dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->regs_base = devm_ioremap_resource(&pdev->dev, res); + dev->regs_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->regs_base)) return PTR_ERR(dev->regs_base); -- cgit v1.2.3 From 6394c2d95399e572332a18894c027bd25785bcb2 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:56:23 +0200 Subject: media: sti: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/bdisp/bdisp-v4l2.c | 3 +-- drivers/media/platform/sti/hva/hva-hw.c | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index 6413cd279125..7d467f2ba072 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -1315,8 +1315,7 @@ static int bdisp_probe(struct platform_device *pdev) mutex_init(&bdisp->lock); /* get resources */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - bdisp->regs = devm_ioremap_resource(dev, res); + bdisp->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(bdisp->regs)) { ret = PTR_ERR(bdisp->regs); goto err_wq; diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c index 30fb1aa4a351..15e8f83b1b56 100644 --- a/drivers/media/platform/sti/hva/hva-hw.c +++ b/drivers/media/platform/sti/hva/hva-hw.c @@ -298,15 +298,13 @@ static unsigned long int hva_hw_get_ip_version(struct hva_dev *hva) int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva) { struct device *dev = &pdev->dev; - struct resource *regs; struct resource *esram; int ret; WARN_ON(!hva); /* get memory for registers */ - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hva->regs = devm_ioremap_resource(dev, regs); + hva->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hva->regs)) { dev_err(dev, "%s failed to get regs\n", HVA_PREFIX); return PTR_ERR(hva->regs); -- cgit v1.2.3 From beabb243e3aa81b7f5b6e2232068816b470119d9 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:56:38 +0200 Subject: media: stih-cec: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/platform/sti/stih-cec.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/cec/platform/sti/stih-cec.c b/drivers/media/cec/platform/sti/stih-cec.c index f0c73e64b586..abf8e8bcbb34 100644 --- a/drivers/media/cec/platform/sti/stih-cec.c +++ b/drivers/media/cec/platform/sti/stih-cec.c @@ -299,7 +299,6 @@ static const struct cec_adap_ops sti_cec_adap_ops = { static int stih_cec_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct resource *res; struct stih_cec *cec; struct device *hdmi_dev; int ret; @@ -315,8 +314,7 @@ static int stih_cec_probe(struct platform_device *pdev) cec->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - cec->regs = devm_ioremap_resource(dev, res); + cec->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(cec->regs)) return PTR_ERR(cec->regs); -- cgit v1.2.3 From 092c69b2eb09137d41ca3c73c8b47cbba79062cb Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:56:45 +0200 Subject: media: stm32-cec: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/platform/stm32/stm32-cec.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/cec/platform/stm32/stm32-cec.c b/drivers/media/cec/platform/stm32/stm32-cec.c index 0ffd89712536..40db7911b437 100644 --- a/drivers/media/cec/platform/stm32/stm32-cec.c +++ b/drivers/media/cec/platform/stm32/stm32-cec.c @@ -255,7 +255,6 @@ static const struct regmap_config stm32_cec_regmap_cfg = { static int stm32_cec_probe(struct platform_device *pdev) { u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | CEC_MODE_MONITOR_ALL; - struct resource *res; struct stm32_cec *cec; void __iomem *mmio; int ret; @@ -266,8 +265,7 @@ static int stm32_cec_probe(struct platform_device *pdev) cec->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mmio = devm_ioremap_resource(&pdev->dev, res); + mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mmio)) return PTR_ERR(mmio); -- cgit v1.2.3 From 23f8bd25d1526079b5907bdfb7bcf6e579533e48 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:56:53 +0200 Subject: media: sunxi: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Acked-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c | 4 +--- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 4 +--- drivers/media/platform/sunxi/sun8i-di/sun8i-di.c | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c index 94e98e470aff..80a10f238bbe 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c @@ -154,7 +154,6 @@ static int sun4i_csi_probe(struct platform_device *pdev) struct v4l2_subdev *subdev; struct video_device *vdev; struct sun4i_csi *csi; - struct resource *res; int ret; int irq; @@ -179,8 +178,7 @@ static int sun4i_csi_probe(struct platform_device *pdev) media_device_init(&csi->mdev); csi->v4l.mdev = &csi->mdev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - csi->regs = devm_ioremap_resource(&pdev->dev, res); + csi->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(csi->regs)) return PTR_ERR(csi->regs); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 4b8d66fec3cf..fc96921b0583 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -833,13 +833,11 @@ static const struct regmap_config sun6i_csi_regmap_config = { static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, struct platform_device *pdev) { - struct resource *res; void __iomem *io_base; int ret; int irq; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - io_base = devm_ioremap_resource(&pdev->dev, res); + io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(io_base)) return PTR_ERR(io_base); diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c index 671e4a928993..aa65d70b6270 100644 --- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c +++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c @@ -803,7 +803,6 @@ static int deinterlace_probe(struct platform_device *pdev) { struct deinterlace_dev *dev; struct video_device *vfd; - struct resource *res; int irq, ret; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); @@ -825,8 +824,7 @@ static int deinterlace_probe(struct platform_device *pdev) return ret; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->base = devm_ioremap_resource(&pdev->dev, res); + dev->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->base)) return PTR_ERR(dev->base); -- cgit v1.2.3 From b4dac22d27a2cc4db76b3f1c132e9a2b4254b1a8 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:57:01 +0200 Subject: media: venus: core : Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 91b15842c555..7e54c5d571dc 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -267,7 +267,6 @@ static int venus_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct venus_core *core; - struct resource *r; int ret; core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL); @@ -276,8 +275,7 @@ static int venus_probe(struct platform_device *pdev) core->dev = dev; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - core->base = devm_ioremap_resource(dev, r); + core->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(core->base)) return PTR_ERR(core->base); -- cgit v1.2.3 From a24973a60551dab8a4b6cbbe02d64719dc2858a1 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:57:08 +0200 Subject: media: vsp1: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Kieran Bingham Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drv.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index de442d6c9926..8acd6d45d8d0 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -785,7 +785,6 @@ static int vsp1_probe(struct platform_device *pdev) struct vsp1_device *vsp1; struct device_node *fcp_node; struct resource *irq; - struct resource *io; unsigned int i; int ret; @@ -800,8 +799,7 @@ static int vsp1_probe(struct platform_device *pdev) platform_set_drvdata(pdev, vsp1); /* I/O and IRQ resources (clock managed by the clock PM domain). */ - io = platform_get_resource(pdev, IORESOURCE_MEM, 0); - vsp1->mmio = devm_ioremap_resource(&pdev->dev, io); + vsp1->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(vsp1->mmio)) return PTR_ERR(vsp1->mmio); -- cgit v1.2.3 From e0bee542882f953f62106325067b5416e111e24f Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 07:57:15 +0200 Subject: media: xilinx: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/xilinx/xilinx-vip.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c index 425a32dd5d19..a0073122798f 100644 --- a/drivers/media/platform/xilinx/xilinx-vip.c +++ b/drivers/media/platform/xilinx/xilinx-vip.c @@ -205,10 +205,8 @@ EXPORT_SYMBOL_GPL(xvip_clr_and_set); int xvip_init_resources(struct xvip_device *xvip) { struct platform_device *pdev = to_platform_device(xvip->dev); - struct resource *res; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - xvip->iomem = devm_ioremap_resource(xvip->dev, res); + xvip->iomem = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(xvip->iomem)) return PTR_ERR(xvip->iomem); -- cgit v1.2.3 From 1b03b539e63512cc003982113a51b520b7582d93 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 13:44:59 +0200 Subject: media: rcar_drif: Make use of the helper function devm_platform_get_and_ioremap_resource() Use the devm_platform_get_and_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately. Signed-off-by: Cai Huoqing Acked-by: Fabrizio Castro Reviewed-by: Kieran Bingham Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar_drif.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index a505d991548b..9a0982fa5c6b 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -1395,8 +1395,7 @@ static int rcar_drif_probe(struct platform_device *pdev) } /* Register map */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ch->base = devm_ioremap_resource(&pdev->dev, res); + ch->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(ch->base)) return PTR_ERR(ch->base); -- cgit v1.2.3 From 76e21bb8be4f5f987f3006d197196fe6af63f656 Mon Sep 17 00:00:00 2001 From: Evgeny Novikov Date: Thu, 27 May 2021 11:26:24 +0200 Subject: media: vidtv: Fix memory leak in remove vidtv_bridge_remove() releases and cleans up everything except for dvb itself. The patch adds this missed release. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Evgeny Novikov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vidtv/vidtv_bridge.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c index 75617709c8ce..0f6d998d18dc 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c +++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c @@ -557,6 +557,7 @@ static int vidtv_bridge_remove(struct platform_device *pdev) dvb_dmxdev_release(&dvb->dmx_dev); dvb_dmx_release(&dvb->demux); dvb_unregister_adapter(&dvb->adapter); + kfree(dvb); dev_info(&pdev->dev, "Successfully removed vidtv\n"); return 0; -- cgit v1.2.3 From a6b63ca455a19f263d56599f4b37cb1d61eb8fee Mon Sep 17 00:00:00 2001 From: Liu Shixin Date: Thu, 27 May 2021 15:17:01 +0200 Subject: media: pvrusb2: Replaced simple_strtol() with kstrtoint() It looks like that memcpy() is a superfluous operation in parse_token()/parse_mtoken(). Simple these two functions and use kstrtoint() instead of simple_strtol() to avoid data overflow. Signed-off-by: Liu Shixin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pvrusb2/pvrusb2-ctrl.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c index 9f71d8c2a3c6..8ae3ad80cccb 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c @@ -355,11 +355,8 @@ static int parse_token(const char *ptr,unsigned int len, int *valptr, const char * const *names, unsigned int namecnt) { - char buf[33]; unsigned int slen; unsigned int idx; - int negfl; - char *p2; *valptr = 0; if (!names) namecnt = 0; for (idx = 0; idx < namecnt; idx++) { @@ -370,18 +367,7 @@ static int parse_token(const char *ptr,unsigned int len, *valptr = idx; return 0; } - negfl = 0; - if ((*ptr == '-') || (*ptr == '+')) { - negfl = (*ptr == '-'); - ptr++; len--; - } - if (len >= sizeof(buf)) return -EINVAL; - memcpy(buf,ptr,len); - buf[len] = 0; - *valptr = simple_strtol(buf,&p2,0); - if (negfl) *valptr = -(*valptr); - if (*p2) return -EINVAL; - return 1; + return kstrtoint(ptr, 0, valptr) ? -EINVAL : 1; } @@ -389,10 +375,8 @@ static int parse_mtoken(const char *ptr,unsigned int len, int *valptr, const char **names,int valid_bits) { - char buf[33]; unsigned int slen; unsigned int idx; - char *p2; int msk; *valptr = 0; for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) { @@ -405,12 +389,7 @@ static int parse_mtoken(const char *ptr,unsigned int len, *valptr = msk; return 0; } - if (len >= sizeof(buf)) return -EINVAL; - memcpy(buf,ptr,len); - buf[len] = 0; - *valptr = simple_strtol(buf,&p2,0); - if (*p2) return -EINVAL; - return 0; + return kstrtoint(ptr, 0, valptr); } -- cgit v1.2.3 From 065a7c66bd8b21db212fa86187ff12f0cac6ea6d Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Fri, 28 May 2021 10:36:41 +0200 Subject: media: mtk-vcodec: venc: fix return value when start_streaming fails In case vb2ops_venc_start_streaming fails, the error value is overwritten by the ret value of pm_runtime_put which might be 0. Fix it. Fixes: 985c73693fe5a (" media: mtk-vcodec: Separating mtk encoder driver") Signed-off-by: Dafna Hirschfeld Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index efa53ea573a2..7457451ebff0 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c @@ -873,7 +873,7 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) { struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q); struct venc_enc_param param; - int ret; + int ret, pm_ret; int i; /* Once state turn into MTK_STATE_ABORT, we need stop_streaming @@ -925,9 +925,9 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) return 0; err_set_param: - ret = pm_runtime_put(&ctx->dev->plat_dev->dev); - if (ret < 0) - mtk_v4l2_err("pm_runtime_put fail %d", ret); + pm_ret = pm_runtime_put(&ctx->dev->plat_dev->dev); + if (pm_ret < 0) + mtk_v4l2_err("pm_runtime_put fail %d", pm_ret); err_start_stream: for (i = 0; i < q->num_buffers; ++i) { -- cgit v1.2.3 From 9031d6b3623f12e7aac6b5f3690ce575a4557da7 Mon Sep 17 00:00:00 2001 From: lijian Date: Fri, 28 May 2021 10:47:40 +0200 Subject: media: via-camera: deleted these redundant semicolons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Macros should not use a trailing semicolon,and it was used the semicolon after macro cam_dbg called in viacam_vb2_prepare, so deleted these redundant semicolons. Signed-off-by: lijian Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/via-camera.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index 3655573e8581..95483c84c3f2 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -132,11 +132,11 @@ static struct via_camera *via_cam_info; * Debugging and related. */ #define cam_err(cam, fmt, arg...) \ - dev_err(&(cam)->platdev->dev, fmt, ##arg); + dev_err(&(cam)->platdev->dev, fmt, ##arg) #define cam_warn(cam, fmt, arg...) \ - dev_warn(&(cam)->platdev->dev, fmt, ##arg); + dev_warn(&(cam)->platdev->dev, fmt, ##arg) #define cam_dbg(cam, fmt, arg...) \ - dev_dbg(&(cam)->platdev->dev, fmt, ##arg); + dev_dbg(&(cam)->platdev->dev, fmt, ##arg) /* * Format handling. This is ripped almost directly from Hans's changes -- cgit v1.2.3 From 35d2969ea3c7d32aee78066b1f3cf61a0d935a4e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 7 Jun 2021 17:23:48 +0200 Subject: media: firewire: firedtv-avc: fix a buffer overflow in avc_ca_pmt() The bounds checking in avc_ca_pmt() is not strict enough. It should be checking "read_pos + 4" because it's reading 5 bytes. If the "es_info_length" is non-zero then it reads a 6th byte so there needs to be an additional check for that. I also added checks for the "write_pos". I don't think these are required because "read_pos" and "write_pos" are tied together so checking one ought to be enough. But they make the code easier to understand for me. The check on write_pos is: if (write_pos + 4 >= sizeof(c->operand) - 4) { The first "+ 4" is because we're writing 5 bytes and the last " - 4" is to leave space for the CRC. The other problem is that "length" can be invalid. It comes from "data_length" in fdtv_ca_pmt(). Cc: stable@vger.kernel.org Reported-by: Luo Likang Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/firewire/firedtv-avc.c | 14 +++++++++++--- drivers/media/firewire/firedtv-ci.c | 2 ++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/media/firewire/firedtv-avc.c b/drivers/media/firewire/firedtv-avc.c index 2bf9467b917d..71991f8638e6 100644 --- a/drivers/media/firewire/firedtv-avc.c +++ b/drivers/media/firewire/firedtv-avc.c @@ -1165,7 +1165,11 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) read_pos += program_info_length; write_pos += program_info_length; } - while (read_pos < length) { + while (read_pos + 4 < length) { + if (write_pos + 4 >= sizeof(c->operand) - 4) { + ret = -EINVAL; + goto out; + } c->operand[write_pos++] = msg[read_pos++]; c->operand[write_pos++] = msg[read_pos++]; c->operand[write_pos++] = msg[read_pos++]; @@ -1177,13 +1181,17 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) c->operand[write_pos++] = es_info_length >> 8; c->operand[write_pos++] = es_info_length & 0xff; if (es_info_length > 0) { + if (read_pos >= length) { + ret = -EINVAL; + goto out; + } pmt_cmd_id = msg[read_pos++]; if (pmt_cmd_id != 1 && pmt_cmd_id != 4) dev_err(fdtv->device, "invalid pmt_cmd_id %d at stream level\n", pmt_cmd_id); - if (es_info_length > sizeof(c->operand) - 4 - - write_pos) { + if (es_info_length > sizeof(c->operand) - 4 - write_pos || + es_info_length > length - read_pos) { ret = -EINVAL; goto out; } diff --git a/drivers/media/firewire/firedtv-ci.c b/drivers/media/firewire/firedtv-ci.c index 9363d005e2b6..e0d57e09dab0 100644 --- a/drivers/media/firewire/firedtv-ci.c +++ b/drivers/media/firewire/firedtv-ci.c @@ -134,6 +134,8 @@ static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg) } else { data_length = msg->msg[3]; } + if (data_length > sizeof(msg->msg) - data_pos) + return -EINVAL; return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length); } -- cgit v1.2.3 From ea8a5c118e2491726ffd27fd3fc149110d104095 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Fri, 18 Jun 2021 00:02:29 +0200 Subject: media: aspeed-video: ignore interrupts that aren't enabled As partially addressed in commit 65d270acb2d6 ("media: aspeed: clear garbage interrupts"), the ASpeed video engine sometimes asserts interrupts that the driver hasn't enabled. In addition to the CAPTURE_COMPLETE and FRAME_COMPLETE interrupts dealt with in that patch, COMP_READY has also been observed. Instead of playing whack-a-mole with each one individually, we can instead just blanket ignore everything we haven't explicitly enabled. Signed-off-by: Zev Weiss Tested-by: Lei YU Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index 7bb6babdcade..77611c296a25 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -563,6 +563,12 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) struct aspeed_video *video = arg; u32 sts = aspeed_video_read(video, VE_INTERRUPT_STATUS); + /* + * Hardware sometimes asserts interrupts that we haven't actually + * enabled; ignore them if so. + */ + sts &= aspeed_video_read(video, VE_INTERRUPT_CTRL); + /* * Resolution changed or signal was lost; reset the engine and * re-initialize @@ -629,16 +635,6 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) aspeed_video_start_frame(video); } - /* - * CAPTURE_COMPLETE and FRAME_COMPLETE interrupts come even when these - * are disabled in the VE_INTERRUPT_CTRL register so clear them to - * prevent unnecessary interrupt calls. - */ - if (sts & VE_INTERRUPT_CAPTURE_COMPLETE) - sts &= ~VE_INTERRUPT_CAPTURE_COMPLETE; - if (sts & VE_INTERRUPT_FRAME_COMPLETE) - sts &= ~VE_INTERRUPT_FRAME_COMPLETE; - return sts ? IRQ_NONE : IRQ_HANDLED; } -- cgit v1.2.3 From 8515965e5e33f4feb56134348c95953f3eadfb26 Mon Sep 17 00:00:00 2001 From: Tuo Li Date: Thu, 5 Aug 2021 09:55:35 +0200 Subject: media: s5p-mfc: fix possible null-pointer dereference in s5p_mfc_probe() The variable pdev is assigned to dev->plat_dev, and dev->plat_dev is checked in: if (!dev->plat_dev) This indicates both dev->plat_dev and pdev can be NULL. If so, the function dev_err() is called to print error information. dev_err(&pdev->dev, "No platform data specified\n"); However, &pdev->dev is an illegal address, and it is dereferenced in dev_err(). To fix this possible null-pointer dereference, replace dev_err() with mfc_err(). Reported-by: TOTE Robot Signed-off-by: Tuo Li Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index e0ec24b39fd4..293af8e664f4 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1283,7 +1283,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) spin_lock_init(&dev->condlock); dev->plat_dev = pdev; if (!dev->plat_dev) { - dev_err(&pdev->dev, "No platform data specified\n"); + mfc_err("No platform data specified\n"); return -ENODEV; } -- cgit v1.2.3 From 7e360fa0c0f3e7dd1aa8f2b574d7b461d0caf5e2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 11 Aug 2021 13:36:54 +0200 Subject: media: cec-pin: fix off-by-one SFT check The CEC pin framework has to wait for the CEC bus to be idle for the requested Signal Free Time before it can start a transmit. However, the check for that was off by one, so transmits would start one bit period (2.4ms) too late. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/core/cec-pin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/cec/core/cec-pin.c b/drivers/media/cec/core/cec-pin.c index 8c613aa649c6..a60b6f03a6a1 100644 --- a/drivers/media/cec/core/cec-pin.c +++ b/drivers/media/cec/core/cec-pin.c @@ -957,7 +957,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) * so we can kick off the pending transmit. */ delta = ktime_us_delta(ts, pin->ts); - if (delta / CEC_TIM_DATA_BIT_TOTAL > + if (delta / CEC_TIM_DATA_BIT_TOTAL >= pin->tx_signal_free_time) { pin->tx_nacked = false; if (tx_custom_start(pin)) @@ -968,7 +968,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) cec_pin_low(pin); break; } - if (delta / CEC_TIM_DATA_BIT_TOTAL > + if (delta / CEC_TIM_DATA_BIT_TOTAL >= pin->tx_signal_free_time - 1) pin->state = CEC_ST_TX_WAIT; break; -- cgit v1.2.3 From cdfaf4752e6915a4b455ad4400133e540e4dc965 Mon Sep 17 00:00:00 2001 From: Nadezda Lutovinova Date: Wed, 11 Aug 2021 15:32:28 +0200 Subject: media: s5p-mfc: Add checking to s5p_mfc_probe(). If of_device_get_match_data() return NULL, then null pointer dereference occurs in s5p_mfc_init_pm(). The patch adds checking if dev->variant is NULL. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Nadezda Lutovinova Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 293af8e664f4..fc85e4e2d020 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1288,6 +1288,10 @@ static int s5p_mfc_probe(struct platform_device *pdev) } dev->variant = of_device_get_match_data(&pdev->dev); + if (!dev->variant) { + dev_err(&pdev->dev, "Failed to get device MFC hardware variant information\n"); + return -ENOENT; + } dev->regs_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->regs_base)) -- cgit v1.2.3 From 48d219f9cc667bc6fbc3e3af0b1bfd75db94fce4 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Thu, 12 Aug 2021 19:00:43 +0200 Subject: media: TDA1997x: handle short reads of hdmi info frame. Static analysis reports this representative problem tda1997x.c:1939: warning: 7th function call argument is an uninitialized value The 7th argument is buffer[0], which is set in the earlier call to io_readn(). When io_readn() call to io_read() fails with the first read, buffer[0] is not set and 0 is returned and stored in len. The later call to hdmi_infoframe_unpack()'s size parameter is the static size of buffer, always 40, so a short read is not caught in hdmi_infoframe_unpacks()'s checking. The variable len should be used instead. Zero initialize buffer to 0 so it is in a known start state. Fixes: 9ac0038db9a7 ("media: i2c: Add TDA1997x HDMI receiver driver") Signed-off-by: Tom Rix Reviewed-by: Tim Harvey Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda1997x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 1e2a263be933..0b995424cb34 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -1248,13 +1248,13 @@ tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr) { struct v4l2_subdev *sd = &state->sd; union hdmi_infoframe frame; - u8 buffer[40]; + u8 buffer[40] = { 0 }; u8 reg; int len, err; /* read data */ len = io_readn(sd, addr, sizeof(buffer), buffer); - err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)); + err = hdmi_infoframe_unpack(&frame, buffer, len); if (err) { v4l_err(state->client, "failed parsing %d byte infoframe: 0x%04x/0x%02x\n", @@ -1928,13 +1928,13 @@ static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr) { struct tda1997x_state *state = to_state(sd); union hdmi_infoframe frame; - u8 buffer[40]; + u8 buffer[40] = { 0 }; int len, err; /* read data */ len = io_readn(sd, addr, sizeof(buffer), buffer); v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len); - err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)); + err = hdmi_infoframe_unpack(&frame, buffer, len); if (err) { v4l_err(state->client, "failed parsing %d byte infoframe: 0x%04x/0x%02x\n", -- cgit v1.2.3 From a9be3931188f240aa2dbdb7c9af65ecfb8c073c1 Mon Sep 17 00:00:00 2001 From: Nil Yi Date: Sun, 15 Aug 2021 11:49:23 +0200 Subject: media: usb: airspy: clean the freed pointer and counter After urb was freed, the pointer and counter need to be cleaned. Signed-off-by: Nil Yi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/airspy/airspy.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 7a81be7970b2..d568452618d1 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -415,8 +415,11 @@ static int airspy_alloc_urbs(struct airspy *s) dev_dbg(s->dev, "alloc urb=%d\n", i); s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); if (!s->urb_list[i]) { - for (j = 0; j < i; j++) + for (j = 0; j < i; j++) { usb_free_urb(s->urb_list[j]); + s->urb_list[j] = NULL; + } + s->urbs_initialized = 0; return -ENOMEM; } usb_fill_bulk_urb(s->urb_list[i], -- cgit v1.2.3 From 749d896551df2ae6996aab51c25bbb3ecd589774 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Wed, 18 Aug 2021 21:41:05 +0200 Subject: media: camss: vfe: simplify vfe_get_wm_sizes() Static analysis reports this representative problem camss-vfe-4-1.c:333: The result of the left shift is undefined because the left operand is negative reg |= (height - 1) << 4; ~~~~~~~~~ ^ The is a false positive. height is set in vfe_get_wm_sizes() which has a switch statement without a default. Reviewing the switch, the cases contain redundant assignments. So simplify to assignments. Signed-off-by: Tom Rix Reviewed-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-vfe-4-1.c | 20 ++++++-------------- drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 10 +++------- drivers/media/platform/qcom/camss/camss-vfe-4-8.c | 9 +++------ 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c index 7b7c9a0aaab2..42047b11ba52 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c @@ -290,22 +290,14 @@ static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable) static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane, u16 *width, u16 *height, u16 *bytesperline) { - switch (pix->pixelformat) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - *width = pix->width; - *height = pix->height; - *bytesperline = pix->plane_fmt[0].bytesperline; + *width = pix->width; + *height = pix->height; + *bytesperline = pix->plane_fmt[0].bytesperline; + + if (pix->pixelformat == V4L2_PIX_FMT_NV12 || + pix->pixelformat == V4L2_PIX_FMT_NV21) if (plane == 1) *height /= 2; - break; - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - *width = pix->width; - *height = pix->height; - *bytesperline = pix->plane_fmt[0].bytesperline; - break; - } } static void vfe_wm_line_based(struct vfe_device *vfe, u32 wm, diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c index 2836b12ec989..ab2d57bdf5e7 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c @@ -370,30 +370,26 @@ static int vfe_word_per_line_by_bytes(u32 bytes_per_line) static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane, u16 *width, u16 *height, u16 *bytesperline) { + *width = pix->width; + *height = pix->height; + switch (pix->pixelformat) { case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: - *width = pix->width; - *height = pix->height; *bytesperline = pix->plane_fmt[0].bytesperline; if (plane == 1) *height /= 2; break; case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV61: - *width = pix->width; - *height = pix->height; *bytesperline = pix->plane_fmt[0].bytesperline; break; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_VYUY: case V4L2_PIX_FMT_UYVY: - *width = pix->width; - *height = pix->height; *bytesperline = pix->plane_fmt[plane].bytesperline; break; - } } diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c index 19519234f727..7e6b62c930ac 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c @@ -343,27 +343,24 @@ static int vfe_word_per_line_by_bytes(u32 bytes_per_line) static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane, u16 *width, u16 *height, u16 *bytesperline) { + *width = pix->width; + *height = pix->height; + switch (pix->pixelformat) { case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: - *width = pix->width; - *height = pix->height; *bytesperline = pix->plane_fmt[0].bytesperline; if (plane == 1) *height /= 2; break; case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV61: - *width = pix->width; - *height = pix->height; *bytesperline = pix->plane_fmt[0].bytesperline; break; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_VYUY: case V4L2_PIX_FMT_UYVY: - *width = pix->width; - *height = pix->height; *bytesperline = pix->plane_fmt[plane].bytesperline; break; } -- cgit v1.2.3 From 2143ad413c05c7be24c3a92760e367b7f6aaac92 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 19 Aug 2021 22:21:25 +0200 Subject: media: mtk-vpu: Fix a resource leak in the error handling path of 'mtk_vpu_probe()' A successful 'clk_prepare()' call should be balanced by a corresponding 'clk_unprepare()' call in the error handling path of the probe, as already done in the remove function. Update the error handling path accordingly. Fixes: 3003a180ef6b ("[media] VPU: mediatek: support Mediatek VPU") Signed-off-by: Christophe JAILLET Reviewed-by: Houlong Wei Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vpu/mtk_vpu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index ec290dde59cf..7f1647da0ade 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -848,7 +848,8 @@ static int mtk_vpu_probe(struct platform_device *pdev) vpu->wdt.wq = create_singlethread_workqueue("vpu_wdt"); if (!vpu->wdt.wq) { dev_err(dev, "initialize wdt workqueue failed\n"); - return -ENOMEM; + ret = -ENOMEM; + goto clk_unprepare; } INIT_WORK(&vpu->wdt.ws, vpu_wdt_reset_func); mutex_init(&vpu->vpu_mutex); @@ -942,6 +943,8 @@ disable_vpu_clk: vpu_clock_disable(vpu); workqueue_destroy: destroy_workqueue(vpu->wdt.wq); +clk_unprepare: + clk_unprepare(vpu->clk); return ret; } -- cgit v1.2.3 From 5c47dc6657543b3c4dffcbe741fb693b9b96796d Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 21 Aug 2021 13:12:53 +0200 Subject: media: imx-jpeg: Fix the error handling path of 'mxc_jpeg_probe()' A successful 'mxc_jpeg_attach_pm_domains()' call should be balanced by a corresponding 'mxc_jpeg_detach_pm_domains()' call in the error handling path of the probe, as already done in the remove function. Update the error handling path accordingly. Fixes: 2db16c6ed72c ("media: imx-jpeg: Add V4L2 driver for i.MX8 JPEG Encoder/Decoder") Signed-off-by: Christophe JAILLET Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/imx-jpeg/mxc-jpeg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/imx-jpeg/mxc-jpeg.c index b3cc5199ef28..73e73b6f2e5b 100644 --- a/drivers/media/platform/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.c @@ -2086,6 +2086,8 @@ err_m2m: v4l2_device_unregister(&jpeg->v4l2_dev); err_register: + mxc_jpeg_detach_pm_domains(jpeg); + err_irq: return ret; } -- cgit v1.2.3 From 1932dc2f4cf6ac23e48e5fcc24d21adbe35691d1 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 21 Aug 2021 23:54:22 +0200 Subject: media: pci/ivtv: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below. It has been compile tested. No memory allocation in involved in this patch, so no GFP_ tweak is needed. @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtv-driver.c | 2 +- drivers/media/pci/ivtv/ivtv-queue.c | 18 ++++++++++-------- drivers/media/pci/ivtv/ivtv-streams.c | 22 +++++++++++----------- drivers/media/pci/ivtv/ivtv-udma.c | 19 ++++++++++++------- drivers/media/pci/ivtv/ivtv-yuv.c | 10 +++++++--- 5 files changed, 41 insertions(+), 30 deletions(-) diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index 8ebc97ebf1a2..57d4d5485d7a 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -837,7 +837,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev, IVTV_ERR("Can't enable device!\n"); return -EIO; } - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { IVTV_ERR("No suitable DMA available.\n"); return -EIO; } diff --git a/drivers/media/pci/ivtv/ivtv-queue.c b/drivers/media/pci/ivtv/ivtv-queue.c index 7ac4615e92ea..f9b192ab7e7c 100644 --- a/drivers/media/pci/ivtv/ivtv-queue.c +++ b/drivers/media/pci/ivtv/ivtv-queue.c @@ -188,7 +188,7 @@ int ivtv_stream_alloc(struct ivtv_stream *s) return 0; IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n", - s->dma != PCI_DMA_NONE ? "DMA " : "", + s->dma != DMA_NONE ? "DMA " : "", s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); s->sg_pending = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN); @@ -218,8 +218,9 @@ int ivtv_stream_alloc(struct ivtv_stream *s) return -ENOMEM; } if (ivtv_might_use_dma(s)) { - s->sg_handle = pci_map_single(itv->pdev, s->sg_dma, - sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); + s->sg_handle = dma_map_single(&itv->pdev->dev, s->sg_dma, + sizeof(struct ivtv_sg_element), + DMA_TO_DEVICE); ivtv_stream_sync_for_cpu(s); } @@ -237,7 +238,7 @@ int ivtv_stream_alloc(struct ivtv_stream *s) } INIT_LIST_HEAD(&buf->list); if (ivtv_might_use_dma(s)) { - buf->dma_handle = pci_map_single(s->itv->pdev, + buf->dma_handle = dma_map_single(&s->itv->pdev->dev, buf->buf, s->buf_size + 256, s->dma); ivtv_buf_sync_for_cpu(s, buf); } @@ -260,8 +261,8 @@ void ivtv_stream_free(struct ivtv_stream *s) /* empty q_free */ while ((buf = ivtv_dequeue(s, &s->q_free))) { if (ivtv_might_use_dma(s)) - pci_unmap_single(s->itv->pdev, buf->dma_handle, - s->buf_size + 256, s->dma); + dma_unmap_single(&s->itv->pdev->dev, buf->dma_handle, + s->buf_size + 256, s->dma); kfree(buf->buf); kfree(buf); } @@ -269,8 +270,9 @@ void ivtv_stream_free(struct ivtv_stream *s) /* Free SG Array/Lists */ if (s->sg_dma != NULL) { if (s->sg_handle != IVTV_DMA_UNMAPPED) { - pci_unmap_single(s->itv->pdev, s->sg_handle, - sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); + dma_unmap_single(&s->itv->pdev->dev, s->sg_handle, + sizeof(struct ivtv_sg_element), + DMA_TO_DEVICE); s->sg_handle = IVTV_DMA_UNMAPPED; } kfree(s->sg_pending); diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c index f04ee84bab5f..6e455948cc77 100644 --- a/drivers/media/pci/ivtv/ivtv-streams.c +++ b/drivers/media/pci/ivtv/ivtv-streams.c @@ -100,7 +100,7 @@ static struct { { /* IVTV_ENC_STREAM_TYPE_MPG */ "encoder MPG", VFL_TYPE_VIDEO, 0, - PCI_DMA_FROMDEVICE, 0, + DMA_FROM_DEVICE, 0, V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, &ivtv_v4l2_enc_fops @@ -108,7 +108,7 @@ static struct { { /* IVTV_ENC_STREAM_TYPE_YUV */ "encoder YUV", VFL_TYPE_VIDEO, IVTV_V4L2_ENC_YUV_OFFSET, - PCI_DMA_FROMDEVICE, 0, + DMA_FROM_DEVICE, 0, V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, &ivtv_v4l2_enc_fops @@ -116,7 +116,7 @@ static struct { { /* IVTV_ENC_STREAM_TYPE_VBI */ "encoder VBI", VFL_TYPE_VBI, 0, - PCI_DMA_FROMDEVICE, 0, + DMA_FROM_DEVICE, 0, V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, &ivtv_v4l2_enc_fops @@ -124,42 +124,42 @@ static struct { { /* IVTV_ENC_STREAM_TYPE_PCM */ "encoder PCM", VFL_TYPE_VIDEO, IVTV_V4L2_ENC_PCM_OFFSET, - PCI_DMA_FROMDEVICE, 0, + DMA_FROM_DEVICE, 0, V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, &ivtv_v4l2_enc_fops }, { /* IVTV_ENC_STREAM_TYPE_RAD */ "encoder radio", VFL_TYPE_RADIO, 0, - PCI_DMA_NONE, 1, + DMA_NONE, 1, V4L2_CAP_RADIO | V4L2_CAP_TUNER, &ivtv_v4l2_radio_fops }, { /* IVTV_DEC_STREAM_TYPE_MPG */ "decoder MPG", VFL_TYPE_VIDEO, IVTV_V4L2_DEC_MPG_OFFSET, - PCI_DMA_TODEVICE, 0, + DMA_TO_DEVICE, 0, V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, &ivtv_v4l2_dec_fops }, { /* IVTV_DEC_STREAM_TYPE_VBI */ "decoder VBI", VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET, - PCI_DMA_NONE, 1, + DMA_NONE, 1, V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_READWRITE, &ivtv_v4l2_enc_fops }, { /* IVTV_DEC_STREAM_TYPE_VOUT */ "decoder VOUT", VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET, - PCI_DMA_NONE, 1, + DMA_NONE, 1, V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, &ivtv_v4l2_dec_fops }, { /* IVTV_DEC_STREAM_TYPE_YUV */ "decoder YUV", VFL_TYPE_VIDEO, IVTV_V4L2_DEC_YUV_OFFSET, - PCI_DMA_TODEVICE, 0, + DMA_TO_DEVICE, 0, V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, &ivtv_v4l2_dec_fops } @@ -179,7 +179,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type) s->caps = ivtv_stream_info[type].v4l2_caps; if (ivtv_stream_info[type].pio) - s->dma = PCI_DMA_NONE; + s->dma = DMA_NONE; else s->dma = ivtv_stream_info[type].dma; s->buf_size = itv->stream_buf_size[type]; @@ -217,7 +217,7 @@ static int ivtv_prep_dev(struct ivtv *itv, int type) /* User explicitly selected 0 buffers for these streams, so don't create them. */ - if (ivtv_stream_info[type].dma != PCI_DMA_NONE && + if (ivtv_stream_info[type].dma != DMA_NONE && itv->options.kilobytes[type] == 0) { IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); return 0; diff --git a/drivers/media/pci/ivtv/ivtv-udma.c b/drivers/media/pci/ivtv/ivtv-udma.c index 0d8372cc364a..210be8290f24 100644 --- a/drivers/media/pci/ivtv/ivtv-udma.c +++ b/drivers/media/pci/ivtv/ivtv-udma.c @@ -81,8 +81,10 @@ void ivtv_udma_alloc(struct ivtv *itv) { if (itv->udma.SG_handle == 0) { /* Map DMA Page Array Buffer */ - itv->udma.SG_handle = pci_map_single(itv->pdev, itv->udma.SGarray, - sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); + itv->udma.SG_handle = dma_map_single(&itv->pdev->dev, + itv->udma.SGarray, + sizeof(itv->udma.SGarray), + DMA_TO_DEVICE); ivtv_udma_sync_for_cpu(itv); } } @@ -135,7 +137,8 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, } /* Map SG List */ - dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); + dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist, + dma->page_count, DMA_TO_DEVICE); /* Fill SG Array with new values */ ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1); @@ -159,7 +162,8 @@ void ivtv_udma_unmap(struct ivtv *itv) /* Unmap Scatterlist */ if (dma->SG_length) { - pci_unmap_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); + dma_unmap_sg(&itv->pdev->dev, dma->SGlist, dma->page_count, + DMA_TO_DEVICE); dma->SG_length = 0; } /* sync DMA */ @@ -175,13 +179,14 @@ void ivtv_udma_free(struct ivtv *itv) /* Unmap SG Array */ if (itv->udma.SG_handle) { - pci_unmap_single(itv->pdev, itv->udma.SG_handle, - sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); + dma_unmap_single(&itv->pdev->dev, itv->udma.SG_handle, + sizeof(itv->udma.SGarray), DMA_TO_DEVICE); } /* Unmap Scatterlist */ if (itv->udma.SG_length) { - pci_unmap_sg(itv->pdev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE); + dma_unmap_sg(&itv->pdev->dev, itv->udma.SGlist, + itv->udma.page_count, DMA_TO_DEVICE); } for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) { diff --git a/drivers/media/pci/ivtv/ivtv-yuv.c b/drivers/media/pci/ivtv/ivtv-yuv.c index 5f7dc9771f8d..e79e8a5a744a 100644 --- a/drivers/media/pci/ivtv/ivtv-yuv.c +++ b/drivers/media/pci/ivtv/ivtv-yuv.c @@ -113,7 +113,8 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, dma->page_count = 0; return -ENOMEM; } - dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); + dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist, + dma->page_count, DMA_TO_DEVICE); /* Fill SG Array with new values */ ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size); @@ -920,7 +921,9 @@ static void ivtv_yuv_init(struct ivtv *itv) /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ yi->blanking_ptr = kzalloc(720 * 16, GFP_ATOMIC|__GFP_NOWARN); if (yi->blanking_ptr) { - yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE); + yi->blanking_dmaptr = dma_map_single(&itv->pdev->dev, + yi->blanking_ptr, + 720 * 16, DMA_TO_DEVICE); } else { yi->blanking_dmaptr = 0; IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n"); @@ -1264,7 +1267,8 @@ void ivtv_yuv_close(struct ivtv *itv) if (yi->blanking_ptr) { kfree(yi->blanking_ptr); yi->blanking_ptr = NULL; - pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); + dma_unmap_single(&itv->pdev->dev, yi->blanking_dmaptr, + 720 * 16, DMA_TO_DEVICE); } /* Invalidate the old dimension information */ -- cgit v1.2.3 From 887069f424550ebdcb411166733e1d05002b58e4 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 22 Aug 2021 11:30:08 +0200 Subject: media: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below. It has been compile tested. @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Reviewed-by: Sakari Ailus Tested-by: Akihiro Tsukada Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cobalt/cobalt-driver.c | 4 ++-- drivers/media/pci/cx18/cx18-driver.c | 2 +- drivers/media/pci/cx18/cx18-queue.c | 13 +++++++------ drivers/media/pci/cx18/cx18-streams.c | 16 ++++++++-------- drivers/media/pci/ddbridge/ddbridge-main.c | 4 ++-- drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 2 +- drivers/media/pci/netup_unidvb/netup_unidvb_core.c | 2 +- drivers/media/pci/pluto2/pluto2.c | 20 ++++++++++---------- drivers/media/pci/pt1/pt1.c | 2 +- drivers/media/pci/tw5864/tw5864-core.c | 2 +- 10 files changed, 34 insertions(+), 33 deletions(-) diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 16af58f2f93c..74edcc76d12f 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -332,8 +332,8 @@ static int cobalt_setup_pci(struct cobalt *cobalt, struct pci_dev *pci_dev, } } - if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64))) { - ret = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(64))) { + ret = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); if (ret) { cobalt_err("no suitable DMA available\n"); goto err_disable; diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index f2440eb38820..59497ba6bf1f 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -804,7 +804,7 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, CX18_ERR("Can't enable device %d!\n", cx->instance); return -EIO; } - if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) { CX18_ERR("No suitable DMA available, card %d\n", cx->instance); return -EIO; } diff --git a/drivers/media/pci/cx18/cx18-queue.c b/drivers/media/pci/cx18/cx18-queue.c index 2f5df471dada..013694bfcb1c 100644 --- a/drivers/media/pci/cx18/cx18-queue.c +++ b/drivers/media/pci/cx18/cx18-queue.c @@ -325,8 +325,8 @@ void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl) struct cx18_buffer *buf; list_for_each_entry(buf, &mdl->buf_list, list) - pci_dma_sync_single_for_device(pci_dev, buf->dma_handle, - buf_size, dma); + dma_sync_single_for_device(&pci_dev->dev, buf->dma_handle, + buf_size, dma); } int cx18_stream_alloc(struct cx18_stream *s) @@ -385,8 +385,9 @@ int cx18_stream_alloc(struct cx18_stream *s) cx18_enqueue(s, mdl, &s->q_idle); INIT_LIST_HEAD(&buf->list); - buf->dma_handle = pci_map_single(s->cx->pci_dev, - buf->buf, s->buf_size, s->dma); + buf->dma_handle = dma_map_single(&s->cx->pci_dev->dev, + buf->buf, s->buf_size, + s->dma); cx18_buf_sync_for_cpu(s, buf); list_add_tail(&buf->list, &s->buf_pool); } @@ -419,8 +420,8 @@ void cx18_stream_free(struct cx18_stream *s) buf = list_first_entry(&s->buf_pool, struct cx18_buffer, list); list_del_init(&buf->list); - pci_unmap_single(s->cx->pci_dev, buf->dma_handle, - s->buf_size, s->dma); + dma_unmap_single(&s->cx->pci_dev->dev, buf->dma_handle, + s->buf_size, s->dma); kfree(buf->buf); kfree(buf); } diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index 16d37ab48906..87ff554bb2d2 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -49,44 +49,44 @@ static struct { { /* CX18_ENC_STREAM_TYPE_MPG */ "encoder MPEG", VFL_TYPE_VIDEO, 0, - PCI_DMA_FROMDEVICE, + DMA_FROM_DEVICE, V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_AUDIO | V4L2_CAP_TUNER }, { /* CX18_ENC_STREAM_TYPE_TS */ "TS", VFL_TYPE_VIDEO, -1, - PCI_DMA_FROMDEVICE, + DMA_FROM_DEVICE, }, { /* CX18_ENC_STREAM_TYPE_YUV */ "encoder YUV", VFL_TYPE_VIDEO, CX18_V4L2_ENC_YUV_OFFSET, - PCI_DMA_FROMDEVICE, + DMA_FROM_DEVICE, V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO | V4L2_CAP_TUNER }, { /* CX18_ENC_STREAM_TYPE_VBI */ "encoder VBI", VFL_TYPE_VBI, 0, - PCI_DMA_FROMDEVICE, + DMA_FROM_DEVICE, V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_TUNER }, { /* CX18_ENC_STREAM_TYPE_PCM */ "encoder PCM audio", VFL_TYPE_VIDEO, CX18_V4L2_ENC_PCM_OFFSET, - PCI_DMA_FROMDEVICE, + DMA_FROM_DEVICE, V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, }, { /* CX18_ENC_STREAM_TYPE_IDX */ "encoder IDX", VFL_TYPE_VIDEO, -1, - PCI_DMA_FROMDEVICE, + DMA_FROM_DEVICE, }, { /* CX18_ENC_STREAM_TYPE_RAD */ "encoder radio", VFL_TYPE_RADIO, 0, - PCI_DMA_NONE, + DMA_NONE, V4L2_CAP_RADIO | V4L2_CAP_TUNER }, }; @@ -324,7 +324,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type) /* User explicitly selected 0 buffers for these streams, so don't create them. */ - if (cx18_stream_info[type].dma != PCI_DMA_NONE && + if (cx18_stream_info[type].dma != DMA_NONE && cx->stream_buffers[type] == 0) { CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name); return 0; diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c index 03dc9924fa2c..25d0d6745b52 100644 --- a/drivers/media/pci/ddbridge/ddbridge-main.c +++ b/drivers/media/pci/ddbridge/ddbridge-main.c @@ -180,8 +180,8 @@ static int ddb_probe(struct pci_dev *pdev, pci_set_master(pdev); - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) return -ENODEV; dev = vzalloc(sizeof(*dev)); diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index 8bcba168cc57..98cb3bc834db 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -1752,7 +1752,7 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, pci_set_master(pci_dev); - r = pci_set_dma_mask(pci_dev, CIO2_DMA_MASK); + r = dma_set_mask(&pci_dev->dev, CIO2_DMA_MASK); if (r) { dev_err(dev, "failed to set DMA mask (%d)\n", r); return -ENODEV; diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index 77bae1468551..8287851b5ffd 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -846,7 +846,7 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev, "%s(): board vendor 0x%x, revision 0x%x\n", __func__, board_vendor, board_revision); pci_set_master(pci_dev); - if (pci_set_dma_mask(pci_dev, 0xffffffff) < 0) { + if (dma_set_mask(&pci_dev->dev, 0xffffffff) < 0) { dev_err(&pci_dev->dev, "%s(): 32bit PCI DMA is not supported\n", __func__); goto pci_detect_err; diff --git a/drivers/media/pci/pluto2/pluto2.c b/drivers/media/pci/pluto2/pluto2.c index f1f4793a4452..6ac9b9bd7435 100644 --- a/drivers/media/pci/pluto2/pluto2.c +++ b/drivers/media/pci/pluto2/pluto2.c @@ -228,16 +228,16 @@ static void pluto_set_dma_addr(struct pluto *pluto) static int pluto_dma_map(struct pluto *pluto) { - pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf, - TS_DMA_BYTES, PCI_DMA_FROMDEVICE); + pluto->dma_addr = dma_map_single(&pluto->pdev->dev, pluto->dma_buf, + TS_DMA_BYTES, DMA_FROM_DEVICE); - return pci_dma_mapping_error(pluto->pdev, pluto->dma_addr); + return dma_mapping_error(&pluto->pdev->dev, pluto->dma_addr); } static void pluto_dma_unmap(struct pluto *pluto) { - pci_unmap_single(pluto->pdev, pluto->dma_addr, - TS_DMA_BYTES, PCI_DMA_FROMDEVICE); + dma_unmap_single(&pluto->pdev->dev, pluto->dma_addr, TS_DMA_BYTES, + DMA_FROM_DEVICE); } static int pluto_start_feed(struct dvb_demux_feed *f) @@ -276,8 +276,8 @@ static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets) { /* synchronize the DMA transfer with the CPU * first so that we see updated contents. */ - pci_dma_sync_single_for_cpu(pluto->pdev, pluto->dma_addr, - TS_DMA_BYTES, PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&pluto->pdev->dev, pluto->dma_addr, + TS_DMA_BYTES, DMA_FROM_DEVICE); /* Workaround for broken hardware: * [1] On startup NBPACKETS seems to contain an uninitialized value, @@ -310,8 +310,8 @@ static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets) pluto_set_dma_addr(pluto); /* sync the buffer and give it back to the card */ - pci_dma_sync_single_for_device(pluto->pdev, pluto->dma_addr, - TS_DMA_BYTES, PCI_DMA_FROMDEVICE); + dma_sync_single_for_device(&pluto->pdev->dev, pluto->dma_addr, + TS_DMA_BYTES, DMA_FROM_DEVICE); } static irqreturn_t pluto_irq(int irq, void *dev_id) @@ -595,7 +595,7 @@ static int pluto2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* enable interrupts */ pci_write_config_dword(pdev, 0x6c, 0x8000); - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret < 0) goto err_pci_disable_device; diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c index f2aa36814fba..121a4a92ea10 100644 --- a/drivers/media/pci/pt1/pt1.c +++ b/drivers/media/pci/pt1/pt1.c @@ -1340,7 +1340,7 @@ static int pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret < 0) goto err; - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret < 0) goto err_pci_disable_device; diff --git a/drivers/media/pci/tw5864/tw5864-core.c b/drivers/media/pci/tw5864/tw5864-core.c index 282f7dfb7aaf..23d3cae54a5d 100644 --- a/drivers/media/pci/tw5864/tw5864-core.c +++ b/drivers/media/pci/tw5864/tw5864-core.c @@ -262,7 +262,7 @@ static int tw5864_initdev(struct pci_dev *pci_dev, pci_set_master(pci_dev); - err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); if (err) { dev_err(&dev->pci->dev, "32 bit PCI DMA is not supported\n"); goto disable_pci; -- cgit v1.2.3 From 012fe9520e827f92997855a37eca69573c63672a Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Mon, 23 Aug 2021 14:29:56 +0200 Subject: media: vim2m: Remove repeated verbose license text remove it because SPDX-License-Identifier is already used Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vim2m.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c index d714fe50afe5..47575490e74a 100644 --- a/drivers/media/test-drivers/vim2m.c +++ b/drivers/media/test-drivers/vim2m.c @@ -12,11 +12,6 @@ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. * Pawel Osciak, * Marek Szyprowski, - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the - * License, or (at your option) any later version */ #include #include -- cgit v1.2.3 From 695fb9c6b06417b26e4c9d70a12b0a6d3805dee6 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 25 Aug 2021 02:23:37 +0200 Subject: media: Request API is no longer experimental The Request API is currently used and specified as part of the Memory-to-memory Stateless Video Decoder Interface [1]. This can now be considered as non-experimental and stable, given the decoder API has been used by products since a couple years, supported by several drivers and userspace frameworks, [1] Documentation/userspace-api/media/v4l/dev-stateless-decoder.rst Signed-off-by: Ezequiel Garcia Acked-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/mc/Kconfig | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/media/mc/Kconfig b/drivers/media/mc/Kconfig index 4815b9dde9af..375b09612981 100644 --- a/drivers/media/mc/Kconfig +++ b/drivers/media/mc/Kconfig @@ -16,13 +16,5 @@ config MEDIA_CONTROLLER_REQUEST_API bool depends on MEDIA_CONTROLLER help - DO NOT ENABLE THIS OPTION UNLESS YOU KNOW WHAT YOU'RE DOING. - This option enables the Request API for the Media controller and V4L2 interfaces. It is currently needed by a few stateless codec drivers. - - There is currently no intention to provide API or ABI stability for - this new API as of yet. - -comment "Please notice that the enabled Media controller Request API is EXPERIMENTAL" - depends on MEDIA_CONTROLLER_REQUEST_API -- cgit v1.2.3 From c6c709ee55ec73a0d794cac4c711b8078f71b884 Mon Sep 17 00:00:00 2001 From: Deborah Brouwer Date: Thu, 26 Aug 2021 05:44:11 +0200 Subject: media: vivid: add signal-free time for cec message xfer Currently, the vivid emulation of cec message transmission does not force adapters to wait until the cec bus has been signal-free for a certain number of bit periods before transmitting or re-transmitting a message. Without enforcing the signal-free time requirements, adapters do not share the bus very well and some messages are sent too quickly while other messages are lost. By emulating a signal-free time and forcing adapters to wait their turn to transmit, the vivid emulation of cec transmission is much more reliable. Signed-off-by: Deborah Brouwer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vivid/vivid-cec.c | 341 ++++++++++++++------------ drivers/media/test-drivers/vivid/vivid-cec.h | 9 +- drivers/media/test-drivers/vivid/vivid-core.c | 38 ++- drivers/media/test-drivers/vivid/vivid-core.h | 23 +- 4 files changed, 219 insertions(+), 192 deletions(-) diff --git a/drivers/media/test-drivers/vivid/vivid-cec.c b/drivers/media/test-drivers/vivid/vivid-cec.c index 55ea039fe5b2..1f7469ff04d5 100644 --- a/drivers/media/test-drivers/vivid/vivid-cec.c +++ b/drivers/media/test-drivers/vivid/vivid-cec.c @@ -5,40 +5,23 @@ * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. */ +#include #include #include "vivid-core.h" #include "vivid-cec.h" -#define CEC_TIM_START_BIT_TOTAL 4500 -#define CEC_TIM_START_BIT_LOW 3700 -#define CEC_TIM_START_BIT_HIGH 800 -#define CEC_TIM_DATA_BIT_TOTAL 2400 -#define CEC_TIM_DATA_BIT_0_LOW 1500 -#define CEC_TIM_DATA_BIT_0_HIGH 900 -#define CEC_TIM_DATA_BIT_1_LOW 600 -#define CEC_TIM_DATA_BIT_1_HIGH 1800 +#define CEC_START_BIT_US 4500 +#define CEC_DATA_BIT_US 2400 +#define CEC_MARGIN_US 350 -void vivid_cec_bus_free_work(struct vivid_dev *dev) -{ - spin_lock(&dev->cec_slock); - while (!list_empty(&dev->cec_work_list)) { - struct vivid_cec_work *cw = - list_first_entry(&dev->cec_work_list, - struct vivid_cec_work, list); - - spin_unlock(&dev->cec_slock); - cancel_delayed_work_sync(&cw->work); - spin_lock(&dev->cec_slock); - list_del(&cw->list); - cec_transmit_attempt_done(cw->adap, CEC_TX_STATUS_LOW_DRIVE); - kfree(cw); - } - spin_unlock(&dev->cec_slock); -} +struct xfer_on_bus { + struct cec_adapter *adap; + u8 status; +}; -static bool vivid_cec_find_dest_adap(struct vivid_dev *dev, - struct cec_adapter *adap, u8 dest) +static bool find_dest_adap(struct vivid_dev *dev, + struct cec_adapter *adap, u8 dest) { unsigned int i; @@ -61,116 +44,187 @@ static bool vivid_cec_find_dest_adap(struct vivid_dev *dev, return false; } -static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts, - const struct cec_msg *msg, bool nacked) +static bool xfer_ready(struct vivid_dev *dev) { - unsigned int len = nacked ? 1 : msg->len; unsigned int i; - bool bit; - - if (adap == NULL) - return; + bool ready = false; - /* - * Suffix ULL on constant 10 makes the expression - * CEC_TIM_START_BIT_TOTAL + 10ULL * len * CEC_TIM_DATA_BIT_TOTAL - * to be evaluated using 64-bit unsigned arithmetic (u64), which - * is what ktime_sub_us expects as second argument. - */ - ts = ktime_sub_us(ts, CEC_TIM_START_BIT_TOTAL + - 10ULL * len * CEC_TIM_DATA_BIT_TOTAL); - cec_queue_pin_cec_event(adap, false, false, ts); - ts = ktime_add_us(ts, CEC_TIM_START_BIT_LOW); - cec_queue_pin_cec_event(adap, true, false, ts); - ts = ktime_add_us(ts, CEC_TIM_START_BIT_HIGH); - - for (i = 0; i < 10 * len; i++) { - switch (i % 10) { - case 0 ... 7: - bit = msg->msg[i / 10] & (0x80 >> (i % 10)); - break; - case 8: /* EOM */ - bit = i / 10 == msg->len - 1; - break; - case 9: /* ACK */ - bit = cec_msg_is_broadcast(msg) ^ nacked; + spin_lock(&dev->cec_xfers_slock); + for (i = 0; i < ARRAY_SIZE(dev->xfers); i++) { + if (dev->xfers[i].sft && + dev->xfers[i].sft <= dev->cec_sft) { + ready = true; break; } - cec_queue_pin_cec_event(adap, false, false, ts); - if (bit) - ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_LOW); - else - ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_LOW); - cec_queue_pin_cec_event(adap, true, false, ts); - if (bit) - ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_HIGH); - else - ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_HIGH); } -} + spin_unlock(&dev->cec_xfers_slock); -static void vivid_cec_pin_events(struct vivid_dev *dev, - const struct cec_msg *msg, bool nacked) -{ - ktime_t ts = ktime_get(); - unsigned int i; - - vivid_cec_pin_adap_events(dev->cec_rx_adap, ts, msg, nacked); - for (i = 0; i < MAX_OUTPUTS; i++) - vivid_cec_pin_adap_events(dev->cec_tx_adap[i], ts, msg, nacked); + return ready; } -static void vivid_cec_xfer_done_worker(struct work_struct *work) +/* + * If an adapter tries to send successive messages, it must wait for the + * longest signal-free time between its transmissions. But, if another + * adapter sends a message in the interim, then the wait can be reduced + * because the messages are no longer successive. Make these adjustments + * if necessary. Should be called holding cec_xfers_slock. + */ +static void adjust_sfts(struct vivid_dev *dev) { - struct vivid_cec_work *cw = - container_of(work, struct vivid_cec_work, work.work); - struct vivid_dev *dev = cw->dev; - struct cec_adapter *adap = cw->adap; - u8 dest = cec_msg_destination(&cw->msg); - bool valid_dest; unsigned int i; + u8 initiator; - valid_dest = cec_msg_is_broadcast(&cw->msg); - if (!valid_dest) - valid_dest = vivid_cec_find_dest_adap(dev, adap, dest); - - cw->tx_status = valid_dest ? CEC_TX_STATUS_OK : CEC_TX_STATUS_NACK; - spin_lock(&dev->cec_slock); - dev->cec_xfer_time_jiffies = 0; - dev->cec_xfer_start_jiffies = 0; - list_del(&cw->list); - spin_unlock(&dev->cec_slock); - vivid_cec_pin_events(dev, &cw->msg, !valid_dest); - cec_transmit_attempt_done(cw->adap, cw->tx_status); - - /* Broadcast message */ - if (adap != dev->cec_rx_adap) - cec_received_msg(dev->cec_rx_adap, &cw->msg); - for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) - if (adap != dev->cec_tx_adap[i]) - cec_received_msg(dev->cec_tx_adap[i], &cw->msg); - kfree(cw); + for (i = 0; i < ARRAY_SIZE(dev->xfers); i++) { + if (dev->xfers[i].sft <= CEC_SIGNAL_FREE_TIME_RETRY) + continue; + initiator = dev->xfers[i].msg[0] >> 4; + if (initiator == dev->last_initiator) + dev->xfers[i].sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER; + else + dev->xfers[i].sft = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR; + } } -static void vivid_cec_xfer_try_worker(struct work_struct *work) +/* + * The main emulation of the bus on which CEC adapters attempt to send + * messages to each other. The bus keeps track of how long it has been + * signal-free and accepts a pending transmission only if the state of + * the bus matches the transmission's signal-free requirements. It calls + * cec_transmit_attempt_done() for all transmits that enter the bus and + * cec_received_msg() for successful transmits. + */ +int vivid_cec_bus_thread(void *_dev) { - struct vivid_cec_work *cw = - container_of(work, struct vivid_cec_work, work.work); - struct vivid_dev *dev = cw->dev; - - spin_lock(&dev->cec_slock); - if (dev->cec_xfer_time_jiffies) { - list_del(&cw->list); - spin_unlock(&dev->cec_slock); - cec_transmit_attempt_done(cw->adap, CEC_TX_STATUS_ARB_LOST); - kfree(cw); - } else { - INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_done_worker); - dev->cec_xfer_start_jiffies = jiffies; - dev->cec_xfer_time_jiffies = usecs_to_jiffies(cw->usecs); - spin_unlock(&dev->cec_slock); - schedule_delayed_work(&cw->work, dev->cec_xfer_time_jiffies); + u32 last_sft; + unsigned int i; + unsigned int dest; + ktime_t start, end; + s64 delta_us, retry_us; + struct vivid_dev *dev = _dev; + + dev->cec_sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER; + for (;;) { + bool first = true; + int wait_xfer_us = 0; + bool valid_dest = false; + int wait_arb_lost_us = 0; + unsigned int first_idx = 0; + unsigned int first_status = 0; + struct cec_msg first_msg = {}; + struct xfer_on_bus xfers_on_bus[MAX_OUTPUTS] = {}; + + wait_event_interruptible(dev->kthread_waitq_cec, xfer_ready(dev) || + kthread_should_stop()); + if (kthread_should_stop()) + break; + last_sft = dev->cec_sft; + dev->cec_sft = 0; + /* + * Move the messages that are ready onto the bus. The adapter with + * the most leading zeros will win control of the bus and any other + * adapters will lose arbitration. + */ + spin_lock(&dev->cec_xfers_slock); + for (i = 0; i < ARRAY_SIZE(dev->xfers); i++) { + if (!dev->xfers[i].sft || dev->xfers[i].sft > last_sft) + continue; + if (first) { + first = false; + first_idx = i; + xfers_on_bus[first_idx].adap = dev->xfers[i].adap; + memcpy(first_msg.msg, dev->xfers[i].msg, dev->xfers[i].len); + first_msg.len = dev->xfers[i].len; + } else { + xfers_on_bus[i].adap = dev->xfers[i].adap; + xfers_on_bus[i].status = CEC_TX_STATUS_ARB_LOST; + /* + * For simplicity wait for all 4 bits of the initiator's + * address even though HDMI specification uses bit-level + * precision. + */ + wait_arb_lost_us = 4 * CEC_DATA_BIT_US + CEC_START_BIT_US; + } + dev->xfers[i].sft = 0; + } + dev->last_initiator = cec_msg_initiator(&first_msg); + adjust_sfts(dev); + spin_unlock(&dev->cec_xfers_slock); + + dest = cec_msg_destination(&first_msg); + valid_dest = cec_msg_is_broadcast(&first_msg); + if (!valid_dest) + valid_dest = find_dest_adap(dev, xfers_on_bus[first_idx].adap, dest); + if (valid_dest) { + first_status = CEC_TX_STATUS_OK; + /* + * Message length is in bytes, but each byte is transmitted in + * a block of 10 bits. + */ + wait_xfer_us = first_msg.len * 10 * CEC_DATA_BIT_US; + } else { + first_status = CEC_TX_STATUS_NACK; + /* + * A message that is not acknowledged stops transmitting after + * the header block of 10 bits. + */ + wait_xfer_us = 10 * CEC_DATA_BIT_US; + } + wait_xfer_us += CEC_START_BIT_US; + xfers_on_bus[first_idx].status = first_status; + + /* Sleep as if sending messages on a real hardware bus. */ + start = ktime_get(); + if (wait_arb_lost_us) { + usleep_range(wait_arb_lost_us - CEC_MARGIN_US, wait_arb_lost_us); + for (i = 0; i < ARRAY_SIZE(xfers_on_bus); i++) { + if (xfers_on_bus[i].status != CEC_TX_STATUS_ARB_LOST) + continue; + cec_transmit_attempt_done(xfers_on_bus[i].adap, + CEC_TX_STATUS_ARB_LOST); + } + if (kthread_should_stop()) + break; + } + wait_xfer_us -= wait_arb_lost_us; + usleep_range(wait_xfer_us - CEC_MARGIN_US, wait_xfer_us); + cec_transmit_attempt_done(xfers_on_bus[first_idx].adap, first_status); + if (kthread_should_stop()) + break; + if (first_status == CEC_TX_STATUS_OK) { + if (xfers_on_bus[first_idx].adap != dev->cec_rx_adap) + cec_received_msg(dev->cec_rx_adap, &first_msg); + for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) + if (xfers_on_bus[first_idx].adap != dev->cec_tx_adap[i]) + cec_received_msg(dev->cec_tx_adap[i], &first_msg); + } + end = ktime_get(); + /* + * If the emulated transfer took more or less time than it should + * have, then compensate by adjusting the wait time needed for the + * bus to be signal-free for 3 bit periods (the retry time). + */ + delta_us = div_s64(end - start, 1000); + delta_us -= wait_xfer_us + wait_arb_lost_us; + retry_us = CEC_SIGNAL_FREE_TIME_RETRY * CEC_DATA_BIT_US - delta_us; + if (retry_us > CEC_MARGIN_US) + usleep_range(retry_us - CEC_MARGIN_US, retry_us); + dev->cec_sft = CEC_SIGNAL_FREE_TIME_RETRY; + /* + * If there are no messages that need to be retried, check if any + * adapters that did not just transmit a message are ready to + * transmit. If none of these adapters are ready, then increase + * the signal-free time so that the bus is available to all + * adapters and go back to waiting for a transmission. + */ + while (dev->cec_sft >= CEC_SIGNAL_FREE_TIME_RETRY && + dev->cec_sft < CEC_SIGNAL_FREE_TIME_NEXT_XFER && + !xfer_ready(dev) && !kthread_should_stop()) { + usleep_range(2 * CEC_DATA_BIT_US - CEC_MARGIN_US, + 2 * CEC_DATA_BIT_US); + dev->cec_sft += 2; + } } + return 0; } static int vivid_cec_adap_enable(struct cec_adapter *adap, bool enable) @@ -184,41 +238,26 @@ static int vivid_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) return 0; } -/* - * One data bit takes 2400 us, each byte needs 10 bits so that's 24000 us - * per byte. - */ -#define USECS_PER_BYTE 24000 - static int vivid_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, u32 signal_free_time, struct cec_msg *msg) { struct vivid_dev *dev = cec_get_drvdata(adap); - struct vivid_cec_work *cw = kzalloc(sizeof(*cw), GFP_KERNEL); - long delta_jiffies = 0; - - if (cw == NULL) - return -ENOMEM; - cw->dev = dev; - cw->adap = adap; - cw->usecs = CEC_FREE_TIME_TO_USEC(signal_free_time) + - msg->len * USECS_PER_BYTE; - cw->msg = *msg; - - spin_lock(&dev->cec_slock); - list_add(&cw->list, &dev->cec_work_list); - if (dev->cec_xfer_time_jiffies == 0) { - INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_done_worker); - dev->cec_xfer_start_jiffies = jiffies; - dev->cec_xfer_time_jiffies = usecs_to_jiffies(cw->usecs); - delta_jiffies = dev->cec_xfer_time_jiffies; - } else { - INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_try_worker); - delta_jiffies = dev->cec_xfer_start_jiffies + - dev->cec_xfer_time_jiffies - jiffies; + u8 idx = cec_msg_initiator(msg); + + spin_lock(&dev->cec_xfers_slock); + dev->xfers[idx].adap = adap; + memcpy(dev->xfers[idx].msg, msg->msg, CEC_MAX_MSG_SIZE); + dev->xfers[idx].len = msg->len; + dev->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_RETRY; + if (signal_free_time > CEC_SIGNAL_FREE_TIME_RETRY) { + if (idx == dev->last_initiator) + dev->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER; + else + dev->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR; } - spin_unlock(&dev->cec_slock); - schedule_delayed_work(&cw->work, delta_jiffies < 0 ? 0 : delta_jiffies); + spin_unlock(&dev->cec_xfers_slock); + wake_up_interruptible(&dev->kthread_waitq_cec); + return 0; } diff --git a/drivers/media/test-drivers/vivid/vivid-cec.h b/drivers/media/test-drivers/vivid/vivid-cec.h index 7524ed48a914..b2bcddb50b83 100644 --- a/drivers/media/test-drivers/vivid/vivid-cec.h +++ b/drivers/media/test-drivers/vivid/vivid-cec.h @@ -9,12 +9,5 @@ struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, unsigned int idx, bool is_source); -void vivid_cec_bus_free_work(struct vivid_dev *dev); - -#else - -static inline void vivid_cec_bus_free_work(struct vivid_dev *dev) -{ -} - +int vivid_cec_bus_thread(void *_dev); #endif diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index 87f27c7524ec..bcf03bea1e3c 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -1888,18 +1888,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) INIT_LIST_HEAD(&dev->meta_out_active); INIT_LIST_HEAD(&dev->touch_cap_active); - INIT_LIST_HEAD(&dev->cec_work_list); - spin_lock_init(&dev->cec_slock); - /* - * Same as create_singlethread_workqueue, but now I can use the - * string formatting of alloc_ordered_workqueue. - */ - dev->cec_workqueue = alloc_ordered_workqueue("vivid-%03d-cec", - WQ_MEM_RECLAIM, inst); - if (!dev->cec_workqueue) { - ret = -ENOMEM; - goto unreg_dev; - } + spin_lock_init(&dev->cec_xfers_slock); if (allocators[inst] == 1) dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); @@ -1939,6 +1928,19 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) cec_tx_bus_cnt++; } } + + if (dev->cec_rx_adap || cec_tx_bus_cnt) { + init_waitqueue_head(&dev->kthread_waitq_cec); + dev->kthread_cec = kthread_run(vivid_cec_bus_thread, dev, + "vivid_cec-%s", dev->v4l2_dev.name); + if (IS_ERR(dev->kthread_cec)) { + dev->kthread_cec = NULL; + v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); + ret = PTR_ERR(dev->kthread_cec); + goto unreg_dev; + } + } + #endif v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap); @@ -1978,10 +1980,8 @@ unreg_dev: cec_unregister_adapter(dev->cec_rx_adap); for (i = 0; i < MAX_OUTPUTS; i++) cec_unregister_adapter(dev->cec_tx_adap[i]); - if (dev->cec_workqueue) { - vivid_cec_bus_free_work(dev); - destroy_workqueue(dev->cec_workqueue); - } + if (dev->kthread_cec) + kthread_stop(dev->kthread_cec); free_dev: v4l2_device_put(&dev->v4l2_dev); return ret; @@ -2103,10 +2103,8 @@ static int vivid_remove(struct platform_device *pdev) cec_unregister_adapter(dev->cec_rx_adap); for (j = 0; j < MAX_OUTPUTS; j++) cec_unregister_adapter(dev->cec_tx_adap[j]); - if (dev->cec_workqueue) { - vivid_cec_bus_free_work(dev); - destroy_workqueue(dev->cec_workqueue); - } + if (dev->kthread_cec) + kthread_stop(dev->kthread_cec); v4l2_device_put(&dev->v4l2_dev); vivid_devs[i] = NULL; } diff --git a/drivers/media/test-drivers/vivid/vivid-core.h b/drivers/media/test-drivers/vivid/vivid-core.h index 1e3c4f5a9413..45f96706edde 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.h +++ b/drivers/media/test-drivers/vivid/vivid-core.h @@ -110,15 +110,11 @@ enum vivid_colorspace { #define VIVID_INVALID_SIGNAL(mode) \ ((mode) == NO_SIGNAL || (mode) == NO_LOCK || (mode) == OUT_OF_RANGE) -struct vivid_cec_work { - struct list_head list; - struct delayed_work work; +struct vivid_cec_xfer { struct cec_adapter *adap; - struct vivid_dev *dev; - unsigned int usecs; - unsigned int timeout_ms; - u8 tx_status; - struct cec_msg msg; + u8 msg[CEC_MAX_MSG_SIZE]; + u32 len; + u32 sft; }; struct vivid_dev { @@ -560,12 +556,13 @@ struct vivid_dev { /* CEC */ struct cec_adapter *cec_rx_adap; struct cec_adapter *cec_tx_adap[MAX_OUTPUTS]; - struct workqueue_struct *cec_workqueue; - spinlock_t cec_slock; - struct list_head cec_work_list; - unsigned int cec_xfer_time_jiffies; - unsigned long cec_xfer_start_jiffies; u8 cec_output2bus_map[MAX_OUTPUTS]; + struct task_struct *kthread_cec; + wait_queue_head_t kthread_waitq_cec; + struct vivid_cec_xfer xfers[MAX_OUTPUTS]; + spinlock_t cec_xfers_slock; /* read and write cec messages */ + u32 cec_sft; /* bus signal free time, in bit periods */ + u8 last_initiator; /* CEC OSD String */ char osd[14]; -- cgit v1.2.3 From 1e6494daaf094afd6b03bbc87d9af70d6c378cfc Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 26 Aug 2021 20:38:18 +0200 Subject: media: imx7.rst: Provide an example for imx6ull-evk capture imx6ull-evk has a parallel OV5640 sensor. Provide an example for imx6ull-evk capture to improve the document. Signed-off-by: Fabio Estevam Acked-by: Rui Miguel Silva Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/admin-guide/media/imx7.rst | 60 ++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/Documentation/admin-guide/media/imx7.rst b/Documentation/admin-guide/media/imx7.rst index 1e442c97da47..4785ae8ac978 100644 --- a/Documentation/admin-guide/media/imx7.rst +++ b/Documentation/admin-guide/media/imx7.rst @@ -155,6 +155,66 @@ the resolutions supported by the sensor. [fmt:SBGGR10_1X10/800x600@1/30 field:none colorspace:srgb] -> "imx7-mipi-csis.0":0 [ENABLED] +i.MX6ULL-EVK with OV5640 +------------------------ + +On this platform a parallel OV5640 sensor is connected to the CSI port. +The following example configures a video capture pipeline with an output +of 640x480 and UYVY8_2X8 format: + +.. code-block:: none + + # Setup links + media-ctl -l "'ov5640 1-003c':0 -> 'csi':0[1]" + media-ctl -l "'csi':1 -> 'csi capture':0[1]" + + # Configure pads for pipeline + media-ctl -v -V "'ov5640 1-003c':0 [fmt:UYVY8_2X8/640x480 field:none]" + +After this streaming can start: + +.. code-block:: none + + gst-launch-1.0 -v v4l2src device=/dev/video1 ! video/x-raw,format=UYVY,width=640,height=480 ! v4l2convert ! fbdevsink + +.. code-block:: none + + # media-ctl -p + Media controller API version 5.14.0 + + Media device information + ------------------------ + driver imx7-csi + model imx-media + serial + bus info + hw revision 0x0 + driver version 5.14.0 + + Device topology + - entity 1: csi (2 pads, 2 links) + type V4L2 subdev subtype Unknown flags 0 + device node name /dev/v4l-subdev0 + pad0: Sink + [fmt:UYVY8_2X8/640x480 field:none colorspace:srgb xfer:srgb ycbcr:601 quantization:full-range] + <- "ov5640 1-003c":0 [ENABLED,IMMUTABLE] + pad1: Source + [fmt:UYVY8_2X8/640x480 field:none colorspace:srgb xfer:srgb ycbcr:601 quantization:full-range] + -> "csi capture":0 [ENABLED,IMMUTABLE] + + - entity 4: csi capture (1 pad, 1 link) + type Node subtype V4L flags 0 + device node name /dev/video1 + pad0: Sink + <- "csi":1 [ENABLED,IMMUTABLE] + + - entity 10: ov5640 1-003c (1 pad, 1 link) + type V4L2 subdev subtype Sensor flags 0 + device node name /dev/v4l-subdev1 + pad0: Source + [fmt:UYVY8_2X8/640x480@1/30 field:none colorspace:srgb xfer:srgb ycbcr:601 quantization:full-range] + -> "csi":0 [ENABLED,IMMUTABLE] + References ---------- -- cgit v1.2.3 From b94b551050b2aad898f87cb78c5e84d3e3e049f2 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 26 Aug 2021 20:38:19 +0200 Subject: media: imx: TODO: Remove items that are already supported Video capture has been successfully tested using an OV5640 parallel sensor on a imx6ull-evk board at a 640x480 resolution and UYVY8_2X8 format. Remove the two items that are no longer pending. Signed-off-by: Fabio Estevam Acked-by: Rui Miguel Silva Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/TODO | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/staging/media/imx/TODO b/drivers/staging/media/imx/TODO index 2384f4c6b09d..06c94f20ecf8 100644 --- a/drivers/staging/media/imx/TODO +++ b/drivers/staging/media/imx/TODO @@ -27,8 +27,3 @@ - i.MX7: all of the above, since it uses the imx media core - i.MX7: use Frame Interval Monitor - -- i.MX7: runtime testing with parallel sensor, links setup and streaming - -- i.MX7: runtime testing with different formats, for the time only 10-bit bayer - is tested -- cgit v1.2.3 From 936c7daa4d99c0c5d10c97cb9afc28966d547d80 Mon Sep 17 00:00:00 2001 From: Chad Fraleigh Date: Mon, 30 Aug 2021 01:51:27 +0200 Subject: media: gspca: Limit frame size to sizeimage. Limit frame size to what userland code expects. This can happen when cameras, such as Kensington VideoCAM, use fixed sized transfer packets which includes trailing junk in the final packet. Signed-off-by: Chad Fraleigh Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/gspca.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 47d8f28bfdfc..770714c34295 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -444,6 +444,8 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, * next first packet, wake up the application and advance * in the queue */ if (packet_type == LAST_PACKET) { + if (gspca_dev->image_len > gspca_dev->pixfmt.sizeimage) + gspca_dev->image_len = gspca_dev->pixfmt.sizeimage; spin_lock_irqsave(&gspca_dev->qlock, flags); list_del(&buf->list); spin_unlock_irqrestore(&gspca_dev->qlock, flags); -- cgit v1.2.3 From 745b475e7e10ae1e8c538e5db89494411ee1c22b Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Thu, 12 Aug 2021 11:21:52 +0200 Subject: media: camss: vfe: Don't call hw_version() before its dependencies are met vfe->ops->hw_version(vfe) is being called before vfe->base has been assigned, and before the hardware has been powered up. Fixes: b10b5334528a9 ("media: camss: vfe: Don't read hardware version needlessly") Reported-by: Linux Kernel Functional Testing Reported-by: Marek Szyprowski Signed-off-by: Robert Foss Tested-by: Marek Szyprowski Reviewed-by: Marek Szyprowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-vfe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 6b2f33fc9be2..71f78b40e7f5 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -604,6 +604,8 @@ static int vfe_get(struct vfe_device *vfe) vfe_reset_output_maps(vfe); vfe_init_outputs(vfe); + + vfe->ops->hw_version(vfe); } else { ret = vfe_check_clock_rates(vfe); if (ret < 0) @@ -1299,7 +1301,6 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, return -EINVAL; } vfe->ops->subdev_init(dev, vfe); - vfe->ops->hw_version(vfe); /* Memory */ -- cgit v1.2.3 From a4b83deb3e76fb9385ca58e2c072a145b3a320d6 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 9 Sep 2021 13:24:23 +0200 Subject: media: videobuf2: rework vb2_mem_ops API With the new DMA API we need an extension of the videobuf2 API. Previously, videobuf2 core would set the non-coherent DMA bit in the vb2_queue dma_attr field (if user-space would pass a corresponding memory hint); the vb2 core then would pass the vb2_queue dma_attrs to the vb2 allocators. The vb2 allocator would use the queue's dma_attr and the DMA API would allocate either coherent or non-coherent memory. But we cannot do this anymore, since there is no corresponding DMA attr flag and, hence, there is no way for the allocator to become aware of what type of allocation user-space has requested. So we need to pass more context from videobuf2 core to the allocators. Fix this by changing the call_ptr_memop() macro to pass the vb2 pointer to the corresponding op callbacks. Signed-off-by: Sergey Senozhatsky Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-core.c | 42 ++++++++++++---------- .../media/common/videobuf2/videobuf2-dma-contig.c | 36 +++++++++++-------- drivers/media/common/videobuf2/videobuf2-dma-sg.c | 33 +++++++++-------- drivers/media/common/videobuf2/videobuf2-vmalloc.c | 30 ++++++++-------- include/media/videobuf2-core.h | 37 +++++++++---------- 5 files changed, 98 insertions(+), 80 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 38ce7c274727..c4ff356da600 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -68,13 +68,13 @@ module_param(debug, int, 0644); err; \ }) -#define call_ptr_memop(vb, op, args...) \ +#define call_ptr_memop(op, vb, args...) \ ({ \ struct vb2_queue *_q = (vb)->vb2_queue; \ void *ptr; \ \ log_memop(vb, op); \ - ptr = _q->mem_ops->op ? _q->mem_ops->op(args) : NULL; \ + ptr = _q->mem_ops->op ? _q->mem_ops->op(vb, args) : NULL; \ if (!IS_ERR_OR_NULL(ptr)) \ (vb)->cnt_mem_ ## op++; \ ptr; \ @@ -144,9 +144,9 @@ module_param(debug, int, 0644); ((vb)->vb2_queue->mem_ops->op ? \ (vb)->vb2_queue->mem_ops->op(args) : 0) -#define call_ptr_memop(vb, op, args...) \ +#define call_ptr_memop(op, vb, args...) \ ((vb)->vb2_queue->mem_ops->op ? \ - (vb)->vb2_queue->mem_ops->op(args) : NULL) + (vb)->vb2_queue->mem_ops->op(vb, args) : NULL) #define call_void_memop(vb, op, args...) \ do { \ @@ -230,9 +230,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) if (size < vb->planes[plane].length) goto free; - mem_priv = call_ptr_memop(vb, alloc, - q->alloc_devs[plane] ? : q->dev, - q->dma_attrs, size, q->dma_dir, q->gfp_flags); + mem_priv = call_ptr_memop(alloc, + vb, + q->alloc_devs[plane] ? : q->dev, + size); if (IS_ERR_OR_NULL(mem_priv)) { if (mem_priv) ret = PTR_ERR(mem_priv); @@ -975,7 +976,7 @@ void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no) if (plane_no >= vb->num_planes || !vb->planes[plane_no].mem_priv) return NULL; - return call_ptr_memop(vb, vaddr, vb->planes[plane_no].mem_priv); + return call_ptr_memop(vaddr, vb, vb->planes[plane_no].mem_priv); } EXPORT_SYMBOL_GPL(vb2_plane_vaddr); @@ -985,7 +986,7 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) if (plane_no >= vb->num_planes || !vb->planes[plane_no].mem_priv) return NULL; - return call_ptr_memop(vb, cookie, vb->planes[plane_no].mem_priv); + return call_ptr_memop(cookie, vb, vb->planes[plane_no].mem_priv); } EXPORT_SYMBOL_GPL(vb2_plane_cookie); @@ -1125,10 +1126,11 @@ static int __prepare_userptr(struct vb2_buffer *vb) vb->planes[plane].data_offset = 0; /* Acquire each plane's memory */ - mem_priv = call_ptr_memop(vb, get_userptr, - q->alloc_devs[plane] ? : q->dev, - planes[plane].m.userptr, - planes[plane].length, q->dma_dir); + mem_priv = call_ptr_memop(get_userptr, + vb, + q->alloc_devs[plane] ? : q->dev, + planes[plane].m.userptr, + planes[plane].length); if (IS_ERR(mem_priv)) { dprintk(q, 1, "failed acquiring userspace memory for plane %d\n", plane); @@ -1249,9 +1251,11 @@ static int __prepare_dmabuf(struct vb2_buffer *vb) vb->planes[plane].data_offset = 0; /* Acquire each plane's memory */ - mem_priv = call_ptr_memop(vb, attach_dmabuf, - q->alloc_devs[plane] ? : q->dev, - dbuf, planes[plane].length, q->dma_dir); + mem_priv = call_ptr_memop(attach_dmabuf, + vb, + q->alloc_devs[plane] ? : q->dev, + dbuf, + planes[plane].length); if (IS_ERR(mem_priv)) { dprintk(q, 1, "failed to attach dmabuf\n"); ret = PTR_ERR(mem_priv); @@ -2197,8 +2201,10 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, vb_plane = &vb->planes[plane]; - dbuf = call_ptr_memop(vb, get_dmabuf, vb_plane->mem_priv, - flags & O_ACCMODE); + dbuf = call_ptr_memop(get_dmabuf, + vb, + vb_plane->mem_priv, + flags & O_ACCMODE); if (IS_ERR_OR_NULL(dbuf)) { dprintk(q, 1, "failed to export buffer %d, plane %d\n", index, plane); diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index a7f61ba85440..019c3843dc6d 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -40,6 +40,8 @@ struct vb2_dc_buf { /* DMABUF related */ struct dma_buf_attachment *db_attach; + + struct vb2_buffer *vb; }; /*********************************************/ @@ -66,14 +68,14 @@ static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt) /* callbacks for all buffers */ /*********************************************/ -static void *vb2_dc_cookie(void *buf_priv) +static void *vb2_dc_cookie(struct vb2_buffer *vb, void *buf_priv) { struct vb2_dc_buf *buf = buf_priv; return &buf->dma_addr; } -static void *vb2_dc_vaddr(void *buf_priv) +static void *vb2_dc_vaddr(struct vb2_buffer *vb, void *buf_priv) { struct vb2_dc_buf *buf = buf_priv; struct dma_buf_map map; @@ -137,9 +139,9 @@ static void vb2_dc_put(void *buf_priv) kfree(buf); } -static void *vb2_dc_alloc(struct device *dev, unsigned long attrs, - unsigned long size, enum dma_data_direction dma_dir, - gfp_t gfp_flags) +static void *vb2_dc_alloc(struct vb2_buffer *vb, + struct device *dev, + unsigned long size) { struct vb2_dc_buf *buf; @@ -150,9 +152,10 @@ static void *vb2_dc_alloc(struct device *dev, unsigned long attrs, if (!buf) return ERR_PTR(-ENOMEM); - buf->attrs = attrs; + buf->attrs = vb->vb2_queue->dma_attrs; buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr, - GFP_KERNEL | gfp_flags, buf->attrs); + GFP_KERNEL | vb->vb2_queue->gfp_flags, + buf->attrs); if (!buf->cookie) { dev_err(dev, "dma_alloc_coherent of size %ld failed\n", size); kfree(buf); @@ -165,11 +168,12 @@ static void *vb2_dc_alloc(struct device *dev, unsigned long attrs, /* Prevent the device from being released while the buffer is used */ buf->dev = get_device(dev); buf->size = size; - buf->dma_dir = dma_dir; + buf->dma_dir = vb->vb2_queue->dma_dir; buf->handler.refcount = &buf->refcount; buf->handler.put = vb2_dc_put; buf->handler.arg = buf; + buf->vb = vb; refcount_set(&buf->refcount, 1); @@ -397,7 +401,9 @@ static struct sg_table *vb2_dc_get_base_sgt(struct vb2_dc_buf *buf) return sgt; } -static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, unsigned long flags) +static struct dma_buf *vb2_dc_get_dmabuf(struct vb2_buffer *vb, + void *buf_priv, + unsigned long flags) { struct vb2_dc_buf *buf = buf_priv; struct dma_buf *dbuf; @@ -459,8 +465,8 @@ static void vb2_dc_put_userptr(void *buf_priv) kfree(buf); } -static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr, - unsigned long size, enum dma_data_direction dma_dir) +static void *vb2_dc_get_userptr(struct vb2_buffer *vb, struct device *dev, + unsigned long vaddr, unsigned long size) { struct vb2_dc_buf *buf; struct frame_vector *vec; @@ -490,7 +496,7 @@ static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr, return ERR_PTR(-ENOMEM); buf->dev = dev; - buf->dma_dir = dma_dir; + buf->dma_dir = vb->vb2_queue->dma_dir; offset = lower_32_bits(offset_in_page(vaddr)); vec = vb2_create_framevec(vaddr, size); @@ -660,8 +666,8 @@ static void vb2_dc_detach_dmabuf(void *mem_priv) kfree(buf); } -static void *vb2_dc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, - unsigned long size, enum dma_data_direction dma_dir) +static void *vb2_dc_attach_dmabuf(struct vb2_buffer *vb, struct device *dev, + struct dma_buf *dbuf, unsigned long size) { struct vb2_dc_buf *buf; struct dma_buf_attachment *dba; @@ -685,7 +691,7 @@ static void *vb2_dc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, return dba; } - buf->dma_dir = dma_dir; + buf->dma_dir = vb->vb2_queue->dma_dir; buf->size = size; buf->db_attach = dba; diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index c5b06a509566..50265080cfc8 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -51,6 +51,8 @@ struct vb2_dma_sg_buf { struct vb2_vmarea_handler handler; struct dma_buf_attachment *db_attach; + + struct vb2_buffer *vb; }; static void vb2_dma_sg_put(void *buf_priv); @@ -96,9 +98,8 @@ static int vb2_dma_sg_alloc_compacted(struct vb2_dma_sg_buf *buf, return 0; } -static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs, - unsigned long size, enum dma_data_direction dma_dir, - gfp_t gfp_flags) +static void *vb2_dma_sg_alloc(struct vb2_buffer *vb, struct device *dev, + unsigned long size) { struct vb2_dma_sg_buf *buf; struct sg_table *sgt; @@ -113,7 +114,7 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs, return ERR_PTR(-ENOMEM); buf->vaddr = NULL; - buf->dma_dir = dma_dir; + buf->dma_dir = vb->vb2_queue->dma_dir; buf->offset = 0; buf->size = size; /* size is already page aligned */ @@ -130,7 +131,7 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs, if (!buf->pages) goto fail_pages_array_alloc; - ret = vb2_dma_sg_alloc_compacted(buf, gfp_flags); + ret = vb2_dma_sg_alloc_compacted(buf, vb->vb2_queue->gfp_flags); if (ret) goto fail_pages_alloc; @@ -154,6 +155,7 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs, buf->handler.refcount = &buf->refcount; buf->handler.put = vb2_dma_sg_put; buf->handler.arg = buf; + buf->vb = vb; refcount_set(&buf->refcount, 1); @@ -213,9 +215,8 @@ static void vb2_dma_sg_finish(void *buf_priv) dma_sync_sgtable_for_cpu(buf->dev, sgt, buf->dma_dir); } -static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr, - unsigned long size, - enum dma_data_direction dma_dir) +static void *vb2_dma_sg_get_userptr(struct vb2_buffer *vb, struct device *dev, + unsigned long vaddr, unsigned long size) { struct vb2_dma_sg_buf *buf; struct sg_table *sgt; @@ -230,7 +231,7 @@ static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr, buf->vaddr = NULL; buf->dev = dev; - buf->dma_dir = dma_dir; + buf->dma_dir = vb->vb2_queue->dma_dir; buf->offset = vaddr & ~PAGE_MASK; buf->size = size; buf->dma_sgt = &buf->sg_table; @@ -292,7 +293,7 @@ static void vb2_dma_sg_put_userptr(void *buf_priv) kfree(buf); } -static void *vb2_dma_sg_vaddr(void *buf_priv) +static void *vb2_dma_sg_vaddr(struct vb2_buffer *vb, void *buf_priv) { struct vb2_dma_sg_buf *buf = buf_priv; struct dma_buf_map map; @@ -511,7 +512,9 @@ static const struct dma_buf_ops vb2_dma_sg_dmabuf_ops = { .release = vb2_dma_sg_dmabuf_ops_release, }; -static struct dma_buf *vb2_dma_sg_get_dmabuf(void *buf_priv, unsigned long flags) +static struct dma_buf *vb2_dma_sg_get_dmabuf(struct vb2_buffer *vb, + void *buf_priv, + unsigned long flags) { struct vb2_dma_sg_buf *buf = buf_priv; struct dma_buf *dbuf; @@ -605,8 +608,8 @@ static void vb2_dma_sg_detach_dmabuf(void *mem_priv) kfree(buf); } -static void *vb2_dma_sg_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, - unsigned long size, enum dma_data_direction dma_dir) +static void *vb2_dma_sg_attach_dmabuf(struct vb2_buffer *vb, struct device *dev, + struct dma_buf *dbuf, unsigned long size) { struct vb2_dma_sg_buf *buf; struct dma_buf_attachment *dba; @@ -630,14 +633,14 @@ static void *vb2_dma_sg_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, return dba; } - buf->dma_dir = dma_dir; + buf->dma_dir = vb->vb2_queue->dma_dir; buf->size = size; buf->db_attach = dba; return buf; } -static void *vb2_dma_sg_cookie(void *buf_priv) +static void *vb2_dma_sg_cookie(struct vb2_buffer *vb, void *buf_priv) { struct vb2_dma_sg_buf *buf = buf_priv; diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 83f95258ec8c..ef36abd912dc 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -34,13 +34,12 @@ struct vb2_vmalloc_buf { static void vb2_vmalloc_put(void *buf_priv); -static void *vb2_vmalloc_alloc(struct device *dev, unsigned long attrs, - unsigned long size, enum dma_data_direction dma_dir, - gfp_t gfp_flags) +static void *vb2_vmalloc_alloc(struct vb2_buffer *vb, struct device *dev, + unsigned long size) { struct vb2_vmalloc_buf *buf; - buf = kzalloc(sizeof(*buf), GFP_KERNEL | gfp_flags); + buf = kzalloc(sizeof(*buf), GFP_KERNEL | vb->vb2_queue->gfp_flags); if (!buf) return ERR_PTR(-ENOMEM); @@ -52,7 +51,7 @@ static void *vb2_vmalloc_alloc(struct device *dev, unsigned long attrs, return ERR_PTR(-ENOMEM); } - buf->dma_dir = dma_dir; + buf->dma_dir = vb->vb2_queue->dma_dir; buf->handler.refcount = &buf->refcount; buf->handler.put = vb2_vmalloc_put; buf->handler.arg = buf; @@ -71,9 +70,8 @@ static void vb2_vmalloc_put(void *buf_priv) } } -static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr, - unsigned long size, - enum dma_data_direction dma_dir) +static void *vb2_vmalloc_get_userptr(struct vb2_buffer *vb, struct device *dev, + unsigned long vaddr, unsigned long size) { struct vb2_vmalloc_buf *buf; struct frame_vector *vec; @@ -84,7 +82,7 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr, if (!buf) return ERR_PTR(-ENOMEM); - buf->dma_dir = dma_dir; + buf->dma_dir = vb->vb2_queue->dma_dir; offset = vaddr & ~PAGE_MASK; buf->size = size; vec = vb2_create_framevec(vaddr, size); @@ -147,7 +145,7 @@ static void vb2_vmalloc_put_userptr(void *buf_priv) kfree(buf); } -static void *vb2_vmalloc_vaddr(void *buf_priv) +static void *vb2_vmalloc_vaddr(struct vb2_buffer *vb, void *buf_priv) { struct vb2_vmalloc_buf *buf = buf_priv; @@ -339,7 +337,9 @@ static const struct dma_buf_ops vb2_vmalloc_dmabuf_ops = { .release = vb2_vmalloc_dmabuf_ops_release, }; -static struct dma_buf *vb2_vmalloc_get_dmabuf(void *buf_priv, unsigned long flags) +static struct dma_buf *vb2_vmalloc_get_dmabuf(struct vb2_buffer *vb, + void *buf_priv, + unsigned long flags) { struct vb2_vmalloc_buf *buf = buf_priv; struct dma_buf *dbuf; @@ -403,8 +403,10 @@ static void vb2_vmalloc_detach_dmabuf(void *mem_priv) kfree(buf); } -static void *vb2_vmalloc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, - unsigned long size, enum dma_data_direction dma_dir) +static void *vb2_vmalloc_attach_dmabuf(struct vb2_buffer *vb, + struct device *dev, + struct dma_buf *dbuf, + unsigned long size) { struct vb2_vmalloc_buf *buf; @@ -416,7 +418,7 @@ static void *vb2_vmalloc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, return ERR_PTR(-ENOMEM); buf->dbuf = dbuf; - buf->dma_dir = dma_dir; + buf->dma_dir = vb->vb2_queue->dma_dir; buf->size = size; return buf; diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 12955cb460d2..3b5986cee073 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -46,6 +46,7 @@ enum vb2_memory { struct vb2_fileio_data; struct vb2_threadio_data; +struct vb2_buffer; /** * struct vb2_mem_ops - memory handling/memory allocator operations. @@ -53,10 +54,8 @@ struct vb2_threadio_data; * return ERR_PTR() on failure or a pointer to allocator private, * per-buffer data on success; the returned private structure * will then be passed as @buf_priv argument to other ops in this - * structure. Additional gfp_flags to use when allocating the - * are also passed to this operation. These flags are from the - * gfp_flags field of vb2_queue. The size argument to this function - * shall be *page aligned*. + * structure. The size argument to this function shall be + * *page aligned*. * @put: inform the allocator that the buffer will no longer be used; * usually will result in the allocator freeing the buffer (if * no other users of this buffer are present); the @buf_priv @@ -117,31 +116,33 @@ struct vb2_threadio_data; * map_dmabuf, unmap_dmabuf. */ struct vb2_mem_ops { - void *(*alloc)(struct device *dev, unsigned long attrs, - unsigned long size, - enum dma_data_direction dma_dir, - gfp_t gfp_flags); + void *(*alloc)(struct vb2_buffer *vb, + struct device *dev, + unsigned long size); void (*put)(void *buf_priv); - struct dma_buf *(*get_dmabuf)(void *buf_priv, unsigned long flags); - - void *(*get_userptr)(struct device *dev, unsigned long vaddr, - unsigned long size, - enum dma_data_direction dma_dir); + struct dma_buf *(*get_dmabuf)(struct vb2_buffer *vb, + void *buf_priv, + unsigned long flags); + + void *(*get_userptr)(struct vb2_buffer *vb, + struct device *dev, + unsigned long vaddr, + unsigned long size); void (*put_userptr)(void *buf_priv); void (*prepare)(void *buf_priv); void (*finish)(void *buf_priv); - void *(*attach_dmabuf)(struct device *dev, + void *(*attach_dmabuf)(struct vb2_buffer *vb, + struct device *dev, struct dma_buf *dbuf, - unsigned long size, - enum dma_data_direction dma_dir); + unsigned long size); void (*detach_dmabuf)(void *buf_priv); int (*map_dmabuf)(void *buf_priv); void (*unmap_dmabuf)(void *buf_priv); - void *(*vaddr)(void *buf_priv); - void *(*cookie)(void *buf_priv); + void *(*vaddr)(struct vb2_buffer *vb, void *buf_priv); + void *(*cookie)(struct vb2_buffer *vb, void *buf_priv); unsigned int (*num_users)(void *buf_priv); -- cgit v1.2.3 From 4dbe7eab95809ada25312a3c67bda0697040bbb0 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 9 Sep 2021 13:24:24 +0200 Subject: media: videobuf2: inverse buffer cache_hints flags It would be less error prone if the default cache hints value (we kzalloc() structs, so it's zeroed out by default) would be to "always sync/flush" caches. Inverse and rename cache hints flags. Signed-off-by: Sergey Senozhatsky Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-core.c | 31 ++++++++----------------- drivers/media/common/videobuf2/videobuf2-v4l2.c | 17 ++++---------- include/media/videobuf2-core.h | 12 +++++----- 3 files changed, 21 insertions(+), 39 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index c4ff356da600..9d57df348b5f 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -327,12 +327,12 @@ static void __vb2_buf_mem_prepare(struct vb2_buffer *vb) if (vb->synced) return; - if (vb->need_cache_sync_on_prepare) { - for (plane = 0; plane < vb->num_planes; ++plane) - call_void_memop(vb, prepare, - vb->planes[plane].mem_priv); - } vb->synced = 1; + if (vb->skip_cache_sync_on_prepare) + return; + + for (plane = 0; plane < vb->num_planes; ++plane) + call_void_memop(vb, prepare, vb->planes[plane].mem_priv); } /* @@ -346,12 +346,12 @@ static void __vb2_buf_mem_finish(struct vb2_buffer *vb) if (!vb->synced) return; - if (vb->need_cache_sync_on_finish) { - for (plane = 0; plane < vb->num_planes; ++plane) - call_void_memop(vb, finish, - vb->planes[plane].mem_priv); - } vb->synced = 0; + if (vb->skip_cache_sync_on_finish) + return; + + for (plane = 0; plane < vb->num_planes; ++plane) + call_void_memop(vb, finish, vb->planes[plane].mem_priv); } /* @@ -415,17 +415,6 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, vb->index = q->num_buffers + buffer; vb->type = q->type; vb->memory = memory; - /* - * We need to set these flags here so that the videobuf2 core - * will call ->prepare()/->finish() cache sync/flush on vb2 - * buffers when appropriate. However, we can avoid explicit - * ->prepare() and ->finish() cache sync for DMABUF buffers, - * because DMA exporter takes care of it. - */ - if (q->memory != VB2_MEMORY_DMABUF) { - vb->need_cache_sync_on_prepare = 1; - vb->need_cache_sync_on_finish = 1; - } for (plane = 0; plane < num_planes; ++plane) { vb->planes[plane].length = plane_sizes[plane]; vb->planes[plane].min_length = plane_sizes[plane]; diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 2988bb38ceb1..454d58268602 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -351,18 +351,11 @@ static void set_buffer_cache_hints(struct vb2_queue *q, * we always need ->prepare() or/and ->finish() cache sync. */ if (q->memory == VB2_MEMORY_DMABUF) { - vb->need_cache_sync_on_finish = 0; - vb->need_cache_sync_on_prepare = 0; + vb->skip_cache_sync_on_finish = 1; + vb->skip_cache_sync_on_prepare = 1; return; } - /* - * Cache sync/invalidation flags are set by default in order to - * preserve existing behaviour for old apps/drivers. - */ - vb->need_cache_sync_on_prepare = 1; - vb->need_cache_sync_on_finish = 1; - if (!vb2_queue_allows_cache_hints(q)) { /* * Clear buffer cache flags if queue does not support user @@ -379,13 +372,13 @@ static void set_buffer_cache_hints(struct vb2_queue *q, * TO_DEVICE. */ if (q->dma_dir == DMA_TO_DEVICE) - vb->need_cache_sync_on_finish = 0; + vb->skip_cache_sync_on_finish = 1; if (b->flags & V4L2_BUF_FLAG_NO_CACHE_INVALIDATE) - vb->need_cache_sync_on_finish = 0; + vb->skip_cache_sync_on_finish = 1; if (b->flags & V4L2_BUF_FLAG_NO_CACHE_CLEAN) - vb->need_cache_sync_on_prepare = 0; + vb->skip_cache_sync_on_prepare = 1; } static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *mdev, diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 3b5986cee073..66e548268242 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -267,10 +267,10 @@ struct vb2_buffer { * after the 'buf_finish' op is called. * copied_timestamp: the timestamp of this capture buffer was copied * from an output buffer. - * need_cache_sync_on_prepare: when set buffer's ->prepare() function - * performs cache sync/invalidation. - * need_cache_sync_on_finish: when set buffer's ->finish() function - * performs cache sync/invalidation. + * skip_cache_sync_on_prepare: when set buffer's ->prepare() function + * skips cache sync/invalidation. + * skip_cache_sync_on_finish: when set buffer's ->finish() function + * skips cache sync/invalidation. * queued_entry: entry on the queued buffers list, which holds * all buffers queued from userspace * done_entry: entry on the list that stores all buffers ready @@ -281,8 +281,8 @@ struct vb2_buffer { unsigned int synced:1; unsigned int prepared:1; unsigned int copied_timestamp:1; - unsigned int need_cache_sync_on_prepare:1; - unsigned int need_cache_sync_on_finish:1; + unsigned int skip_cache_sync_on_prepare:1; + unsigned int skip_cache_sync_on_finish:1; struct vb2_plane planes[VB2_MAX_PLANES]; struct list_head queued_entry; -- cgit v1.2.3 From 0a12d652fcfe0c1be8fec7439b27d8392aa45678 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 9 Sep 2021 13:24:25 +0200 Subject: media: videobuf2: split buffer cache_hints initialisation V4L2 is not the perfect place to manage vb2 buffer cache hints. It works for V4L2 users, but there are backends that use vb2 core and don't use V4L2. Factor out buffer cache hints initialisation and call it when we allocate vb2 buffer. Signed-off-by: Sergey Senozhatsky Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-core.c | 22 ++++++++++++++++++++++ drivers/media/common/videobuf2/videobuf2-v4l2.c | 18 ------------------ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 9d57df348b5f..59bd781c9a34 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -382,6 +382,27 @@ static void __setup_offsets(struct vb2_buffer *vb) } } +static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb) +{ + /* + * DMA exporter should take care of cache syncs, so we can avoid + * explicit ->prepare()/->finish() syncs. For other ->memory types + * we always need ->prepare() or/and ->finish() cache sync. + */ + if (q->memory == VB2_MEMORY_DMABUF) { + vb->skip_cache_sync_on_finish = 1; + vb->skip_cache_sync_on_prepare = 1; + return; + } + + /* + * ->finish() cache sync can be avoided when queue direction is + * TO_DEVICE. + */ + if (q->dma_dir == DMA_TO_DEVICE) + vb->skip_cache_sync_on_finish = 1; +} + /* * __vb2_queue_alloc() - allocate videobuf buffer structures and (for MMAP type) * video buffer memory for all buffers/planes on the queue and initializes the @@ -415,6 +436,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, vb->index = q->num_buffers + buffer; vb->type = q->type; vb->memory = memory; + init_buffer_cache_hints(q, vb); for (plane = 0; plane < num_planes; ++plane) { vb->planes[plane].length = plane_sizes[plane]; vb->planes[plane].min_length = plane_sizes[plane]; diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 454d58268602..2fbae9bd7b52 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -345,17 +345,6 @@ static void set_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb, struct v4l2_buffer *b) { - /* - * DMA exporter should take care of cache syncs, so we can avoid - * explicit ->prepare()/->finish() syncs. For other ->memory types - * we always need ->prepare() or/and ->finish() cache sync. - */ - if (q->memory == VB2_MEMORY_DMABUF) { - vb->skip_cache_sync_on_finish = 1; - vb->skip_cache_sync_on_prepare = 1; - return; - } - if (!vb2_queue_allows_cache_hints(q)) { /* * Clear buffer cache flags if queue does not support user @@ -367,13 +356,6 @@ static void set_buffer_cache_hints(struct vb2_queue *q, return; } - /* - * ->finish() cache sync can be avoided when queue direction is - * TO_DEVICE. - */ - if (q->dma_dir == DMA_TO_DEVICE) - vb->skip_cache_sync_on_finish = 1; - if (b->flags & V4L2_BUF_FLAG_NO_CACHE_INVALIDATE) vb->skip_cache_sync_on_finish = 1; -- cgit v1.2.3 From cde513fd9b35e29e345ef95cd59f0db8bffca91c Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 9 Sep 2021 13:24:26 +0200 Subject: media: videobuf2: move cache_hints handling to allocators This moves cache hints handling from the videobuf2 core down to the allocator's level, because allocators do the sync/flush caches eventually and may take better decisions. Besides, allocators already decide whether cache sync/flush should be done or can be skipped. This patch moves the scattered buffer cache sync logic to one common place. Signed-off-by: Sergey Senozhatsky Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-core.c | 6 ------ drivers/media/common/videobuf2/videobuf2-dma-contig.c | 6 ++++++ drivers/media/common/videobuf2/videobuf2-dma-sg.c | 6 ++++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 59bd781c9a34..8fa9f92ed028 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -328,9 +328,6 @@ static void __vb2_buf_mem_prepare(struct vb2_buffer *vb) return; vb->synced = 1; - if (vb->skip_cache_sync_on_prepare) - return; - for (plane = 0; plane < vb->num_planes; ++plane) call_void_memop(vb, prepare, vb->planes[plane].mem_priv); } @@ -347,9 +344,6 @@ static void __vb2_buf_mem_finish(struct vb2_buffer *vb) return; vb->synced = 0; - if (vb->skip_cache_sync_on_finish) - return; - for (plane = 0; plane < vb->num_planes; ++plane) call_void_memop(vb, finish, vb->planes[plane].mem_priv); } diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index 019c3843dc6d..1e218bc440c6 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -101,6 +101,9 @@ static void vb2_dc_prepare(void *buf_priv) struct vb2_dc_buf *buf = buf_priv; struct sg_table *sgt = buf->dma_sgt; + if (buf->vb->skip_cache_sync_on_prepare) + return; + if (!sgt) return; @@ -112,6 +115,9 @@ static void vb2_dc_finish(void *buf_priv) struct vb2_dc_buf *buf = buf_priv; struct sg_table *sgt = buf->dma_sgt; + if (buf->vb->skip_cache_sync_on_finish) + return; + if (!sgt) return; diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 50265080cfc8..33ee63a99139 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -204,6 +204,9 @@ static void vb2_dma_sg_prepare(void *buf_priv) struct vb2_dma_sg_buf *buf = buf_priv; struct sg_table *sgt = buf->dma_sgt; + if (buf->vb->skip_cache_sync_on_prepare) + return; + dma_sync_sgtable_for_device(buf->dev, sgt, buf->dma_dir); } @@ -212,6 +215,9 @@ static void vb2_dma_sg_finish(void *buf_priv) struct vb2_dma_sg_buf *buf = buf_priv; struct sg_table *sgt = buf->dma_sgt; + if (buf->vb->skip_cache_sync_on_finish) + return; + dma_sync_sgtable_for_cpu(buf->dev, sgt, buf->dma_dir); } -- cgit v1.2.3 From 965c1e0bfeb66888fb000540c1fc4e8b55533d9c Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 9 Sep 2021 13:24:27 +0200 Subject: media: videobuf2: add V4L2_MEMORY_FLAG_NON_COHERENT flag By setting or clearing the V4L2_MEMORY_FLAG_NON_COHERENT flag user-space should be able to hint vb2 that either non-coherent (if supported) or coherent memory should be used for the buffer allocation. Signed-off-by: Sergey Senozhatsky Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/buffer.rst | 40 ++++++++++++++++++++-- .../userspace-api/media/v4l/vidioc-reqbufs.rst | 5 +-- include/uapi/linux/videodev2.h | 2 ++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/buffer.rst b/Documentation/userspace-api/media/v4l/buffer.rst index e991ba73d873..4638ec64db00 100644 --- a/Documentation/userspace-api/media/v4l/buffer.rst +++ b/Documentation/userspace-api/media/v4l/buffer.rst @@ -676,8 +676,6 @@ Buffer Flags \normalsize -.. _memory-flags: - enum v4l2_memory ================ @@ -701,6 +699,44 @@ enum v4l2_memory - 4 - The buffer is used for :ref:`DMA shared buffer ` I/O. +.. _memory-flags: + +Memory Consistency Flags +------------------------ + +.. raw:: latex + + \small + +.. tabularcolumns:: |p{7.0cm}|p{2.1cm}|p{8.4cm}| + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 3 1 4 + + * .. _`V4L2-MEMORY-FLAG-NON-COHERENT`: + + - ``V4L2_MEMORY_FLAG_NON_COHERENT`` + - 0x00000001 + - A buffer is allocated either in coherent (it will be automatically + coherent between the CPU and the bus) or non-coherent memory. The + latter can provide performance gains, for instance the CPU cache + sync/flush operations can be avoided if the buffer is accessed by the + corresponding device only and the CPU does not read/write to/from that + buffer. However, this requires extra care from the driver -- it must + guarantee memory consistency by issuing a cache flush/sync when + consistency is needed. If this flag is set V4L2 will attempt to + allocate the buffer in non-coherent memory. The flag takes effect + only if the buffer is used for :ref:`memory mapping ` I/O and the + queue reports the :ref:`V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS + ` capability. + +.. raw:: latex + + \normalsize Timecodes ========= diff --git a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst index 50ea72043bb0..e59306aba2b0 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst @@ -158,8 +158,9 @@ aborting or finishing any DMA in progress, an implicit - This capability is set by the driver to indicate that the queue supports cache and memory management hints. However, it's only valid when the queue is used for :ref:`memory mapping ` streaming I/O. See - :ref:`V4L2_BUF_FLAG_NO_CACHE_INVALIDATE ` and - :ref:`V4L2_BUF_FLAG_NO_CACHE_CLEAN `. + :ref:`V4L2_BUF_FLAG_NO_CACHE_INVALIDATE `, + :ref:`V4L2_BUF_FLAG_NO_CACHE_CLEAN ` and + :ref:`V4L2_MEMORY_FLAG_NON_COHERENT `. .. raw:: latex diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 5cc9545feb40..9b7032abb2c7 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -962,6 +962,8 @@ struct v4l2_requestbuffers { __u32 reserved[1]; }; +#define V4L2_MEMORY_FLAG_NON_COHERENT (1 << 0) + /* capabilities for struct v4l2_requestbuffers and v4l2_create_buffers */ #define V4L2_BUF_CAP_SUPPORTS_MMAP (1 << 0) #define V4L2_BUF_CAP_SUPPORTS_USERPTR (1 << 1) -- cgit v1.2.3 From b00a9e59c539684d9e105feafaeee36df11ee493 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 9 Sep 2021 13:24:28 +0200 Subject: media: videobuf2: add queue memory coherency parameter Preparations for future V4L2_MEMORY_FLAG_NON_COHERENT support. Extend the vb2_core_reqbufs() parameters list to accept requests' ->flags, which will be used for memory coherency configuration. An attempt to allocate a buffer with coherency requirements that do not match the queue's consistency model will fail. Signed-off-by: Sergey Senozhatsky Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-core.c | 37 +++++++++++++++++++++---- drivers/media/common/videobuf2/videobuf2-v4l2.c | 5 ++-- drivers/media/dvb-core/dvb_vb2.c | 2 +- include/media/videobuf2-core.h | 10 +++++-- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 8fa9f92ed028..60fb43b8f134 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -738,11 +738,30 @@ int vb2_verify_memory_type(struct vb2_queue *q, } EXPORT_SYMBOL(vb2_verify_memory_type); +static void set_queue_coherency(struct vb2_queue *q, bool non_coherent_mem) +{ + q->non_coherent_mem = 0; + + if (!vb2_queue_allows_cache_hints(q)) + return; + q->non_coherent_mem = non_coherent_mem; +} + +static bool verify_coherency_flags(struct vb2_queue *q, bool non_coherent_mem) +{ + if (non_coherent_mem != q->non_coherent_mem) { + dprintk(q, 1, "memory coherency model mismatch\n"); + return false; + } + return true; +} + int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, - unsigned int *count) + unsigned int flags, unsigned int *count) { unsigned int num_buffers, allocated_buffers, num_planes = 0; unsigned plane_sizes[VB2_MAX_PLANES] = { }; + bool non_coherent_mem = false; unsigned int i; int ret; @@ -757,7 +776,8 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, } if (*count == 0 || q->num_buffers != 0 || - (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory)) { + (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory) || + !verify_coherency_flags(q, non_coherent_mem)) { /* * We already have buffers allocated, so first check if they * are not in use and can be freed. @@ -794,6 +814,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, num_buffers = min_t(unsigned int, num_buffers, VB2_MAX_FRAME); memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); q->memory = memory; + set_queue_coherency(q, non_coherent_mem); /* * Ask the driver how many buffers and planes per buffer it requires. @@ -878,12 +899,13 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, EXPORT_SYMBOL_GPL(vb2_core_reqbufs); int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, - unsigned int *count, + unsigned int flags, unsigned int *count, unsigned int requested_planes, const unsigned int requested_sizes[]) { unsigned int num_planes = 0, num_buffers, allocated_buffers; unsigned plane_sizes[VB2_MAX_PLANES] = { }; + bool non_coherent_mem = false; int ret; if (q->num_buffers == VB2_MAX_FRAME) { @@ -899,11 +921,14 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); q->memory = memory; q->waiting_for_buffers = !q->is_output; + set_queue_coherency(q, non_coherent_mem); } else { if (q->memory != memory) { dprintk(q, 1, "memory model mismatch\n"); return -EINVAL; } + if (!verify_coherency_flags(q, non_coherent_mem)) + return -EINVAL; } num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers); @@ -2608,7 +2633,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) fileio->memory = VB2_MEMORY_MMAP; fileio->type = q->type; q->fileio = fileio; - ret = vb2_core_reqbufs(q, fileio->memory, &fileio->count); + ret = vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count); if (ret) goto err_kfree; @@ -2665,7 +2690,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) err_reqbufs: fileio->count = 0; - vb2_core_reqbufs(q, fileio->memory, &fileio->count); + vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count); err_kfree: q->fileio = NULL; @@ -2685,7 +2710,7 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q) vb2_core_streamoff(q, q->type); q->fileio = NULL; fileio->count = 0; - vb2_core_reqbufs(q, fileio->memory, &fileio->count); + vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count); kfree(fileio); dprintk(q, 3, "file io emulator closed\n"); } diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 2fbae9bd7b52..b4f70ddb09b0 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -697,7 +697,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) int ret = vb2_verify_memory_type(q, req->memory, req->type); fill_buf_caps(q, &req->capabilities); - return ret ? ret : vb2_core_reqbufs(q, req->memory, &req->count); + return ret ? ret : vb2_core_reqbufs(q, req->memory, 0, &req->count); } EXPORT_SYMBOL_GPL(vb2_reqbufs); @@ -772,6 +772,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) if (requested_sizes[i] == 0) return -EINVAL; return ret ? ret : vb2_core_create_bufs(q, create->memory, + 0, &create->count, requested_planes, requested_sizes); @@ -974,7 +975,7 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv, return res; if (vb2_queue_is_busy(vdev, file)) return -EBUSY; - res = vb2_core_reqbufs(vdev->queue, p->memory, &p->count); + res = vb2_core_reqbufs(vdev->queue, p->memory, 0, &p->count); /* If count == 0, then the owner has released all buffers and he is no longer owner of the queue. Otherwise we have a new owner. */ if (res == 0) diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c index 6974f1731529..959d110407a4 100644 --- a/drivers/media/dvb-core/dvb_vb2.c +++ b/drivers/media/dvb-core/dvb_vb2.c @@ -342,7 +342,7 @@ int dvb_vb2_reqbufs(struct dvb_vb2_ctx *ctx, struct dmx_requestbuffers *req) ctx->buf_siz = req->size; ctx->buf_cnt = req->count; - ret = vb2_core_reqbufs(&ctx->vb_q, VB2_MEMORY_MMAP, &req->count); + ret = vb2_core_reqbufs(&ctx->vb_q, VB2_MEMORY_MMAP, 0, &req->count); if (ret) { ctx->state = DVB_VB2_STATE_NONE; dprintk(1, "[%s] count=%d size=%d errno=%d\n", ctx->name, diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 66e548268242..2467284e5f26 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -504,6 +504,8 @@ struct vb2_buf_ops { * @allow_cache_hints: when set user-space can pass cache management hints in * order to skip cache flush/invalidation on ->prepare() or/and * ->finish(). + * @non_coherent_mem: when set queue will attempt to allocate buffers using + * non-coherent memory. * @lock: pointer to a mutex that protects the &struct vb2_queue. The * driver can set this to a mutex to let the v4l2 core serialize * the queuing ioctls. If the driver wants to handle locking @@ -583,6 +585,7 @@ struct vb2_queue { unsigned int uses_qbuf:1; unsigned int uses_requests:1; unsigned int allow_cache_hints:1; + unsigned int non_coherent_mem:1; struct mutex *lock; void *owner; @@ -748,6 +751,8 @@ void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb); * vb2_core_reqbufs() - Initiate streaming. * @q: pointer to &struct vb2_queue with videobuf2 queue. * @memory: memory type, as defined by &enum vb2_memory. + * @flags: auxiliary queue/buffer management flags. Currently, the only + * used flag is %V4L2_MEMORY_FLAG_NON_COHERENT. * @count: requested buffer count. * * Videobuf2 core helper to implement VIDIOC_REQBUF() operation. It is called @@ -772,12 +777,13 @@ void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb); * Return: returns zero on success; an error code otherwise. */ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, - unsigned int *count); + unsigned int flags, unsigned int *count); /** * vb2_core_create_bufs() - Allocate buffers and any required auxiliary structs * @q: pointer to &struct vb2_queue with videobuf2 queue. * @memory: memory type, as defined by &enum vb2_memory. + * @flags: auxiliary queue/buffer management flags. * @count: requested buffer count. * @requested_planes: number of planes requested. * @requested_sizes: array with the size of the planes. @@ -795,7 +801,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, * Return: returns zero on success; an error code otherwise. */ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, - unsigned int *count, + unsigned int flags, unsigned int *count, unsigned int requested_planes, const unsigned int requested_sizes[]); -- cgit v1.2.3 From c0acf9cfeee061f041fab778dbdcb34b6ca5e2e7 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 9 Sep 2021 13:24:29 +0200 Subject: media: videobuf2: handle V4L2_MEMORY_FLAG_NON_COHERENT flag This patch lets user-space request a non-coherent memory allocation during CREATE_BUFS and REQBUFS ioctl calls. = CREATE_BUFS struct v4l2_create_buffers has seven 4-byte reserved areas, so reserved[0] is renamed to ->flags. The struct, thus, now has six reserved 4-byte regions. = CREATE_BUFS32 struct v4l2_create_buffers32 has seven 4-byte reserved areas, so reserved[0] is renamed to ->flags. The struct, thus, now has six reserved 4-byte regions. = REQBUFS We use one byte of a 4 byte ->reserved[1] member of struct v4l2_requestbuffers. The struct, thus, now has reserved 3 bytes. Signed-off-by: Sergey Senozhatsky Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/vidioc-create-bufs.rst | 7 ++++- .../userspace-api/media/v4l/vidioc-reqbufs.rst | 11 +++++--- drivers/media/common/videobuf2/videobuf2-core.c | 4 +-- drivers/media/common/videobuf2/videobuf2-v4l2.c | 31 +++++++++++++++++++--- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 9 ++++++- drivers/media/v4l2-core/v4l2-ioctl.c | 4 +-- include/uapi/linux/videodev2.h | 9 +++++-- 7 files changed, 60 insertions(+), 15 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst b/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst index f98f18c9e91c..a048a9f6b7b6 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst @@ -113,7 +113,12 @@ than the number requested. ``V4L2_MEMORY_MMAP`` and ``format.type`` to the buffer type. * - __u32 - - ``reserved``\ [7] + - ``flags`` + - Specifies additional buffer management attributes. + See :ref:`memory-flags`. + + * - __u32 + - ``reserved``\ [6] - A place holder for future extensions. Drivers and applications must set the array to zero. diff --git a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst index e59306aba2b0..099fa6695167 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst @@ -104,10 +104,13 @@ aborting or finishing any DMA in progress, an implicit ``V4L2_MEMORY_MMAP`` and ``type`` set to the buffer type. This will free any previously allocated buffers, so this is typically something that will be done at the start of the application. - * - __u32 - - ``reserved``\ [1] - - A place holder for future extensions. Drivers and applications - must set the array to zero. + * - __u8 + - ``flags`` + - Specifies additional buffer management attributes. + See :ref:`memory-flags`. + * - __u8 + - ``reserved``\ [3] + - Reserved for future extensions. .. _v4l2-buf-capabilities: .. _V4L2-BUF-CAP-SUPPORTS-MMAP: diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 60fb43b8f134..2266bbd239ab 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -761,7 +761,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, { unsigned int num_buffers, allocated_buffers, num_planes = 0; unsigned plane_sizes[VB2_MAX_PLANES] = { }; - bool non_coherent_mem = false; + bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT; unsigned int i; int ret; @@ -905,7 +905,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, { unsigned int num_planes = 0, num_buffers, allocated_buffers; unsigned plane_sizes[VB2_MAX_PLANES] = { }; - bool non_coherent_mem = false; + bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT; int ret; if (q->num_buffers == VB2_MAX_FRAME) { diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index b4f70ddb09b0..6edf4508c636 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -692,12 +692,32 @@ static void fill_buf_caps(struct vb2_queue *q, u32 *caps) #endif } +static void validate_memory_flags(struct vb2_queue *q, + int memory, + u32 *flags) +{ + if (!q->allow_cache_hints || memory != V4L2_MEMORY_MMAP) { + /* + * This needs to clear V4L2_MEMORY_FLAG_NON_COHERENT only, + * but in order to avoid bugs we zero out all bits. + */ + *flags = 0; + } else { + /* Clear all unknown flags. */ + *flags &= V4L2_MEMORY_FLAG_NON_COHERENT; + } +} + int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) { int ret = vb2_verify_memory_type(q, req->memory, req->type); + u32 flags = req->flags; fill_buf_caps(q, &req->capabilities); - return ret ? ret : vb2_core_reqbufs(q, req->memory, 0, &req->count); + validate_memory_flags(q, req->memory, &flags); + req->flags = flags; + return ret ? ret : vb2_core_reqbufs(q, req->memory, + req->flags, &req->count); } EXPORT_SYMBOL_GPL(vb2_reqbufs); @@ -729,6 +749,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) unsigned i; fill_buf_caps(q, &create->capabilities); + validate_memory_flags(q, create->memory, &create->flags); create->index = q->num_buffers; if (create->count == 0) return ret != -EBUSY ? ret : 0; @@ -772,7 +793,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) if (requested_sizes[i] == 0) return -EINVAL; return ret ? ret : vb2_core_create_bufs(q, create->memory, - 0, + create->flags, &create->count, requested_planes, requested_sizes); @@ -969,13 +990,16 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv, { struct video_device *vdev = video_devdata(file); int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type); + u32 flags = p->flags; fill_buf_caps(vdev->queue, &p->capabilities); + validate_memory_flags(vdev->queue, p->memory, &flags); + p->flags = flags; if (res) return res; if (vb2_queue_is_busy(vdev, file)) return -EBUSY; - res = vb2_core_reqbufs(vdev->queue, p->memory, 0, &p->count); + res = vb2_core_reqbufs(vdev->queue, p->memory, p->flags, &p->count); /* If count == 0, then the owner has released all buffers and he is no longer owner of the queue. Otherwise we have a new owner. */ if (res == 0) @@ -993,6 +1017,7 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv, p->index = vdev->queue->num_buffers; fill_buf_caps(vdev->queue, &p->capabilities); + validate_memory_flags(vdev->queue, p->memory, &p->flags); /* * If count == 0, then just check if memory and type are valid. * Any -EBUSY result from vb2_verify_memory_type can be mapped to 0. diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 47aff3b19742..8176769a89fa 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -126,6 +126,9 @@ struct v4l2_format32 { * @memory: buffer memory type * @format: frame format, for which buffers are requested * @capabilities: capabilities of this buffer type. + * @flags: additional buffer management attributes (ignored unless the + * queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability and + * configured for MMAP streaming I/O). * @reserved: future extensions */ struct v4l2_create_buffers32 { @@ -134,7 +137,8 @@ struct v4l2_create_buffers32 { __u32 memory; /* enum v4l2_memory */ struct v4l2_format32 format; __u32 capabilities; - __u32 reserved[7]; + __u32 flags; + __u32 reserved[6]; }; static int get_v4l2_format32(struct v4l2_format *p64, @@ -182,6 +186,8 @@ static int get_v4l2_create32(struct v4l2_create_buffers *p64, if (copy_from_user(p64, p32, offsetof(struct v4l2_create_buffers32, format))) return -EFAULT; + if (copy_from_user(&p64->flags, &p32->flags, sizeof(p32->flags))) + return -EFAULT; return get_v4l2_format32(&p64->format, &p32->format); } @@ -227,6 +233,7 @@ static int put_v4l2_create32(struct v4l2_create_buffers *p64, if (copy_to_user(p32, p64, offsetof(struct v4l2_create_buffers32, format)) || put_user(p64->capabilities, &p32->capabilities) || + put_user(p64->flags, &p32->flags) || copy_to_user(p32->reserved, p64->reserved, sizeof(p64->reserved))) return -EFAULT; return put_v4l2_format32(&p64->format, &p32->format); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index bc83d23ce25d..31d0109ce5a8 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2024,7 +2024,7 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, if (ret) return ret; - CLEAR_AFTER_FIELD(p, capabilities); + CLEAR_AFTER_FIELD(p, flags); return ops->vidioc_reqbufs(file, fh, p); } @@ -2065,7 +2065,7 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, if (ret) return ret; - CLEAR_AFTER_FIELD(create, capabilities); + CLEAR_AFTER_FIELD(create, flags); v4l_sanitize_format(&create->format); diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 9b7032abb2c7..f118fe7a9f58 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -959,7 +959,8 @@ struct v4l2_requestbuffers { __u32 type; /* enum v4l2_buf_type */ __u32 memory; /* enum v4l2_memory */ __u32 capabilities; - __u32 reserved[1]; + __u8 flags; + __u8 reserved[3]; }; #define V4L2_MEMORY_FLAG_NON_COHERENT (1 << 0) @@ -2507,6 +2508,9 @@ struct v4l2_dbg_chip_info { * @memory: enum v4l2_memory; buffer memory type * @format: frame format, for which buffers are requested * @capabilities: capabilities of this buffer type. + * @flags: additional buffer management attributes (ignored unless the + * queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability + * and configured for MMAP streaming I/O). * @reserved: future extensions */ struct v4l2_create_buffers { @@ -2515,7 +2519,8 @@ struct v4l2_create_buffers { __u32 memory; struct v4l2_format format; __u32 capabilities; - __u32 reserved[7]; + __u32 flags; + __u32 reserved[6]; }; /* -- cgit v1.2.3 From de27891f675ed1e46e8821d2e05e036e5f97586b Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 9 Sep 2021 13:24:30 +0200 Subject: media: videobuf2: handle non-contiguous DMA allocations This adds support for the new noncontiguous DMA API, which requires allocators to have two execution branches: one for the current API, and one for the new one. Signed-off-by: Sergey Senozhatsky Acked-by: Christoph Hellwig Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/common/videobuf2/videobuf2-dma-contig.c | 161 +++++++++++++++++---- 1 file changed, 130 insertions(+), 31 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index 1e218bc440c6..b052a4e36961 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,7 @@ struct vb2_dc_buf { struct dma_buf_attachment *db_attach; struct vb2_buffer *vb; + bool non_coherent_mem; }; /*********************************************/ @@ -75,17 +77,39 @@ static void *vb2_dc_cookie(struct vb2_buffer *vb, void *buf_priv) return &buf->dma_addr; } +/* + * This function may fail if: + * + * - dma_buf_vmap() fails + * E.g. due to lack of virtual mapping address space, or due to + * dmabuf->ops misconfiguration. + * + * - dma_vmap_noncontiguous() fails + * For instance, when requested buffer size is larger than totalram_pages(). + * Relevant for buffers that use non-coherent memory. + * + * - Queue DMA attrs have DMA_ATTR_NO_KERNEL_MAPPING set + * Relevant for buffers that use coherent memory. + */ static void *vb2_dc_vaddr(struct vb2_buffer *vb, void *buf_priv) { struct vb2_dc_buf *buf = buf_priv; - struct dma_buf_map map; - int ret; - if (!buf->vaddr && buf->db_attach) { - ret = dma_buf_vmap(buf->db_attach->dmabuf, &map); - buf->vaddr = ret ? NULL : map.vaddr; + if (buf->vaddr) + return buf->vaddr; + + if (buf->db_attach) { + struct dma_buf_map map; + + if (!dma_buf_vmap(buf->db_attach->dmabuf, &map)) + buf->vaddr = map.vaddr; + + return buf->vaddr; } + if (buf->non_coherent_mem) + buf->vaddr = dma_vmap_noncontiguous(buf->dev, buf->size, + buf->dma_sgt); return buf->vaddr; } @@ -101,13 +125,19 @@ static void vb2_dc_prepare(void *buf_priv) struct vb2_dc_buf *buf = buf_priv; struct sg_table *sgt = buf->dma_sgt; + /* This takes care of DMABUF and user-enforced cache sync hint */ if (buf->vb->skip_cache_sync_on_prepare) return; - if (!sgt) + if (!buf->non_coherent_mem) return; + /* For both USERPTR and non-coherent MMAP */ dma_sync_sgtable_for_device(buf->dev, sgt, buf->dma_dir); + + /* Non-coherent MMAP only */ + if (buf->vaddr) + flush_kernel_vmap_range(buf->vaddr, buf->size); } static void vb2_dc_finish(void *buf_priv) @@ -115,13 +145,19 @@ static void vb2_dc_finish(void *buf_priv) struct vb2_dc_buf *buf = buf_priv; struct sg_table *sgt = buf->dma_sgt; + /* This takes care of DMABUF and user-enforced cache sync hint */ if (buf->vb->skip_cache_sync_on_finish) return; - if (!sgt) + if (!buf->non_coherent_mem) return; + /* For both USERPTR and non-coherent MMAP */ dma_sync_sgtable_for_cpu(buf->dev, sgt, buf->dma_dir); + + /* Non-coherent MMAP only */ + if (buf->vaddr) + invalidate_kernel_vmap_range(buf->vaddr, buf->size); } /*********************************************/ @@ -135,21 +171,69 @@ static void vb2_dc_put(void *buf_priv) if (!refcount_dec_and_test(&buf->refcount)) return; - if (buf->sgt_base) { - sg_free_table(buf->sgt_base); - kfree(buf->sgt_base); + if (buf->non_coherent_mem) { + if (buf->vaddr) + dma_vunmap_noncontiguous(buf->dev, buf->vaddr); + dma_free_noncontiguous(buf->dev, buf->size, + buf->dma_sgt, buf->dma_dir); + } else { + if (buf->sgt_base) { + sg_free_table(buf->sgt_base); + kfree(buf->sgt_base); + } + dma_free_attrs(buf->dev, buf->size, buf->cookie, + buf->dma_addr, buf->attrs); } - dma_free_attrs(buf->dev, buf->size, buf->cookie, buf->dma_addr, - buf->attrs); put_device(buf->dev); kfree(buf); } +static int vb2_dc_alloc_coherent(struct vb2_dc_buf *buf) +{ + struct vb2_queue *q = buf->vb->vb2_queue; + + buf->cookie = dma_alloc_attrs(buf->dev, + buf->size, + &buf->dma_addr, + GFP_KERNEL | q->gfp_flags, + buf->attrs); + if (!buf->cookie) + return -ENOMEM; + + if (q->dma_attrs & DMA_ATTR_NO_KERNEL_MAPPING) + return 0; + + buf->vaddr = buf->cookie; + return 0; +} + +static int vb2_dc_alloc_non_coherent(struct vb2_dc_buf *buf) +{ + struct vb2_queue *q = buf->vb->vb2_queue; + + buf->dma_sgt = dma_alloc_noncontiguous(buf->dev, + buf->size, + buf->dma_dir, + GFP_KERNEL | q->gfp_flags, + buf->attrs); + if (!buf->dma_sgt) + return -ENOMEM; + + buf->dma_addr = sg_dma_address(buf->dma_sgt->sgl); + + /* + * For non-coherent buffers the kernel mapping is created on demand + * in vb2_dc_vaddr(). + */ + return 0; +} + static void *vb2_dc_alloc(struct vb2_buffer *vb, struct device *dev, unsigned long size) { struct vb2_dc_buf *buf; + int ret; if (WARN_ON(!dev)) return ERR_PTR(-EINVAL); @@ -159,27 +243,28 @@ static void *vb2_dc_alloc(struct vb2_buffer *vb, return ERR_PTR(-ENOMEM); buf->attrs = vb->vb2_queue->dma_attrs; - buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr, - GFP_KERNEL | vb->vb2_queue->gfp_flags, - buf->attrs); - if (!buf->cookie) { - dev_err(dev, "dma_alloc_coherent of size %ld failed\n", size); - kfree(buf); - return ERR_PTR(-ENOMEM); - } - - if ((buf->attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0) - buf->vaddr = buf->cookie; + buf->dma_dir = vb->vb2_queue->dma_dir; + buf->vb = vb; + buf->non_coherent_mem = vb->vb2_queue->non_coherent_mem; + buf->size = size; /* Prevent the device from being released while the buffer is used */ buf->dev = get_device(dev); - buf->size = size; - buf->dma_dir = vb->vb2_queue->dma_dir; + + if (buf->non_coherent_mem) + ret = vb2_dc_alloc_non_coherent(buf); + else + ret = vb2_dc_alloc_coherent(buf); + + if (ret) { + dev_err(dev, "dma alloc of size %ld failed\n", size); + kfree(buf); + return ERR_PTR(-ENOMEM); + } buf->handler.refcount = &buf->refcount; buf->handler.put = vb2_dc_put; buf->handler.arg = buf; - buf->vb = vb; refcount_set(&buf->refcount, 1); @@ -196,9 +281,12 @@ static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma) return -EINVAL; } - ret = dma_mmap_attrs(buf->dev, vma, buf->cookie, - buf->dma_addr, buf->size, buf->attrs); - + if (buf->non_coherent_mem) + ret = dma_mmap_noncontiguous(buf->dev, vma, buf->size, + buf->dma_sgt); + else + ret = dma_mmap_attrs(buf->dev, vma, buf->cookie, buf->dma_addr, + buf->size, buf->attrs); if (ret) { pr_err("Remapping memory failed, error: %d\n", ret); return ret; @@ -360,9 +448,15 @@ vb2_dc_dmabuf_ops_end_cpu_access(struct dma_buf *dbuf, static int vb2_dc_dmabuf_ops_vmap(struct dma_buf *dbuf, struct dma_buf_map *map) { - struct vb2_dc_buf *buf = dbuf->priv; + struct vb2_dc_buf *buf; + void *vaddr; - dma_buf_map_set_vaddr(map, buf->vaddr); + buf = dbuf->priv; + vaddr = vb2_dc_vaddr(buf->vb, buf); + if (!vaddr) + return -EINVAL; + + dma_buf_map_set_vaddr(map, vaddr); return 0; } @@ -390,6 +484,9 @@ static struct sg_table *vb2_dc_get_base_sgt(struct vb2_dc_buf *buf) int ret; struct sg_table *sgt; + if (buf->non_coherent_mem) + return buf->dma_sgt; + sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); if (!sgt) { dev_err(buf->dev, "failed to alloc sg table\n"); @@ -567,6 +664,8 @@ static void *vb2_dc_get_userptr(struct vb2_buffer *vb, struct device *dev, buf->dma_addr = sg_dma_address(sgt->sgl); buf->dma_sgt = sgt; + buf->non_coherent_mem = 1; + out: buf->size = size; -- cgit v1.2.3 From 1e153520cd043d7b6086bb1f061347e55cebc11f Mon Sep 17 00:00:00 2001 From: Deepak R Varma Date: Sat, 1 May 2021 08:44:24 +0200 Subject: media: staging: media: atomisp: code formatting changes atomisp_csi2.c Several trivial code reformatting changes done according to the coding style guidelines. These changes improves code organisation and readability and also 4 address many chackpatch error, warning and check complaints. Signed-off-by: Deepak R Varma Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_csi2.c | 70 ++++++++++++------------ 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c index 11b6b1216473..4a9268bac8a9 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c @@ -22,13 +22,11 @@ #include "atomisp_internal.h" #include "atomisp-regs.h" -static struct v4l2_mbus_framefmt *__csi2_get_format(struct - atomisp_mipi_csi2_device - * csi2, - struct v4l2_subdev_state *sd_state, - enum - v4l2_subdev_format_whence - which, unsigned int pad) +static struct +v4l2_mbus_framefmt *__csi2_get_format(struct atomisp_mipi_csi2_device *csi2, + struct v4l2_subdev_state *sd_state, + enum v4l2_subdev_format_whence which, + unsigned int pad) { if (which == V4L2_SUBDEV_FORMAT_TRY) return v4l2_subdev_get_try_format(&csi2->subdev, sd_state, @@ -43,7 +41,7 @@ static struct v4l2_mbus_framefmt *__csi2_get_format(struct * @fh : V4L2 subdev file handle * @code : pointer to v4l2_subdev_pad_mbus_code_enum structure * return -EINVAL or zero on success -*/ + */ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -69,7 +67,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, * @pad: pad num * @fmt: pointer to v4l2 format structure * return -EINVAL or zero on success -*/ + */ static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -104,12 +102,12 @@ int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd, else actual_ffmt->code = atomisp_in_fmt_conv[0].code; - actual_ffmt->width = clamp_t( - u32, ffmt->width, ATOM_ISP_MIN_WIDTH, - ATOM_ISP_MAX_WIDTH); - actual_ffmt->height = clamp_t( - u32, ffmt->height, ATOM_ISP_MIN_HEIGHT, - ATOM_ISP_MAX_HEIGHT); + actual_ffmt->width = clamp_t(u32, ffmt->width, + ATOM_ISP_MIN_WIDTH, + ATOM_ISP_MAX_WIDTH); + actual_ffmt->height = clamp_t(u32, ffmt->height, + ATOM_ISP_MIN_HEIGHT, + ATOM_ISP_MAX_HEIGHT); tmp_ffmt = *ffmt = *actual_ffmt; @@ -132,7 +130,7 @@ int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd, * @pad: pad num * @fmt: pointer to v4l2 format structure * return -EINVAL or zero on success -*/ + */ static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -147,7 +145,7 @@ static int csi2_set_format(struct v4l2_subdev *sd, * @enable: Enable/disable stream (1/0) * * Return 0 on success or a negative error code otherwise. -*/ + */ static int csi2_set_stream(struct v4l2_subdev *sd, int enable) { return 0; @@ -184,7 +182,7 @@ static const struct v4l2_subdev_ops csi2_ops = { * @remote : Pointer to remote pad array * @flags : Link flags * return -EINVAL or zero on success -*/ + */ static int csi2_link_setup(struct media_entity *entity, const struct media_pad *local, const struct media_pad *remote, u32 flags) @@ -222,10 +220,10 @@ static const struct media_entity_operations csi2_media_ops = { }; /* -* ispcsi2_init_entities - Initialize subdev and media entity. -* @csi2: Pointer to ispcsi2 structure. -* return -ENOMEM or zero on success -*/ + * ispcsi2_init_entities - Initialize subdev and media entity. + * @csi2: Pointer to ispcsi2 structure. + * return -ENOMEM or zero on success + */ static int mipi_csi2_init_entities(struct atomisp_mipi_csi2_device *csi2, int port) { @@ -249,9 +247,8 @@ static int mipi_csi2_init_entities(struct atomisp_mipi_csi2_device *csi2, if (ret < 0) return ret; - csi2->formats[CSI2_PAD_SINK].code = - csi2->formats[CSI2_PAD_SOURCE].code = - atomisp_in_fmt_conv[0].code; + csi2->formats[CSI2_PAD_SINK].code = atomisp_in_fmt_conv[0].code; + csi2->formats[CSI2_PAD_SOURCE].code = atomisp_in_fmt_conv[0].code; return 0; } @@ -379,21 +376,22 @@ static void atomisp_csi2_configure_isp2401(struct atomisp_sub_device *asd) (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl) == 0) mipi_freq = ctrl.value; - clk_termen = atomisp_csi2_configure_calc(coeff_clk_termen, - mipi_freq, TERMEN_DEFAULT); - clk_settle = atomisp_csi2_configure_calc(coeff_clk_settle, - mipi_freq, SETTLE_DEFAULT); - dat_termen = atomisp_csi2_configure_calc(coeff_dat_termen, - mipi_freq, TERMEN_DEFAULT); - dat_settle = atomisp_csi2_configure_calc(coeff_dat_settle, - mipi_freq, SETTLE_DEFAULT); + clk_termen = atomisp_csi2_configure_calc(coeff_clk_termen, mipi_freq, + TERMEN_DEFAULT); + clk_settle = atomisp_csi2_configure_calc(coeff_clk_settle, mipi_freq, + SETTLE_DEFAULT); + dat_termen = atomisp_csi2_configure_calc(coeff_dat_termen, mipi_freq, + TERMEN_DEFAULT); + dat_settle = atomisp_csi2_configure_calc(coeff_dat_settle, mipi_freq, + SETTLE_DEFAULT); + for (n = 0; n < csi2_port_lanes[port] + 1; n++) { hrt_address base = csi2_port_base[port] + csi2_lane_base[n]; atomisp_css2_hw_store_32(base + CSI2_REG_RX_CSI_DLY_CNT_TERMEN, - n == 0 ? clk_termen : dat_termen); + n == 0 ? clk_termen : dat_termen); atomisp_css2_hw_store_32(base + CSI2_REG_RX_CSI_DLY_CNT_SETTLE, - n == 0 ? clk_settle : dat_settle); + n == 0 ? clk_settle : dat_settle); } } @@ -405,7 +403,7 @@ void atomisp_csi2_configure(struct atomisp_sub_device *asd) /* * atomisp_mipi_csi2_cleanup - Routine for module driver cleanup -*/ + */ void atomisp_mipi_csi2_cleanup(struct atomisp_device *isp) { } -- cgit v1.2.3 From 439b87fceb23e7d9c963171ffb2e73144f794cc2 Mon Sep 17 00:00:00 2001 From: Seongyong Park Date: Tue, 8 Jun 2021 17:24:50 +0200 Subject: media: video-i2c: more precise intervals between frames MLX90640 should ideally be working without a frame skip. In short, if a frame is skipped, then half of a frame loses correction information, having no way to retrieve its original compensation. This patch improves the timing in three ways: 1) Replaced schedule_timeout_interruptible() to usleep_range() The former "only ensures that it will sleep for at least schedule_delay (if not interrupted)", as pointed out by mchehab. As a result, the frame rate could lag behind than the actual capability of the hardware (Raspberry Pi would show a few Hz slower than set value) 2) Calculation based on us, not jiffies Jiffies usually has resolution of 100Hz, and possibly even cruder. MLX90640 can go up to 64Hz frame rate, which does not make sense to calculate the interval with aforementioned resolution. 3) Interval calculation based on the last frame's end time Using the start time of the current frame will probably make tiny bit of drift every time. This made more sense when I didn't realize 1), but it still makes sense without adding virtually any complexity, so this stays in. Signed-off-by: Seongyong Park Acked-by: Matt Ranostay Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/video-i2c.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index de12f38f347c..cb660b4bfd4b 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -441,14 +441,15 @@ static void buffer_queue(struct vb2_buffer *vb) static int video_i2c_thread_vid_cap(void *priv) { struct video_i2c_data *data = priv; - unsigned int delay = mult_frac(HZ, data->frame_interval.numerator, - data->frame_interval.denominator); + u32 delay = mult_frac(1000000UL, data->frame_interval.numerator, + data->frame_interval.denominator); + s64 end_us = ktime_to_us(ktime_get()); set_freezable(); do { - unsigned long start_jiffies = jiffies; struct video_i2c_buffer *vid_cap_buf = NULL; + s64 current_us; int schedule_delay; try_to_freeze(); @@ -475,12 +476,14 @@ static int video_i2c_thread_vid_cap(void *priv) VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); } - schedule_delay = delay - (jiffies - start_jiffies); - - if (time_after(jiffies, start_jiffies + delay)) - schedule_delay = delay; - - schedule_timeout_interruptible(schedule_delay); + end_us += delay; + current_us = ktime_to_us(ktime_get()); + if (current_us < end_us) { + schedule_delay = end_us - current_us; + usleep_range(schedule_delay * 3 / 4, schedule_delay); + } else { + end_us = current_us; + } } while (!kthread_should_stop()); return 0; -- cgit v1.2.3 From aea54c13488575ccd1b32dde2e057ea36eed123d Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 27 Jul 2021 07:40:32 +0200 Subject: media: s3c-camif: Remove unused including Remove including that don't need it. Signed-off-by: Cai Huoqing Acked-by: Randy Dunlap Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s3c-camif/camif-core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c index b6a03296c923..32892ab359ee 100644 --- a/drivers/media/platform/s3c-camif/camif-core.c +++ b/drivers/media/platform/s3c-camif/camif-core.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From 538314dbfc8adbe8af64a13c9f14e907a0a887fb Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 14:46:49 +0200 Subject: media: usb: stkwebcam: Update the reference count of the usb device structure Use usb_get_dev() to increment the reference count of the usb device structure in order to avoid releasing the structure while it is still in use. And use usb_put_dev() to decrement the reference count and thus, when it will be equal to 0 the structure will be released. Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 0e231e576dc3..9f445e6ab5fa 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -1234,6 +1234,11 @@ static void stk_v4l_dev_release(struct video_device *vd) if (dev->sio_bufs != NULL || dev->isobufs != NULL) pr_err("We are leaking memory\n"); usb_put_intf(dev->interface); + usb_put_dev(dev->udev); + + v4l2_ctrl_handler_free(&dev->hdl); + v4l2_device_unregister(&dev->v4l2_dev); + kfree(dev); } static const struct video_device stk_v4l_data = { @@ -1309,7 +1314,7 @@ static int stk_camera_probe(struct usb_interface *interface, init_waitqueue_head(&dev->wait_frame); dev->first_init = 1; /* webcam LED management */ - dev->udev = udev; + dev->udev = usb_get_dev(udev); dev->interface = interface; usb_get_intf(interface); @@ -1365,6 +1370,7 @@ static int stk_camera_probe(struct usb_interface *interface, error_put: usb_put_intf(interface); + usb_put_dev(dev->udev); error: v4l2_ctrl_handler_free(hdl); v4l2_device_unregister(&dev->v4l2_dev); @@ -1385,9 +1391,6 @@ static void stk_camera_disconnect(struct usb_interface *interface) video_device_node_name(&dev->vdev)); video_unregister_device(&dev->vdev); - v4l2_ctrl_handler_free(&dev->hdl); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); } #ifdef CONFIG_PM -- cgit v1.2.3 From 4ba8d7046c04e0db11f3849643f894decb5e6d0a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 2 Sep 2021 12:31:37 +0200 Subject: media: ivtv: don't allow negative resolutions as module parameters This driver takes "osd_xres" and "osd_yres" as module parameters and caps the upper bounds but it doesn't cap the lower bounds. Obviously the admin is not going to enter negative resolutions but the possibility makes static analysis more difficult. Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtvfb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index e2d56dca5be4..c58ca8aa6d90 100644 --- a/drivers/media/pci/ivtv/ivtvfb.c +++ b/drivers/media/pci/ivtv/ivtvfb.c @@ -48,8 +48,8 @@ static bool osd_laced; static int osd_depth; static int osd_upper; static int osd_left; -static int osd_yres; -static int osd_xres; +static unsigned int osd_yres; +static unsigned int osd_xres; module_param(ivtvfb_card_id, int, 0444); module_param_named(debug,ivtvfb_debug, int, 0644); @@ -58,8 +58,8 @@ module_param(osd_laced, bool, 0444); module_param(osd_depth, int, 0444); module_param(osd_upper, int, 0444); module_param(osd_left, int, 0444); -module_param(osd_yres, int, 0444); -module_param(osd_xres, int, 0444); +module_param(osd_yres, uint, 0444); +module_param(osd_xres, uint, 0444); MODULE_PARM_DESC(ivtvfb_card_id, "Only use framebuffer of the specified ivtv card (0-31)\n" -- cgit v1.2.3 From 594a2edbcce5f96a58c3e969693e5394b801d52e Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Thu, 2 Sep 2021 13:46:41 +0200 Subject: media: MAINTAINERS: Add linux-renesas-soc mailing list to renesas JPU 'linux-renesas-soc' is the mailing list for renesas SOC driver, so add it to renesas JPU driver info. Signed-off-by: Cai Huoqing Reviewed-by: Geert Uytterhoeven Reviewed-by: Kieran Bingham Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index f3761373e7c5..d7e0febe278b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10033,6 +10033,7 @@ F: include/linux/jbd2.h JPU V4L2 MEM2MEM DRIVER FOR RENESAS M: Mikhail Ulyanov L: linux-media@vger.kernel.org +L: linux-renesas-soc@vger.kernel.org S: Maintained F: drivers/media/platform/rcar_jpu.c -- cgit v1.2.3 From 49b6f9b27ff0fcbee0c034cd56cd5e89fb7cfc31 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 2 Sep 2021 17:25:01 +0200 Subject: media: MAINTAINERS, .mailmap: Update Ezequiel Garcia's email address Update the media drivers I maintain to use my personal mail address. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .mailmap | 1 + MAINTAINERS | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.mailmap b/.mailmap index 6e849110cb4e..4f6e37da6058 100644 --- a/.mailmap +++ b/.mailmap @@ -98,6 +98,7 @@ Douglas Gilbert Ed L. Cashin Erik Kaneda Evgeniy Polyakov +Ezequiel Garcia Felipe W Damasio Felix Kuhling Felix Moeller diff --git a/MAINTAINERS b/MAINTAINERS index d7e0febe278b..c4c8de673fc9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8190,7 +8190,7 @@ T: git git://linuxtv.org/anttip/media_tree.git F: drivers/media/usb/hackrf/ HANTRO VPU CODEC DRIVER -M: Ezequiel Garcia +M: Ezequiel Garcia M: Philipp Zabel L: linux-media@vger.kernel.org L: linux-rockchip@lists.infradead.org @@ -16120,7 +16120,7 @@ F: include/uapi/linux/rkisp1-config.h ROCKCHIP RASTER 2D GRAPHIC ACCELERATION UNIT DRIVER M: Jacob Chen -M: Ezequiel Garcia +M: Ezequiel Garcia L: linux-media@vger.kernel.org L: linux-rockchip@lists.infradead.org S: Maintained @@ -16128,7 +16128,7 @@ F: Documentation/devicetree/bindings/media/rockchip-rga.yaml F: drivers/media/platform/rockchip/rga/ ROCKCHIP VIDEO DECODER DRIVER -M: Ezequiel Garcia +M: Ezequiel Garcia L: linux-media@vger.kernel.org L: linux-rockchip@lists.infradead.org S: Maintained -- cgit v1.2.3 From e4625044d656f3c33ece0cc9da22577bc10ca5d3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 5 Sep 2021 01:28:08 +0200 Subject: media: i2c: ths8200 needs V4L2_ASYNC Fix the build errors reported by the kernel test robot by selecting V4L2_ASYNC: mips-linux-ld: drivers/media/i2c/ths8200.o: in function `ths8200_remove': ths8200.c:(.text+0x1ec): undefined reference to `v4l2_async_unregister_subdev' mips-linux-ld: drivers/media/i2c/ths8200.o: in function `ths8200_probe': ths8200.c:(.text+0x404): undefined reference to `v4l2_async_register_subdev' Fixes: ed29f89497006 ("media: i2c: ths8200: support asynchronous probing") Signed-off-by: Randy Dunlap Reported-by: kernel test robot Reviewed-by: Lad Prabhakar Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index cfbcda1f7e48..adb348aa8396 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -597,6 +597,7 @@ config VIDEO_AK881X config VIDEO_THS8200 tristate "Texas Instruments THS8200 video encoder" depends on VIDEO_V4L2 && I2C + select V4L2_ASYNC help Support for the Texas Instruments THS8200 video encoder. -- cgit v1.2.3 From 79b48af2126d4750ff3e5e4acba9fbe1e33870f5 Mon Sep 17 00:00:00 2001 From: zhaoxiao Date: Mon, 6 Sep 2021 09:00:13 +0200 Subject: media: Media: meson: vdec: Use devm_platform_ioremap_resource_byname() Use the devm_platform_ioremap_resource_byname() helper instead of calling platform_get_resource_byname() and devm_ioremap_resource() separately. Signed-off-by: zhaoxiao Reviewed-by: Neil Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/meson/vdec/vdec.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c index e51d69c4729d..8549d95be0f2 100644 --- a/drivers/staging/media/meson/vdec/vdec.c +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -994,7 +994,6 @@ static int vdec_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct video_device *vdev; struct amvdec_core *core; - struct resource *r; const struct of_device_id *of_id; int irq; int ret; @@ -1006,13 +1005,11 @@ static int vdec_probe(struct platform_device *pdev) core->dev = dev; platform_set_drvdata(pdev, core); - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dos"); - core->dos_base = devm_ioremap_resource(dev, r); + core->dos_base = devm_platform_ioremap_resource_byname(pdev, "dos"); if (IS_ERR(core->dos_base)) return PTR_ERR(core->dos_base); - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "esparser"); - core->esparser_base = devm_ioremap_resource(dev, r); + core->esparser_base = devm_platform_ioremap_resource_byname(pdev, "esparser"); if (IS_ERR(core->esparser_base)) return PTR_ERR(core->esparser_base); -- cgit v1.2.3 From 645d74c59f1471dcbdc30882a25fd593326f05b7 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Tue, 7 Sep 2021 16:56:37 +0200 Subject: media: hantro: Fix media device bus_info string Even if model and bus_info currently both are 32 bytes large, use the correct array size for bus_info. Signed-off-by: Martin Kepplinger Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 41345b9e54bd..2d88fbb0445b 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -980,7 +980,7 @@ static int hantro_probe(struct platform_device *pdev) vpu->mdev.dev = vpu->dev; strscpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model)); strscpy(vpu->mdev.bus_info, "platform: " DRIVER_NAME, - sizeof(vpu->mdev.model)); + sizeof(vpu->mdev.bus_info)); media_device_init(&vpu->mdev); vpu->mdev.ops = &hantro_m2m_media_ops; vpu->v4l2_dev.mdev = &vpu->mdev; -- cgit v1.2.3 From 6d0d779b212c27293d9ccb4da092ff0ccb6efa39 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Wed, 8 Sep 2021 10:47:46 +0200 Subject: media: imx: set a media_device bus_info string Some tools like v4l2-compliance let users select a media device based on the bus_info string which can be quite convenient. Use a unique string for that. This also fixes the following v4l2-compliance warning: warn: v4l2-test-media.cpp(52): empty bus_info Signed-off-by: Martin Kepplinger Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-dev-common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/media/imx/imx-media-dev-common.c b/drivers/staging/media/imx/imx-media-dev-common.c index d006e961d8f4..80b69a9a752c 100644 --- a/drivers/staging/media/imx/imx-media-dev-common.c +++ b/drivers/staging/media/imx/imx-media-dev-common.c @@ -367,6 +367,8 @@ struct imx_media_dev *imx_media_dev_init(struct device *dev, imxmd->v4l2_dev.notify = imx_media_notify; strscpy(imxmd->v4l2_dev.name, "imx-media", sizeof(imxmd->v4l2_dev.name)); + snprintf(imxmd->md.bus_info, sizeof(imxmd->md.bus_info), + "platform:%s", dev_name(imxmd->md.dev)); media_device_init(&imxmd->md); -- cgit v1.2.3 From 8ed852834683ebe064157e069af8dfb41cad6403 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Wed, 8 Sep 2021 12:56:09 +0200 Subject: media: sun6i-csi: Allow the video device to be open multiple times Previously it was possible, but a recent fix for uninitialized `ret` variable broke this behavior. v4l2_fh_is_singular_file() check is there just to determine whether the power needs to be enabled, and it's not a failure if it returns false. Fixes: ba9139116bc0 ("media: sun6i-csi: add a missing return code") Signed-off-by: Ondrej Jirman Reviewed-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 33459892c1a9..607a8d39fbe2 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -467,7 +467,7 @@ static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = { static int sun6i_video_open(struct file *file) { struct sun6i_video *video = video_drvdata(file); - int ret; + int ret = 0; if (mutex_lock_interruptible(&video->lock)) return -ERESTARTSYS; @@ -481,10 +481,8 @@ static int sun6i_video_open(struct file *file) goto fh_release; /* check if already powered */ - if (!v4l2_fh_is_singular_file(file)) { - ret = -EBUSY; + if (!v4l2_fh_is_singular_file(file)) goto unlock; - } ret = sun6i_csi_set_power(video->csi, true); if (ret < 0) -- cgit v1.2.3 From 5a3683d60e56f4faa9552d3efafd87ef106dd393 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 8 Sep 2021 12:57:59 +0200 Subject: media: staging: media: rkvdec: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkvdec/rkvdec.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index 7131156c1f2c..bf00fe6534a3 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -967,7 +967,6 @@ static const char * const rkvdec_clk_names[] = { static int rkvdec_probe(struct platform_device *pdev) { struct rkvdec_dev *rkvdec; - struct resource *res; unsigned int i; int ret, irq; @@ -999,8 +998,7 @@ static int rkvdec_probe(struct platform_device *pdev) */ clk_set_rate(rkvdec->clocks[0].clk, 500 * 1000 * 1000); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - rkvdec->regs = devm_ioremap_resource(&pdev->dev, res); + rkvdec->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(rkvdec->regs)) return PTR_ERR(rkvdec->regs); -- cgit v1.2.3 From 1c43c1ecd6a4dd0673f097ee11f5566a1ff25ef7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 10 Sep 2021 13:39:57 +0200 Subject: media: saa7164: Remove redundant assignment of pointer t The pointer t is being assigned a value that is never read, it is being updated later on inside the for-loop. The assignment is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7164/saa7164-api.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/pci/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c index 4ddd0f5b50f1..5526bcc7a9bd 100644 --- a/drivers/media/pci/saa7164/saa7164-api.c +++ b/drivers/media/pci/saa7164/saa7164-api.c @@ -1057,8 +1057,6 @@ static int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) dprintk(DBGLVL_API, " numformats = 0x%x\n", vcoutputtermhdr->numformats); - t = (struct tmComResDescrHeader *) - ((struct tmComResDMATermDescrHeader *)(buf + idx)); next_offset = idx + (vcoutputtermhdr->len); for (i = 0; i < vcoutputtermhdr->numformats; i++) { t = (struct tmComResDescrHeader *) -- cgit v1.2.3 From a5991c4e947153418f71f4689614b87ca0551b81 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Sat, 11 Sep 2021 21:19:58 +0200 Subject: media: rcar-vin: Use user provided buffers when starting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When adding an internal scratch buffer to improve buffer handling when stopping it was also erroneously used when syncing at capture start. This led to that the first three buffers captured were always dropped as they were captured in the scratch buffer instead of in a buffer provided by the user. Allow the hardware to be given user provided buffers when preparing for capture in the stopped state. This still allows the driver to sync with the hardware and always completes the buffers to user-space in the correct order as no buffers are completed before the sync is complete. This change improves the driver as buffers are completed and given to the user three frames earlier than before. The change also fixes a warning produced by v4l2-compliance, warn: v4l2-test-buffers.cpp(448): got sequence number 3, expected 0 [hverkuil: fixed some typos in the Subject and the log message] Signed-off-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-dma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 58718e52ae54..e5162bf42bd0 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -906,7 +906,8 @@ static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot) vin->format.sizeimage / 2; break; } - } else if (vin->state != RUNNING || list_empty(&vin->buf_list)) { + } else if ((vin->state != STOPPED && vin->state != RUNNING) || + list_empty(&vin->buf_list)) { vin->buf_hw[slot].buffer = NULL; vin->buf_hw[slot].type = FULL; phys_addr = vin->scratch_phys; -- cgit v1.2.3 From 9b4a9b31b9aeef262b4fa211f2083c30c4391df7 Mon Sep 17 00:00:00 2001 From: Pedro Terra Date: Tue, 31 Aug 2021 19:48:22 +0200 Subject: media: vimc: Enable set resolution at the scaler src pad Modify the scaler subdevice to accept setting the resolution of the source pad (previously the source resolution would always be 3 times the sink for both dimensions). Now any resolution can be set at src (even smaller ones) and the sink video will be scaled to match it. Test example: With the vimc module up (using the default vimc topology) media-ctl -d platform:vimc -V '"Sensor A":0[fmt:SBGGR8_1X8/640x480]' media-ctl -d platform:vimc -V '"Debayer A":0[fmt:SBGGR8_1X8/640x480]' media-ctl -d platform:vimc -V '"Scaler":0[fmt:RGB888_1X24/640x480]' media-ctl -d platform:vimc -V '"Scaler":0[crop:(100,50)/400x150]' media-ctl -d platform:vimc -V '"Scaler":1[fmt:RGB888_1X24/300x700]' v4l2-ctl -z platform:vimc -d "RGB/YUV Capture" -v width=300,height=700 v4l2-ctl -z platform:vimc -d "Raw Capture 0" -v pixelformat=BA81 v4l2-ctl --stream-mmap --stream-count=10 -z platform:vimc -d "RGB/YUV Capture" \ --stream-to=test.raw The result will be a cropped stream that can be checked with the command ffplay -loglevel warning -v info -f rawvideo -pixel_format rgb24 \ -video_size "300x700" test.raw Co-developed-by: Gabriela Bittencourt Signed-off-by: Gabriela Bittencourt Co-developed-by: Gabriel Francisco Mandaji Signed-off-by: Gabriel Francisco Mandaji Signed-off-by: Pedro Terra Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/admin-guide/media/vimc.rst | 20 +- drivers/media/test-drivers/vimc/vimc-scaler.c | 366 ++++++++++---------------- 2 files changed, 148 insertions(+), 238 deletions(-) diff --git a/Documentation/admin-guide/media/vimc.rst b/Documentation/admin-guide/media/vimc.rst index 211cc8972410..180507d455f2 100644 --- a/Documentation/admin-guide/media/vimc.rst +++ b/Documentation/admin-guide/media/vimc.rst @@ -61,9 +61,10 @@ vimc-debayer: * 1 Pad source vimc-scaler: - Scale up the image by a factor of 3. E.g.: a 640x480 image becomes a - 1920x1440 image. (this value can be configured, see at - `Module options`_). + Re-size the image to meet the source pad resolution. E.g.: if the sync + pad is configured to 360x480 and the source to 1280x720, the image will + be stretched to fit the source resolution. Works for any resolution + within the vimc limitations (even shrinking the image if necessary). Exposes: * 1 Pad sink @@ -75,16 +76,3 @@ vimc-capture: * 1 Pad sink * 1 Pad source - - -Module options --------------- - -Vimc has a module parameter to configure the driver. - -* ``sca_mult=`` - - Image size multiplier factor to be used to multiply both width and - height, so the image size will be ``sca_mult^2`` bigger than the - original one. Currently, only supports scaling up (the default value - is 3). diff --git a/drivers/media/test-drivers/vimc/vimc-scaler.c b/drivers/media/test-drivers/vimc/vimc-scaler.c index 06880dd0b6ac..820b8f5b502f 100644 --- a/drivers/media/test-drivers/vimc/vimc-scaler.c +++ b/drivers/media/test-drivers/vimc/vimc-scaler.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -13,11 +14,11 @@ #include "vimc-common.h" -static unsigned int sca_mult = 3; -module_param(sca_mult, uint, 0000); -MODULE_PARM_DESC(sca_mult, " the image size multiplier"); - -#define MAX_ZOOM 8 +/* Pad identifier */ +enum vic_sca_pad { + VIMC_SCA_SINK = 0, + VIMC_SCA_SRC = 1, +}; #define VIMC_SCA_FMT_WIDTH_DEFAULT 640 #define VIMC_SCA_FMT_HEIGHT_DEFAULT 480 @@ -25,19 +26,16 @@ MODULE_PARM_DESC(sca_mult, " the image size multiplier"); struct vimc_sca_device { struct vimc_ent_device ved; struct v4l2_subdev sd; - /* NOTE: the source fmt is the same as the sink - * with the width and hight multiplied by mult - */ - struct v4l2_mbus_framefmt sink_fmt; struct v4l2_rect crop_rect; + /* Frame format for both sink and src pad */ + struct v4l2_mbus_framefmt fmt[2]; /* Values calculated when the stream starts */ u8 *src_frame; - unsigned int src_line_size; unsigned int bpp; struct media_pad pads[2]; }; -static const struct v4l2_mbus_framefmt sink_fmt_default = { +static const struct v4l2_mbus_framefmt fmt_default = { .width = VIMC_SCA_FMT_WIDTH_DEFAULT, .height = VIMC_SCA_FMT_HEIGHT_DEFAULT, .code = MEDIA_BUS_FMT_RGB888_1X24, @@ -72,17 +70,6 @@ vimc_sca_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt) return r; } -static void vimc_sca_adjust_sink_crop(struct v4l2_rect *r, - const struct v4l2_mbus_framefmt *sink_fmt) -{ - const struct v4l2_rect sink_rect = - vimc_sca_get_crop_bound_sink(sink_fmt); - - /* Disallow rectangles smaller than the minimal one. */ - v4l2_rect_set_min_size(r, &crop_rect_min); - v4l2_rect_map_inside(r, &sink_rect); -} - static int vimc_sca_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { @@ -90,19 +77,14 @@ static int vimc_sca_init_cfg(struct v4l2_subdev *sd, struct v4l2_rect *r; unsigned int i; - mf = v4l2_subdev_get_try_format(sd, sd_state, 0); - *mf = sink_fmt_default; - - r = v4l2_subdev_get_try_crop(sd, sd_state, 0); - *r = crop_rect_default; - - for (i = 1; i < sd->entity.num_pads; i++) { + for (i = 0; i < sd->entity.num_pads; i++) { mf = v4l2_subdev_get_try_format(sd, sd_state, i); - *mf = sink_fmt_default; - mf->width = mf->width * sca_mult; - mf->height = mf->height * sca_mult; + *mf = fmt_default; } + r = v4l2_subdev_get_try_crop(sd, sd_state, VIMC_SCA_SINK); + *r = crop_rect_default; + return 0; } @@ -144,112 +126,108 @@ static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd, fse->min_width = VIMC_FRAME_MIN_WIDTH; fse->min_height = VIMC_FRAME_MIN_HEIGHT; - if (VIMC_IS_SINK(fse->pad)) { - fse->max_width = VIMC_FRAME_MAX_WIDTH; - fse->max_height = VIMC_FRAME_MAX_HEIGHT; - } else { - fse->max_width = VIMC_FRAME_MAX_WIDTH * MAX_ZOOM; - fse->max_height = VIMC_FRAME_MAX_HEIGHT * MAX_ZOOM; - } + fse->max_width = VIMC_FRAME_MAX_WIDTH; + fse->max_height = VIMC_FRAME_MAX_HEIGHT; return 0; } +static struct v4l2_mbus_framefmt * +vimc_sca_pad_format(struct vimc_sca_device *vsca, + struct v4l2_subdev_state *sd_state, u32 pad, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&vsca->sd, sd_state, pad); + else + return &vsca->fmt[pad]; +} + +static struct v4l2_rect * +vimc_sca_pad_crop(struct vimc_sca_device *vsca, + struct v4l2_subdev_state *sd_state, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_crop(&vsca->sd, sd_state, + VIMC_SCA_SINK); + else + return &vsca->crop_rect; +} + static int vimc_sca_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); - struct v4l2_rect *crop_rect; - - /* Get the current sink format */ - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0); - crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0); - } else { - format->format = vsca->sink_fmt; - crop_rect = &vsca->crop_rect; - } - - /* Scale the frame size for the source pad */ - if (VIMC_IS_SRC(format->pad)) { - format->format.width = crop_rect->width * sca_mult; - format->format.height = crop_rect->height * sca_mult; - } + format->format = *vimc_sca_pad_format(vsca, sd_state, format->pad, + format->which); return 0; } -static void vimc_sca_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) -{ - const struct vimc_pix_map *vpix; - - /* Only accept code in the pix map table in non bayer format */ - vpix = vimc_pix_map_by_code(fmt->code); - if (!vpix || vpix->bayer) - fmt->code = sink_fmt_default.code; - - fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH, - VIMC_FRAME_MAX_WIDTH) & ~1; - fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT, - VIMC_FRAME_MAX_HEIGHT) & ~1; - - if (fmt->field == V4L2_FIELD_ANY) - fmt->field = sink_fmt_default.field; - - vimc_colorimetry_clamp(fmt); -} - static int vimc_sca_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) + struct v4l2_subdev_format *format) { struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *sink_fmt; - struct v4l2_rect *crop_rect; + struct v4l2_mbus_framefmt *fmt; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - /* Do not change the format while stream is on */ - if (vsca->src_frame) - return -EBUSY; + /* Do not change the active format while stream is on */ + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && vsca->src_frame) + return -EBUSY; - sink_fmt = &vsca->sink_fmt; - crop_rect = &vsca->crop_rect; - } else { - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); - crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0); + fmt = vimc_sca_pad_format(vsca, sd_state, format->pad, format->which); + + /* + * The media bus code and colorspace can only be changed on the sink + * pad, the source pad only follows. + */ + if (format->pad == VIMC_SCA_SINK) { + const struct vimc_pix_map *vpix; + + /* Only accept code in the pix map table in non bayer format. */ + vpix = vimc_pix_map_by_code(format->format.code); + if (vpix && !vpix->bayer) + fmt->code = format->format.code; + else + fmt->code = fmt_default.code; + + /* Clamp the colorspace to valid values. */ + fmt->colorspace = format->format.colorspace; + fmt->ycbcr_enc = format->format.ycbcr_enc; + fmt->quantization = format->format.quantization; + fmt->xfer_func = format->format.xfer_func; + vimc_colorimetry_clamp(fmt); } + /* Clamp and align the width and height */ + fmt->width = clamp_t(u32, format->format.width, VIMC_FRAME_MIN_WIDTH, + VIMC_FRAME_MAX_WIDTH) & ~1; + fmt->height = clamp_t(u32, format->format.height, VIMC_FRAME_MIN_HEIGHT, + VIMC_FRAME_MAX_HEIGHT) & ~1; + /* - * Do not change the format of the source pad, - * it is propagated from the sink + * Propagate the sink pad format to the crop rectangle and the source + * pad. */ - if (VIMC_IS_SRC(fmt->pad)) { - fmt->format = *sink_fmt; - fmt->format.width = crop_rect->width * sca_mult; - fmt->format.height = crop_rect->height * sca_mult; - } else { - /* Set the new format in the sink pad */ - vimc_sca_adjust_sink_fmt(&fmt->format); - - dev_dbg(vsca->ved.dev, "%s: sink format update: " - "old:%dx%d (0x%x, %d, %d, %d, %d) " - "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsca->sd.name, - /* old */ - sink_fmt->width, sink_fmt->height, sink_fmt->code, - sink_fmt->colorspace, sink_fmt->quantization, - sink_fmt->xfer_func, sink_fmt->ycbcr_enc, - /* new */ - fmt->format.width, fmt->format.height, fmt->format.code, - fmt->format.colorspace, fmt->format.quantization, - fmt->format.xfer_func, fmt->format.ycbcr_enc); - - *sink_fmt = fmt->format; - - /* Do the crop, but respect the current bounds */ - vimc_sca_adjust_sink_crop(crop_rect, sink_fmt); + if (format->pad == VIMC_SCA_SINK) { + struct v4l2_mbus_framefmt *src_fmt; + struct v4l2_rect *crop; + + crop = vimc_sca_pad_crop(vsca, sd_state, format->which); + crop->width = fmt->width; + crop->height = fmt->height; + crop->top = 0; + crop->left = 0; + + src_fmt = vimc_sca_pad_format(vsca, sd_state, VIMC_SCA_SRC, + format->which); + *src_fmt = *fmt; } + format->format = *fmt; + return 0; } @@ -259,24 +237,17 @@ static int vimc_sca_get_selection(struct v4l2_subdev *sd, { struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *sink_fmt; - struct v4l2_rect *crop_rect; if (VIMC_IS_SRC(sel->pad)) return -EINVAL; - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - sink_fmt = &vsca->sink_fmt; - crop_rect = &vsca->crop_rect; - } else { - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); - crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0); - } - switch (sel->target) { case V4L2_SEL_TGT_CROP: - sel->r = *crop_rect; + sel->r = *vimc_sca_pad_crop(vsca, sd_state, sel->which); break; case V4L2_SEL_TGT_CROP_BOUNDS: + sink_fmt = vimc_sca_pad_format(vsca, sd_state, VIMC_SCA_SINK, + sel->which); sel->r = vimc_sca_get_crop_bound_sink(sink_fmt); break; default: @@ -286,6 +257,17 @@ static int vimc_sca_get_selection(struct v4l2_subdev *sd, return 0; } +static void vimc_sca_adjust_sink_crop(struct v4l2_rect *r, + const struct v4l2_mbus_framefmt *sink_fmt) +{ + const struct v4l2_rect sink_rect = + vimc_sca_get_crop_bound_sink(sink_fmt); + + /* Disallow rectangles smaller than the minimal one. */ + v4l2_rect_set_min_size(r, &crop_rect_min); + v4l2_rect_map_inside(r, &sink_rect); +} + static int vimc_sca_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) @@ -294,30 +276,18 @@ static int vimc_sca_set_selection(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *crop_rect; - if (VIMC_IS_SRC(sel->pad)) + /* Only support setting the crop of the sink pad */ + if (VIMC_IS_SRC(sel->pad) || sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - /* Do not change the format while stream is on */ - if (vsca->src_frame) - return -EBUSY; + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && vsca->src_frame) + return -EBUSY; - crop_rect = &vsca->crop_rect; - sink_fmt = &vsca->sink_fmt; - } else { - crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0); - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); - } - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - /* Do the crop, but respect the current bounds */ - vimc_sca_adjust_sink_crop(&sel->r, sink_fmt); - *crop_rect = sel->r; - break; - default: - return -EINVAL; - } + crop_rect = vimc_sca_pad_crop(vsca, sd_state, sel->which); + sink_fmt = vimc_sca_pad_format(vsca, sd_state, VIMC_SCA_SINK, + sel->which); + vimc_sca_adjust_sink_crop(&sel->r, sink_fmt); + *crop_rect = sel->r; return 0; } @@ -344,16 +314,12 @@ static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable) return 0; /* Save the bytes per pixel of the sink */ - vpix = vimc_pix_map_by_code(vsca->sink_fmt.code); + vpix = vimc_pix_map_by_code(vsca->fmt[VIMC_SCA_SINK].code); vsca->bpp = vpix->bpp; - /* Calculate the width in bytes of the src frame */ - vsca->src_line_size = vsca->crop_rect.width * - sca_mult * vsca->bpp; - /* Calculate the frame size of the source pad */ - frame_size = vsca->src_line_size * vsca->crop_rect.height * - sca_mult; + frame_size = vsca->fmt[VIMC_SCA_SRC].width + * vsca->fmt[VIMC_SCA_SRC].height * vsca->bpp; /* Allocate the frame buffer. Use vmalloc to be able to * allocate a large amount of memory @@ -382,77 +348,32 @@ static const struct v4l2_subdev_ops vimc_sca_ops = { .video = &vimc_sca_video_ops, }; -static void vimc_sca_fill_pix(u8 *const ptr, - const u8 *const pixel, - const unsigned int bpp) -{ - unsigned int i; - - /* copy the pixel to the pointer */ - for (i = 0; i < bpp; i++) - ptr[i] = pixel[i]; -} - -static void vimc_sca_scale_pix(const struct vimc_sca_device *const vsca, - unsigned int lin, unsigned int col, - const u8 *const sink_frame) -{ - const struct v4l2_rect crop_rect = vsca->crop_rect; - unsigned int i, j, index; - const u8 *pixel; - - /* Point to the pixel value in position (lin, col) in the sink frame */ - index = VIMC_FRAME_INDEX(lin, col, - vsca->sink_fmt.width, - vsca->bpp); - pixel = &sink_frame[index]; - - dev_dbg(vsca->ved.dev, - "sca: %s: --- scale_pix sink pos %dx%d, index %d ---\n", - vsca->sd.name, lin, col, index); - - /* point to the place we are going to put the first pixel - * in the scaled src frame - */ - lin -= crop_rect.top; - col -= crop_rect.left; - index = VIMC_FRAME_INDEX(lin * sca_mult, col * sca_mult, - crop_rect.width * sca_mult, vsca->bpp); - - dev_dbg(vsca->ved.dev, "sca: %s: scale_pix src pos %dx%d, index %d\n", - vsca->sd.name, lin * sca_mult, col * sca_mult, index); - - /* Repeat this pixel mult times */ - for (i = 0; i < sca_mult; i++) { - /* Iterate through each beginning of a - * pixel repetition in a line - */ - for (j = 0; j < sca_mult * vsca->bpp; j += vsca->bpp) { - dev_dbg(vsca->ved.dev, - "sca: %s: sca: scale_pix src pos %d\n", - vsca->sd.name, index + j); - - /* copy the pixel to the position index + j */ - vimc_sca_fill_pix(&vsca->src_frame[index + j], - pixel, vsca->bpp); - } - - /* move the index to the next line */ - index += vsca->src_line_size; - } -} - static void vimc_sca_fill_src_frame(const struct vimc_sca_device *const vsca, const u8 *const sink_frame) { - const struct v4l2_rect r = vsca->crop_rect; - unsigned int i, j; - - /* Scale each pixel from the original sink frame */ - /* TODO: implement scale down, only scale up is supported for now */ - for (i = r.top; i < r.top + r.height; i++) - for (j = r.left; j < r.left + r.width; j++) - vimc_sca_scale_pix(vsca, i, j, sink_frame); + const struct v4l2_mbus_framefmt *src_fmt = &vsca->fmt[VIMC_SCA_SRC]; + const struct v4l2_rect *r = &vsca->crop_rect; + unsigned int snk_width = vsca->fmt[VIMC_SCA_SINK].width; + unsigned int src_x, src_y; + u8 *walker = vsca->src_frame; + + /* Set each pixel at the src_frame to its sink_frame equivalent */ + for (src_y = 0; src_y < src_fmt->height; src_y++) { + unsigned int snk_y, y_offset; + + snk_y = (src_y * r->height) / src_fmt->height + r->top; + y_offset = snk_y * snk_width * vsca->bpp; + + for (src_x = 0; src_x < src_fmt->width; src_x++) { + unsigned int snk_x, x_offset, index; + + snk_x = (src_x * r->width) / src_fmt->width + r->left; + x_offset = snk_x * vsca->bpp; + index = y_offset + x_offset; + memcpy(walker, &sink_frame[index], vsca->bpp); + walker += vsca->bpp; + } + } } static void *vimc_sca_process_frame(struct vimc_ent_device *ved, @@ -492,8 +413,8 @@ static struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc, return ERR_PTR(-ENOMEM); /* Initialize ved and sd */ - vsca->pads[0].flags = MEDIA_PAD_FL_SINK; - vsca->pads[1].flags = MEDIA_PAD_FL_SOURCE; + vsca->pads[VIMC_SCA_SINK].flags = MEDIA_PAD_FL_SINK; + vsca->pads[VIMC_SCA_SRC].flags = MEDIA_PAD_FL_SOURCE; ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev, vcfg_name, @@ -508,7 +429,8 @@ static struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc, vsca->ved.dev = vimc->mdev.dev; /* Initialize the frame format */ - vsca->sink_fmt = sink_fmt_default; + vsca->fmt[VIMC_SCA_SINK] = fmt_default; + vsca->fmt[VIMC_SCA_SRC] = fmt_default; /* Initialize the crop selection */ vsca->crop_rect = crop_rect_default; -- cgit v1.2.3 From ea7caaea6ed4ee1fe1ef5878ec29c40ecb082d1e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 21 Jul 2021 17:24:59 +0200 Subject: media: rcar_drif: select CONFIG_V4L2_ASYNC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this, I see a randconfig link failure: aarch64-linux-ld: drivers/media/platform/rcar_drif.o: in function `rcar_drif_remove': rcar_drif.c:(.text+0x2a8): undefined reference to `v4l2_async_notifier_unregister' aarch64-linux-ld: rcar_drif.c:(.text+0x2b0): undefined reference to `v4l2_async_notifier_cleanup' aarch64-linux-ld: drivers/media/platform/rcar_drif.o: in function `rcar_drif_sdr_probe': rcar_drif.c:(.text+0x1444): undefined reference to `v4l2_async_notifier_init' aarch64-linux-ld: rcar_drif.c:(.text+0x14a0): undefined reference to `v4l2_async_notifier_register' aarch64-linux-ld: rcar_drif.c:(.text+0x14d8): undefined reference to `v4l2_async_notifier_cleanup' aarch64-linux-ld: rcar_drif.c:(.text+0x15a8): undefined reference to `__v4l2_async_notifier_add_fwnode_subdev' I could not easily figure out when this was introduced, as this code has not changed in a while but I only saw the problem recently. Signed-off-by: Arnd Bergmann Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index aa277a19e275..d9f90084c2f6 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -638,6 +638,7 @@ config VIDEO_RCAR_DRIF depends on VIDEO_V4L2 depends on ARCH_RENESAS || COMPILE_TEST select VIDEOBUF2_VMALLOC + select V4L2_ASYNC help Say Y if you want to enable R-Car Gen3 DRIF support. DRIF is Digital Radio Interface that interfaces with an RF front end chip. It is a -- cgit v1.2.3 From dfadec236aa99f6086141949c9dc3ec50f3ff20d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 3 Aug 2021 21:46:08 +0200 Subject: media: radio-wl1273: Avoid card name truncation The "card" string only holds 31 characters (and the terminating NUL). In order to avoid truncation, use a shorter card description instead of the current result, "Texas Instruments Wl1273 FM Rad". Suggested-by: Hans Verkuil Fixes: 87d1a50ce451 ("[media] V4L2: WL1273 FM Radio: TI WL1273 FM radio driver") Signed-off-by: Kees Cook Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-wl1273.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 112376873167..484046471c03 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1279,7 +1279,7 @@ static int wl1273_fm_vidioc_querycap(struct file *file, void *priv, strscpy(capability->driver, WL1273_FM_DRIVER_NAME, sizeof(capability->driver)); - strscpy(capability->card, "Texas Instruments Wl1273 FM Radio", + strscpy(capability->card, "TI Wl1273 FM Radio", sizeof(capability->card)); strscpy(capability->bus_info, radio->bus_type, sizeof(capability->bus_info)); -- cgit v1.2.3 From 2908249f3878a591f7918368fdf0b7b0a6c3158c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 3 Aug 2021 21:46:09 +0200 Subject: media: si470x: Avoid card name truncation The "card" string only holds 31 characters (and the terminating NUL). In order to avoid truncation, use a shorter card description instead of the current result, "Silicon Labs Si470x FM Radio Re". Suggested-by: Hans Verkuil Fixes: 78656acdcf48 ("V4L/DVB (7038): USB radio driver for Silicon Labs Si470x FM Radio Receivers") Fixes: cc35bbddfe10 ("V4L/DVB (12416): radio-si470x: add i2c driver for si470x") Signed-off-by: Kees Cook Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/si470x/radio-si470x-i2c.c | 2 +- drivers/media/radio/si470x/radio-si470x-usb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index f491420d7b53..a972c0705ac7 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -11,7 +11,7 @@ /* driver definitions */ #define DRIVER_AUTHOR "Joonyoung Shim "; -#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" +#define DRIVER_CARD "Silicon Labs Si470x FM Radio" #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers" #define DRIVER_VERSION "1.0.2" diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index fedff68d8c49..3f8634a46573 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -16,7 +16,7 @@ /* driver definitions */ #define DRIVER_AUTHOR "Tobias Lorenz " -#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" +#define DRIVER_CARD "Silicon Labs Si470x FM Radio" #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" #define DRIVER_VERSION "1.0.10" -- cgit v1.2.3 From 42bb98e420d454fef3614b70ea11cc59068395f6 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 3 Aug 2021 21:46:10 +0200 Subject: media: tm6000: Avoid card name truncation The "card" string only holds 31 characters (and the terminating NUL). In order to avoid truncation, use a shorter card description instead of the current result, "Trident TVMaster TM5600/6000/60". Suggested-by: Hans Verkuil Fixes: e28f49b0b2a8 ("V4L/DVB: tm6000: fix some info messages") Signed-off-by: Kees Cook Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tm6000/tm6000-video.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 3f650ede0c3d..e293f6f3d1bc 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -852,8 +852,7 @@ static int vidioc_querycap(struct file *file, void *priv, struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev; strscpy(cap->driver, "tm6000", sizeof(cap->driver)); - strscpy(cap->card, "Trident TVMaster TM5600/6000/6010", - sizeof(cap->card)); + strscpy(cap->card, "Trident TM5600/6000/6010", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_DEVICE_CAPS; -- cgit v1.2.3 From 7266dda2f1dfe151b12ef0c14eb4d4e622fb211c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 4 Aug 2021 10:50:10 +0200 Subject: media: cx23885: Fix snd_card_free call on null card pointer Currently a call to snd_card_new that fails will set card with a NULL pointer, this causes a null pointer dereference on the error cleanup path when card it passed to snd_card_free. Fix this by adding a new error exit path that does not call snd_card_free and exiting via this new path. Addresses-Coverity: ("Explicit null dereference") Fixes: 9e44d63246a9 ("[media] cx23885: Add ALSA support") Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-alsa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index ab14d35214aa..25dc8d4dc5b7 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -550,7 +550,7 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev) SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, sizeof(struct cx23885_audio_dev), &card); if (err < 0) - goto error; + goto error_msg; chip = (struct cx23885_audio_dev *) card->private_data; chip->dev = dev; @@ -576,6 +576,7 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev) error: snd_card_free(card); +error_msg: pr_err("%s(): Failed to register analog audio adapter\n", __func__); -- cgit v1.2.3 From 9d45ccf721aac94efa5a014a9d40f9a0b2cee4e6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 4 Aug 2021 15:53:43 +0200 Subject: media: staging/media/meson: vdec.h: fix kerneldoc warnings Fix a bunch of kernel-doc warnings: drivers/staging/media/meson/vdec/esparser.h:22: warning: Function parameter or member 'core' not described in 'esparser_queue_eos' drivers/staging/media/meson/vdec/esparser.h:22: warning: Function parameter or member 'data' not described in 'esparser_queue_eos' drivers/staging/media/meson/vdec/esparser.h:22: warning: Function parameter or member 'len' not described in 'esparser_queue_eos' drivers/staging/media/meson/vdec/esparser.h:28: warning: Function parameter or member 'work' not described in 'esparser_queue_all_src' drivers/staging/media/meson/vdec/vdec.h:92: warning: Function parameter or member 'vdec_hevcf_clk' not described in 'amvdec_core' drivers/staging/media/meson/vdec/vdec.h:92: warning: Function parameter or member 'vdev_dec' not described in 'amvdec_core' drivers/staging/media/meson/vdec/vdec.h:92: warning: Function parameter or member 'lock' not described in 'amvdec_core' drivers/staging/media/meson/vdec/vdec.h:141: warning: Function parameter or member 'resume' not described in 'amvdec_codec_ops' drivers/staging/media/meson/vdec/vdec.h:274: warning: Function parameter or member 'lock' not described in 'amvdec_session' drivers/staging/media/meson/vdec/vdec.h:274: warning: Function parameter or member 'sequence_out' not described in 'amvdec_session' drivers/staging/media/meson/vdec/vdec.h:274: warning: Function parameter or member 'num_dst_bufs' not described in 'amvdec_session' drivers/staging/media/meson/vdec/vdec.h:274: warning: Function parameter or member 'changed_format' not described in 'amvdec_session' drivers/staging/media/meson/vdec/vdec.h:274: warning: Function parameter or member 'last_offset' not described in 'amvdec_session' drivers/staging/media/meson/vdec/vdec.h:274: warning: Function parameter or member 'wrap_count' not described in 'amvdec_session' drivers/staging/media/meson/vdec/vdec.h:274: warning: Function parameter or member 'fw_idx_to_vb2_idx' not described in 'amvdec_session' drivers/staging/media/meson/vdec/vdec_helpers.h:59: warning: Function parameter or member 'tc' not described in 'amvdec_add_ts' drivers/staging/media/meson/vdec/vdec_helpers.h:59: warning: Function parameter or member 'flags' not described in 'amvdec_add_ts' Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/meson/vdec/esparser.h | 6 +++++- drivers/staging/media/meson/vdec/vdec.h | 16 +++++++++++++--- drivers/staging/media/meson/vdec/vdec_helpers.h | 3 ++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/staging/media/meson/vdec/esparser.h b/drivers/staging/media/meson/vdec/esparser.h index ff51fe7fda66..9351e62c70e6 100644 --- a/drivers/staging/media/meson/vdec/esparser.h +++ b/drivers/staging/media/meson/vdec/esparser.h @@ -17,13 +17,17 @@ int esparser_power_up(struct amvdec_session *sess); /** * esparser_queue_eos() - write End Of Stream sequence to the ESPARSER * - * @core vdec core struct + * @core: vdec core struct + * @data: EOS sequence + * @len: length of EOS sequence */ int esparser_queue_eos(struct amvdec_core *core, const u8 *data, u32 len); /** * esparser_queue_all_src() - work handler that writes as many src buffers * as possible to the ESPARSER + * + * @work: work struct */ void esparser_queue_all_src(struct work_struct *work); diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h index f95445ac0658..0906b8fb5cc6 100644 --- a/drivers/staging/media/meson/vdec/vdec.h +++ b/drivers/staging/media/meson/vdec/vdec.h @@ -60,10 +60,12 @@ struct amvdec_session; * @dos_clk: DOS clock * @vdec_1_clk: VDEC_1 clock * @vdec_hevc_clk: VDEC_HEVC clock + * @vdec_hevcf_clk: VDEC_HEVCF clock * @esparser_reset: RESET for the PARSER - * @vdec_dec: video device for the decoder + * @vdev_dec: video device for the decoder * @v4l2_dev: v4l2 device * @cur_sess: current decoding session + * @lock: video device lock */ struct amvdec_core { void __iomem *dos_base; @@ -88,7 +90,7 @@ struct amvdec_core { struct v4l2_device v4l2_dev; struct amvdec_session *cur_sess; - struct mutex lock; /* video device lock */ + struct mutex lock; }; /** @@ -120,6 +122,7 @@ struct amvdec_ops { * @recycle: optional call to tell the codec to recycle a dst buffer. Must go * in pair with @can_recycle * @drain: optional call if the codec has a custom way of draining + * @resume: optional call to resume after a resolution change * @eos_sequence: optional call to get an end sequence to send to esparser * for flush. Mutually exclusive with @drain. * @isr: mandatory call when the ISR triggers @@ -185,6 +188,7 @@ enum amvdec_status { * @m2m_ctx: v4l2 m2m context * @ctrl_handler: V4L2 control handler * @ctrl_min_buf_capture: V4L2 control V4L2_CID_MIN_BUFFERS_FOR_CAPTURE + * @lock: cap & out queues lock * @fmt_out: vdec pixel format for the OUTPUT queue * @pixfmt_cap: V4L2 pixel format for the CAPTURE queue * @src_buffer_size: size in bytes of the OUTPUT buffers' only plane @@ -200,9 +204,12 @@ enum amvdec_status { * @streamon_cap: stream on flag for capture queue * @streamon_out: stream on flag for output queue * @sequence_cap: capture sequence counter + * @sequence_out: output sequence counter * @should_stop: flag set if userspace signaled EOS via command * or empty buffer * @keyframe_found: flag set once a keyframe has been parsed + * @num_dst_bufs: number of destination buffers + * @changed_format: the format changed * @canvas_alloc: array of all the canvas IDs allocated * @canvas_num: number of canvas IDs allocated * @vififo_vaddr: virtual address for the VIFIFO @@ -214,6 +221,9 @@ enum amvdec_status { * @timestamps: chronological list of src timestamps * @ts_spinlock: spinlock for the timestamps list * @last_irq_jiffies: tracks last time the vdec triggered an IRQ + * @last_offset: tracks last offset of vififo + * @wrap_count: number of times the vififo wrapped around + * @fw_idx_to_vb2_idx: firmware buffer index to vb2 buffer index * @status: current decoding status * @priv: codec private data */ @@ -225,7 +235,7 @@ struct amvdec_session { struct v4l2_m2m_ctx *m2m_ctx; struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl *ctrl_min_buf_capture; - struct mutex lock; /* cap & out queues lock */ + struct mutex lock; const struct amvdec_format *fmt_out; u32 pixfmt_cap; diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.h b/drivers/staging/media/meson/vdec/vdec_helpers.h index cfaed52ab526..88137d15aa3a 100644 --- a/drivers/staging/media/meson/vdec/vdec_helpers.h +++ b/drivers/staging/media/meson/vdec/vdec_helpers.h @@ -52,8 +52,9 @@ void amvdec_dst_buf_done_offset(struct amvdec_session *sess, * * @sess: current session * @ts: timestamp to add + * @tc: timecode to add * @offset: offset in the VIFIFO where the associated packet was written - * @flags the vb2_v4l2_buffer flags + * @flags: the vb2_v4l2_buffer flags */ void amvdec_add_ts(struct amvdec_session *sess, u64 ts, struct v4l2_timecode tc, u32 offset, u32 flags); -- cgit v1.2.3 From d7f26849ed7cc875d0ff7480c2efebeeccea2bad Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Mon, 13 Sep 2021 12:22:54 +0200 Subject: media: atmel: fix the ispck initialization The runtime enabling of the ISPCK (internally clocks the pipeline inside the ISC) has to be done after the pm_runtime for the ISC dev has been started. After the commit by Mauro: the ISC failed to probe with the error: atmel-sama5d2-isc f0008000.isc: failed to enable ispck: -13 atmel-sama5d2-isc: probe of f0008000.isc failed with error -13 This is because the enabling of the ispck is done too early in the probe, and the PM runtime returns invalid request. Thus, moved this clock enabling after pm_runtime_idle is called. The ISPCK is required only for sama5d2 type of ISC. Thus, add a bool inside the isc struct that is platform dependent. For the sama7g5-isc, the enabling of the ISPCK is wrong and does not make sense. Removed it from the sama7g5 probe. In sama7g5-isc, there is only one clock, the MCK, which also clocks the internal pipeline of the ISC. Adapted the clk_prepare and clk_unprepare to request the runtime PM for both clocks (MCK and ISPCK) in case of sama5d2-isc, and the single clock (MCK) in case of sama7g5-isc. Fixes: dd97908ee350 ("media: atmel: properly get pm_runtime") Signed-off-by: Eugen Hristev Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc-base.c | 25 +++++++-------- drivers/media/platform/atmel/atmel-isc.h | 2 ++ drivers/media/platform/atmel/atmel-sama5d2-isc.c | 39 +++++++++++++----------- drivers/media/platform/atmel/atmel-sama7g5-isc.c | 22 +++---------- 4 files changed, 38 insertions(+), 50 deletions(-) diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c index 3e0a3837d608..660cd0ab6749 100644 --- a/drivers/media/platform/atmel/atmel-isc-base.c +++ b/drivers/media/platform/atmel/atmel-isc-base.c @@ -123,11 +123,9 @@ static int isc_clk_prepare(struct clk_hw *hw) struct isc_clk *isc_clk = to_isc_clk(hw); int ret; - if (isc_clk->id == ISC_ISPCK) { - ret = pm_runtime_resume_and_get(isc_clk->dev); - if (ret < 0) - return ret; - } + ret = pm_runtime_resume_and_get(isc_clk->dev); + if (ret < 0) + return ret; return isc_wait_clk_stable(hw); } @@ -138,8 +136,7 @@ static void isc_clk_unprepare(struct clk_hw *hw) isc_wait_clk_stable(hw); - if (isc_clk->id == ISC_ISPCK) - pm_runtime_put_sync(isc_clk->dev); + pm_runtime_put_sync(isc_clk->dev); } static int isc_clk_enable(struct clk_hw *hw) @@ -186,16 +183,13 @@ static int isc_clk_is_enabled(struct clk_hw *hw) u32 status; int ret; - if (isc_clk->id == ISC_ISPCK) { - ret = pm_runtime_resume_and_get(isc_clk->dev); - if (ret < 0) - return 0; - } + ret = pm_runtime_resume_and_get(isc_clk->dev); + if (ret < 0) + return 0; regmap_read(isc_clk->regmap, ISC_CLKSR, &status); - if (isc_clk->id == ISC_ISPCK) - pm_runtime_put_sync(isc_clk->dev); + pm_runtime_put_sync(isc_clk->dev); return status & ISC_CLK(isc_clk->id) ? 1 : 0; } @@ -325,6 +319,9 @@ static int isc_clk_register(struct isc_device *isc, unsigned int id) const char *parent_names[3]; int num_parents; + if (id == ISC_ISPCK && !isc->ispck_required) + return 0; + num_parents = of_clk_get_parent_count(np); if (num_parents < 1 || num_parents > 3) return -EINVAL; diff --git a/drivers/media/platform/atmel/atmel-isc.h b/drivers/media/platform/atmel/atmel-isc.h index 19cc60dfcbe0..2bfcb135ef13 100644 --- a/drivers/media/platform/atmel/atmel-isc.h +++ b/drivers/media/platform/atmel/atmel-isc.h @@ -178,6 +178,7 @@ struct isc_reg_offsets { * @hclock: Hclock clock input (refer datasheet) * @ispck: iscpck clock (refer datasheet) * @isc_clks: ISC clocks + * @ispck_required: ISC requires ISP Clock initialization * @dcfg: DMA master configuration, architecture dependent * * @dev: Registered device driver @@ -252,6 +253,7 @@ struct isc_device { struct clk *hclock; struct clk *ispck; struct isc_clk isc_clks[2]; + bool ispck_required; u32 dcfg; struct device *dev; diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c index 0fa6013560df..1b2063cce0f7 100644 --- a/drivers/media/platform/atmel/atmel-sama5d2-isc.c +++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c @@ -454,6 +454,9 @@ static int atmel_isc_probe(struct platform_device *pdev) /* sama5d2-isc - 8 bits per beat */ isc->dcfg = ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8; + /* sama5d2-isc : ISPCK is required and mandatory */ + isc->ispck_required = true; + ret = isc_pipeline_init(isc); if (ret) return ret; @@ -476,22 +479,6 @@ static int atmel_isc_probe(struct platform_device *pdev) dev_err(dev, "failed to init isc clock: %d\n", ret); goto unprepare_hclk; } - - isc->ispck = isc->isc_clks[ISC_ISPCK].clk; - - ret = clk_prepare_enable(isc->ispck); - if (ret) { - dev_err(dev, "failed to enable ispck: %d\n", ret); - goto unprepare_hclk; - } - - /* ispck should be greater or equal to hclock */ - ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock)); - if (ret) { - dev_err(dev, "failed to set ispck rate: %d\n", ret); - goto unprepare_clk; - } - ret = v4l2_device_register(dev, &isc->v4l2_dev); if (ret) { dev_err(dev, "unable to register v4l2 device.\n"); @@ -546,19 +533,35 @@ static int atmel_isc_probe(struct platform_device *pdev) pm_runtime_enable(dev); pm_request_idle(dev); + isc->ispck = isc->isc_clks[ISC_ISPCK].clk; + + ret = clk_prepare_enable(isc->ispck); + if (ret) { + dev_err(dev, "failed to enable ispck: %d\n", ret); + goto cleanup_subdev; + } + + /* ispck should be greater or equal to hclock */ + ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock)); + if (ret) { + dev_err(dev, "failed to set ispck rate: %d\n", ret); + goto unprepare_clk; + } + regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver); dev_info(dev, "Microchip ISC version %x\n", ver); return 0; +unprepare_clk: + clk_disable_unprepare(isc->ispck); + cleanup_subdev: isc_subdev_cleanup(isc); unregister_v4l2_device: v4l2_device_unregister(&isc->v4l2_dev); -unprepare_clk: - clk_disable_unprepare(isc->ispck); unprepare_hclk: clk_disable_unprepare(isc->hclock); diff --git a/drivers/media/platform/atmel/atmel-sama7g5-isc.c b/drivers/media/platform/atmel/atmel-sama7g5-isc.c index ee68cf1f4243..5d1c76f680f3 100644 --- a/drivers/media/platform/atmel/atmel-sama7g5-isc.c +++ b/drivers/media/platform/atmel/atmel-sama7g5-isc.c @@ -447,6 +447,9 @@ static int microchip_xisc_probe(struct platform_device *pdev) /* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */ isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32; + /* sama7g5-isc : ISPCK does not exist, ISC is clocked by MCK */ + isc->ispck_required = false; + ret = isc_pipeline_init(isc); if (ret) return ret; @@ -470,25 +473,10 @@ static int microchip_xisc_probe(struct platform_device *pdev) goto unprepare_hclk; } - isc->ispck = isc->isc_clks[ISC_ISPCK].clk; - - ret = clk_prepare_enable(isc->ispck); - if (ret) { - dev_err(dev, "failed to enable ispck: %d\n", ret); - goto unprepare_hclk; - } - - /* ispck should be greater or equal to hclock */ - ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock)); - if (ret) { - dev_err(dev, "failed to set ispck rate: %d\n", ret); - goto unprepare_clk; - } - ret = v4l2_device_register(dev, &isc->v4l2_dev); if (ret) { dev_err(dev, "unable to register v4l2 device.\n"); - goto unprepare_clk; + goto unprepare_hclk; } ret = xisc_parse_dt(dev, isc); @@ -550,8 +538,6 @@ cleanup_subdev: unregister_v4l2_device: v4l2_device_unregister(&isc->v4l2_dev); -unprepare_clk: - clk_disable_unprepare(isc->ispck); unprepare_hclk: clk_disable_unprepare(isc->hclock); -- cgit v1.2.3 From c73ba202a851c0b611ef2c25e568fadeff5e667f Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 15 Sep 2021 18:14:07 +0200 Subject: media: ir-kbd-i2c: improve responsiveness of hauppauge zilog receivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The IR receiver has two issues: - Sometimes there is no response to a button press - Sometimes a button press is repeated when it should not have been Hanging the polling interval fixes this behaviour. Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=994050 Cc: stable@vger.kernel.org Suggested-by: Joaquín Alberto Calderón Pozo Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ir-kbd-i2c.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 92376592455e..56674173524f 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -791,6 +791,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) rc_proto = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_RC6_6A_32; ir_codes = RC_MAP_HAUPPAUGE; + ir->polling_interval = 125; probe_tx = true; break; } -- cgit v1.2.3 From 5173cca012b018e2acf5da3f928807618e367dae Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 2 Sep 2021 11:50:23 +0200 Subject: media: ir_toy: print firmware version in correct format A value of 25 means firmware version 2.5. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir_toy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c index b0dc19d36ac9..45d39b6e49c0 100644 --- a/drivers/media/rc/ir_toy.c +++ b/drivers/media/rc/ir_toy.c @@ -440,8 +440,9 @@ static int irtoy_probe(struct usb_interface *intf, if (err) goto free_rcdev; - dev_info(irtoy->dev, "version: hardware %u, firmware %u, protocol %u", - irtoy->hw_version, irtoy->sw_version, irtoy->proto_version); + dev_info(irtoy->dev, "version: hardware %u, firmware %u.%u, protocol %u", + irtoy->hw_version, irtoy->sw_version / 10, + irtoy->sw_version % 10, irtoy->proto_version); if (irtoy->sw_version < MIN_FW_VERSION) { dev_err(irtoy->dev, "need firmware V%02u or higher", -- cgit v1.2.3 From 1d37c85425122cdb56f6448286cc41419a34d621 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 8 Sep 2021 15:05:52 +0200 Subject: media: ir_toy: deal with residual irdata before expected response After sending the start transmit command, the device is supposed to respond with the length of the buffer which can be sent. There might be some residual ir data there. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir_toy.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c index 45d39b6e49c0..2b7c8bba4d6a 100644 --- a/drivers/media/rc/ir_toy.c +++ b/drivers/media/rc/ir_toy.c @@ -122,6 +122,7 @@ static void irtoy_response(struct irtoy *irtoy, u32 len) len, irtoy->in); } break; + case STATE_COMMAND_NO_RESP: case STATE_IRDATA: { struct ir_raw_event rawir = { .pulse = irtoy->pulse }; __be16 *in = (__be16 *)irtoy->in; @@ -167,10 +168,8 @@ static void irtoy_response(struct irtoy *irtoy, u32 len) int err; if (len != 1 || space > MAX_PACKET || space == 0) { - dev_err(irtoy->dev, "packet length expected: %*phN\n", + dev_dbg(irtoy->dev, "packet length expected: %*phN\n", len, irtoy->in); - irtoy->state = STATE_IRDATA; - complete(&irtoy->command_done); break; } @@ -194,9 +193,6 @@ static void irtoy_response(struct irtoy *irtoy, u32 len) irtoy->tx_len -= buf_len; } break; - case STATE_COMMAND_NO_RESP: - dev_err(irtoy->dev, "unexpected response to reset: %*phN\n", - len, irtoy->in); } } -- cgit v1.2.3 From 92f461517d22d85adb8c24970ee61357b97af0aa Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 8 Sep 2021 11:22:40 +0200 Subject: media: ir_toy: do not resubmit broken urb This causes the same urb to resubmitted continuously, hogging up a cpu. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir_toy.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c index 2b7c8bba4d6a..d2d9346eb8f5 100644 --- a/drivers/media/rc/ir_toy.c +++ b/drivers/media/rc/ir_toy.c @@ -213,10 +213,20 @@ static void irtoy_in_callback(struct urb *urb) struct irtoy *irtoy = urb->context; int ret; - if (urb->status == 0) + switch (urb->status) { + case 0: irtoy_response(irtoy, urb->actual_length); - else + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + case -EPROTO: + case -EPIPE: + usb_unlink_urb(urb); + return; + default: dev_dbg(irtoy->dev, "in urb status: %d\n", urb->status); + } ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret && ret != -ENODEV) -- cgit v1.2.3 From dccdd92b7b08ddbb7a8dbc1d6daba1f4fbd6bba2 Mon Sep 17 00:00:00 2001 From: jing yangyang Date: Sat, 21 Aug 2021 05:50:33 +0200 Subject: media: meson-ir-tx: fix platform_no_drv_owner.cocci warnings ./drivers/media/rc/meson-ir-tx.c:398:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Reported-by: Zeal Robot Signed-off-by: jing yangyang Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/meson-ir-tx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/rc/meson-ir-tx.c b/drivers/media/rc/meson-ir-tx.c index 3055f8e1b6ff..c22cd26a5c07 100644 --- a/drivers/media/rc/meson-ir-tx.c +++ b/drivers/media/rc/meson-ir-tx.c @@ -395,7 +395,6 @@ static struct platform_driver meson_irtx_pd = { .remove = meson_irtx_remove, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = meson_irtx_dt_match, }, }; -- cgit v1.2.3 From 44870a9e7a3c24acbb3f888b2a7cc22c9bdf7e7f Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Thu, 19 Aug 2021 12:42:21 +0200 Subject: media: mxl111sf: change mutex_init() location Syzbot reported, that mxl111sf_ctrl_msg() uses uninitialized mutex. The problem was in wrong mutex_init() location. Previous mutex_init(&state->msg_lock) call was in ->init() function, but dvb_usbv2_init() has this order of calls: dvb_usbv2_init() dvb_usbv2_adapter_init() dvb_usbv2_adapter_frontend_init() props->frontend_attach() props->init() Since mxl111sf_* devices call mxl111sf_ctrl_msg() in ->frontend_attach() internally we need to initialize state->msg_lock before frontend_attach(). To achieve it, ->probe() call added to all mxl111sf_* devices, which will simply initiaize mutex. Reported-and-tested-by: syzbot+5ca0bf339f13c4243001@syzkaller.appspotmail.com Fixes: 8572211842af ("[media] mxl111sf: convert to new DVB USB") Signed-off-by: Pavel Skripkin Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/mxl111sf.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index 7865fa0a8295..cd5861a30b6f 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -931,8 +931,6 @@ static int mxl111sf_init(struct dvb_usb_device *d) .len = sizeof(eeprom), .buf = eeprom }, }; - mutex_init(&state->msg_lock); - ret = get_chip_info(state); if (mxl_fail(ret)) pr_err("failed to get chip info during probe"); @@ -1074,6 +1072,14 @@ static int mxl111sf_get_stream_config_dvbt(struct dvb_frontend *fe, return 0; } +static int mxl111sf_probe(struct dvb_usb_device *dev) +{ + struct mxl111sf_state *state = d_to_priv(dev); + + mutex_init(&state->msg_lock); + return 0; +} + static struct dvb_usb_device_properties mxl111sf_props_dvbt = { .driver_name = KBUILD_MODNAME, .owner = THIS_MODULE, @@ -1083,6 +1089,7 @@ static struct dvb_usb_device_properties mxl111sf_props_dvbt = { .generic_bulk_ctrl_endpoint = 0x02, .generic_bulk_ctrl_endpoint_response = 0x81, + .probe = mxl111sf_probe, .i2c_algo = &mxl111sf_i2c_algo, .frontend_attach = mxl111sf_frontend_attach_dvbt, .tuner_attach = mxl111sf_attach_tuner, @@ -1124,6 +1131,7 @@ static struct dvb_usb_device_properties mxl111sf_props_atsc = { .generic_bulk_ctrl_endpoint = 0x02, .generic_bulk_ctrl_endpoint_response = 0x81, + .probe = mxl111sf_probe, .i2c_algo = &mxl111sf_i2c_algo, .frontend_attach = mxl111sf_frontend_attach_atsc, .tuner_attach = mxl111sf_attach_tuner, @@ -1165,6 +1173,7 @@ static struct dvb_usb_device_properties mxl111sf_props_mh = { .generic_bulk_ctrl_endpoint = 0x02, .generic_bulk_ctrl_endpoint_response = 0x81, + .probe = mxl111sf_probe, .i2c_algo = &mxl111sf_i2c_algo, .frontend_attach = mxl111sf_frontend_attach_mh, .tuner_attach = mxl111sf_attach_tuner, @@ -1233,6 +1242,7 @@ static struct dvb_usb_device_properties mxl111sf_props_atsc_mh = { .generic_bulk_ctrl_endpoint = 0x02, .generic_bulk_ctrl_endpoint_response = 0x81, + .probe = mxl111sf_probe, .i2c_algo = &mxl111sf_i2c_algo, .frontend_attach = mxl111sf_frontend_attach_atsc_mh, .tuner_attach = mxl111sf_attach_tuner, @@ -1311,6 +1321,7 @@ static struct dvb_usb_device_properties mxl111sf_props_mercury = { .generic_bulk_ctrl_endpoint = 0x02, .generic_bulk_ctrl_endpoint_response = 0x81, + .probe = mxl111sf_probe, .i2c_algo = &mxl111sf_i2c_algo, .frontend_attach = mxl111sf_frontend_attach_mercury, .tuner_attach = mxl111sf_attach_tuner, @@ -1381,6 +1392,7 @@ static struct dvb_usb_device_properties mxl111sf_props_mercury_mh = { .generic_bulk_ctrl_endpoint = 0x02, .generic_bulk_ctrl_endpoint_response = 0x81, + .probe = mxl111sf_probe, .i2c_algo = &mxl111sf_i2c_algo, .frontend_attach = mxl111sf_frontend_attach_mercury_mh, .tuner_attach = mxl111sf_attach_tuner, -- cgit v1.2.3 From 476db72e521983ecb847e4013b263072bb1110fc Mon Sep 17 00:00:00 2001 From: Rajat Asthana Date: Wed, 18 Aug 2021 22:31:10 +0200 Subject: media: mceusb: return without resubmitting URB in case of -EPROTO error. Syzkaller reported a warning called "rcu detected stall in dummy_timer". The error seems to be an error in mceusb_dev_recv(). In the case of -EPROTO error, the routine immediately resubmits the URB. Instead it should return without resubmitting URB. Reported-by: syzbot+4d3749e9612c2cfab956@syzkaller.appspotmail.com Signed-off-by: Rajat Asthana Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 28bf78ff246a..d09bee82c04c 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1386,6 +1386,7 @@ static void mceusb_dev_recv(struct urb *urb) case -ECONNRESET: case -ENOENT: case -EILSEQ: + case -EPROTO: case -ESHUTDOWN: usb_unlink_urb(urb); return; -- cgit v1.2.3 From 19c23f4fd860615714b776f32d890cdd93c0e8a3 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Mon, 23 Aug 2021 14:13:50 +0200 Subject: media: dvb-frontend/mxl692: Remove repeated verbose license text remove it because SPDX-License-Identifier is already used Signed-off-by: Cai Huoqing Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mxl692.c | 9 --------- drivers/media/dvb-frontends/mxl692.h | 9 --------- drivers/media/dvb-frontends/mxl692_defs.h | 9 --------- 3 files changed, 27 deletions(-) diff --git a/drivers/media/dvb-frontends/mxl692.c b/drivers/media/dvb-frontends/mxl692.c index a246db683cdf..dd7954e8f553 100644 --- a/drivers/media/dvb-frontends/mxl692.c +++ b/drivers/media/dvb-frontends/mxl692.c @@ -7,15 +7,6 @@ * based on code: * Copyright (c) 2016 MaxLinear, Inc. All rights reserved * which was released under GPL V2 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/media/dvb-frontends/mxl692.h b/drivers/media/dvb-frontends/mxl692.h index 45bc48f1f12f..77764a047c07 100644 --- a/drivers/media/dvb-frontends/mxl692.h +++ b/drivers/media/dvb-frontends/mxl692.h @@ -7,15 +7,6 @@ * based on code: * Copyright (c) 2016 MaxLinear, Inc. All rights reserved * which was released under GPL V2 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _MXL692_H_ diff --git a/drivers/media/dvb-frontends/mxl692_defs.h b/drivers/media/dvb-frontends/mxl692_defs.h index 776ac407b4e7..c603f3d6f27f 100644 --- a/drivers/media/dvb-frontends/mxl692_defs.h +++ b/drivers/media/dvb-frontends/mxl692_defs.h @@ -7,15 +7,6 @@ * based on code: * Copyright (c) 2016 MaxLinear, Inc. All rights reserved * which was released under GPL V2 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ /***************************************************************************** -- cgit v1.2.3 From 5f1644bd81221e307105eb596e5212453b8d4283 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Mon, 23 Aug 2021 14:12:43 +0200 Subject: media: dvb-frontend/mxl5xx: Remove repeated verbose license text remove it because SPDX-License-Identifier is already used Signed-off-by: Cai Huoqing Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mxl5xx.c | 9 --------- drivers/media/dvb-frontends/mxl5xx.h | 9 --------- drivers/media/dvb-frontends/mxl5xx_defs.h | 4 ---- drivers/media/dvb-frontends/mxl5xx_regs.h | 10 ---------- 4 files changed, 32 deletions(-) diff --git a/drivers/media/dvb-frontends/mxl5xx.c b/drivers/media/dvb-frontends/mxl5xx.c index 0b00a23436ed..934d1c0b214a 100644 --- a/drivers/media/dvb-frontends/mxl5xx.c +++ b/drivers/media/dvb-frontends/mxl5xx.c @@ -9,15 +9,6 @@ * based on code: * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved * which was released under GPL V2 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/media/dvb-frontends/mxl5xx.h b/drivers/media/dvb-frontends/mxl5xx.h index 706a2f5d8f97..139e16b2ecfc 100644 --- a/drivers/media/dvb-frontends/mxl5xx.h +++ b/drivers/media/dvb-frontends/mxl5xx.h @@ -9,15 +9,6 @@ * based on code: * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved * which was released under GPL V2 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _MXL5XX_H_ diff --git a/drivers/media/dvb-frontends/mxl5xx_defs.h b/drivers/media/dvb-frontends/mxl5xx_defs.h index 1442af8dc176..097271f73740 100644 --- a/drivers/media/dvb-frontends/mxl5xx_defs.h +++ b/drivers/media/dvb-frontends/mxl5xx_defs.h @@ -7,10 +7,6 @@ * based on code: * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved * which was released under GPL V2 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2, as published by the Free Software Foundation. */ enum MXL_BOOL_E { diff --git a/drivers/media/dvb-frontends/mxl5xx_regs.h b/drivers/media/dvb-frontends/mxl5xx_regs.h index 86d5317eba7a..b38a13847033 100644 --- a/drivers/media/dvb-frontends/mxl5xx_regs.h +++ b/drivers/media/dvb-frontends/mxl5xx_regs.h @@ -2,16 +2,6 @@ /* * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved * - * License type: GPLv2 - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * * This program may alternatively be licensed under a proprietary license from * MaxLinear, Inc. * -- cgit v1.2.3 From c251d8b3b79527de34949dd76fe5472c680e8192 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Mon, 23 Aug 2021 14:07:41 +0200 Subject: media: dvb-frontends/stv6111: Remove repeated verbose license text remove it because SPDX-License-Identifier is already used Signed-off-by: Cai Huoqing Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv6111.c | 9 --------- drivers/media/dvb-frontends/stv6111.h | 9 --------- 2 files changed, 18 deletions(-) diff --git a/drivers/media/dvb-frontends/stv6111.c b/drivers/media/dvb-frontends/stv6111.c index d5035dac4574..2d0adb6fcb08 100644 --- a/drivers/media/dvb-frontends/stv6111.c +++ b/drivers/media/dvb-frontends/stv6111.c @@ -3,15 +3,6 @@ * Driver for the ST STV6111 tuner * * Copyright (C) 2014 Digital Devices GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/media/dvb-frontends/stv6111.h b/drivers/media/dvb-frontends/stv6111.h index 49e821ac9954..f172c3e3d886 100644 --- a/drivers/media/dvb-frontends/stv6111.h +++ b/drivers/media/dvb-frontends/stv6111.h @@ -3,15 +3,6 @@ * Driver for the ST STV6111 tuner * * Copyright (C) 2014 Digital Devices GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _STV6111_H_ -- cgit v1.2.3 From be7468c77b0d00b9619bbc4bbea1f98931b9785e Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Mon, 23 Aug 2021 14:06:43 +0200 Subject: media: dvb-frontends/stv0910: Remove repeated verbose license text remove it because SPDX-License-Identifier is already used Signed-off-by: Cai Huoqing Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv0910.c | 9 --------- drivers/media/dvb-frontends/stv0910.h | 9 --------- 2 files changed, 18 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c index 68d7c7b41071..e517ff757744 100644 --- a/drivers/media/dvb-frontends/stv0910.c +++ b/drivers/media/dvb-frontends/stv0910.c @@ -5,15 +5,6 @@ * Copyright (C) 2014-2015 Ralph Metzler * Marcus Metzler * developed for Digital Devices GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/media/dvb-frontends/stv0910.h b/drivers/media/dvb-frontends/stv0910.h index 24ecc6902235..0b6f02ad7910 100644 --- a/drivers/media/dvb-frontends/stv0910.h +++ b/drivers/media/dvb-frontends/stv0910.h @@ -5,15 +5,6 @@ * Copyright (C) 2014-2015 Ralph Metzler * Marcus Metzler * developed for Digital Devices GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _STV0910_H_ -- cgit v1.2.3 From 2990cd10e1ddba92b72872a6646df1a37096c025 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Mon, 23 Aug 2021 14:05:40 +0200 Subject: media: dvb-frontends/cxd2099: Remove repeated verbose license text remove it because SPDX-License-Identifier is already used Signed-off-by: Cai Huoqing Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2099.c | 9 --------- drivers/media/dvb-frontends/cxd2099.h | 9 --------- 2 files changed, 18 deletions(-) diff --git a/drivers/media/dvb-frontends/cxd2099.c b/drivers/media/dvb-frontends/cxd2099.c index f88b5355493e..1c8207ab8988 100644 --- a/drivers/media/dvb-frontends/cxd2099.c +++ b/drivers/media/dvb-frontends/cxd2099.c @@ -3,15 +3,6 @@ * cxd2099.c: Driver for the Sony CXD2099AR Common Interface Controller * * Copyright (C) 2010-2013 Digital Devices GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/media/dvb-frontends/cxd2099.h b/drivers/media/dvb-frontends/cxd2099.h index 0c101bdef01d..5d4060007c46 100644 --- a/drivers/media/dvb-frontends/cxd2099.h +++ b/drivers/media/dvb-frontends/cxd2099.h @@ -3,15 +3,6 @@ * cxd2099.h: Driver for the Sony CXD2099AR Common Interface Controller * * Copyright (C) 2010-2011 Digital Devices GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _CXD2099_H_ -- cgit v1.2.3 From 689e453a9b9c9158522b508876a1ff02ab0c3aa8 Mon Sep 17 00:00:00 2001 From: "F.A.Sulaiman" Date: Tue, 24 Aug 2021 20:37:30 +0530 Subject: HID: betop: fix slab-out-of-bounds Write in betop_probe Syzbot reported slab-out-of-bounds Write bug in hid-betopff driver. The problem is the driver assumes the device must have an input report but some malicious devices violate this assumption. So this patch checks hid_device's input is non empty before it's been used. Reported-by: syzbot+07efed3bc5a1407bd742@syzkaller.appspotmail.com Signed-off-by: F.A. SULAIMAN Reviewed-by: Pavel Skripkin Signed-off-by: Jiri Kosina --- drivers/hid/hid-betopff.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-betopff.c b/drivers/hid/hid-betopff.c index 0790fbd3fc9a..467d789f9bc2 100644 --- a/drivers/hid/hid-betopff.c +++ b/drivers/hid/hid-betopff.c @@ -56,15 +56,22 @@ static int betopff_init(struct hid_device *hid) { struct betopff_device *betopff; struct hid_report *report; - struct hid_input *hidinput = - list_first_entry(&hid->inputs, struct hid_input, list); + struct hid_input *hidinput; struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct input_dev *dev = hidinput->input; + struct input_dev *dev; int field_count = 0; int error; int i, j; + if (list_empty(&hid->inputs)) { + hid_err(hid, "no inputs found\n"); + return -ENODEV; + } + + hidinput = list_first_entry(&hid->inputs, struct hid_input, list); + dev = hidinput->input; + if (list_empty(report_list)) { hid_err(hid, "no output reports found\n"); return -ENODEV; -- cgit v1.2.3 From 125aaf6ec2fab57ed4be47929386101a8ab06d4c Mon Sep 17 00:00:00 2001 From: Mizuho Mori Date: Thu, 29 Jul 2021 20:03:25 +0900 Subject: HID: apple: Fix logical maximum and usage maximum of Magic Keyboard JIS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apple Magic Keyboard(JIS)'s Logical Maximum and Usage Maximum are wrong. Below is a report descriptor. 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x06, /* Usage (Keyboard), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x01, /* Report ID (1), */ 0x05, 0x07, /* Usage Page (Keyboard), */ 0x15, 0x00, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */ 0x29, 0xE7, /* Usage Maximum (KB Right GUI), */ 0x75, 0x01, /* Report Size (1), */ 0x95, 0x08, /* Report Count (8), */ 0x81, 0x02, /* Input (Variable), */ 0x95, 0x05, /* Report Count (5), */ 0x75, 0x01, /* Report Size (1), */ 0x05, 0x08, /* Usage Page (LED), */ 0x19, 0x01, /* Usage Minimum (01h), */ 0x29, 0x05, /* Usage Maximum (05h), */ 0x91, 0x02, /* Output (Variable), */ 0x95, 0x01, /* Report Count (1), */ 0x75, 0x03, /* Report Size (3), */ 0x91, 0x03, /* Output (Constant, Variable), */ 0x95, 0x08, /* Report Count (8), */ 0x75, 0x01, /* Report Size (1), */ 0x15, 0x00, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ here is a report descriptor which is parsed one in kernel. see sys/kernel/debug/hid//rdesc 05 01 09 06 a1 01 85 01 05 07 15 00 25 01 19 e0 29 e7 75 01 95 08 81 02 95 05 75 01 05 08 19 01 29 05 91 02 95 01 75 03 91 03 95 08 75 01 15 00 25 01 06 00 ff 09 03 81 03 95 06 75 08 15 00 25 [65] 05 07 19 00 29 [65] 81 00 95 01 75 01 15 00 25 01 05 0c 09 b8 81 02 95 01 75 01 06 01 ff 09 03 81 02 95 01 75 06 81 03 06 02 ff 09 55 85 55 15 00 26 ff 00 75 08 95 40 b1 a2 c0 06 00 ff 09 14 a1 01 85 90 05 84 75 01 95 03 15 00 25 01 09 61 05 85 09 44 09 46 81 02 95 05 81 01 75 08 95 01 15 00 26 ff 00 09 65 81 02 c0 00 Position 64(Logical Maximum) and 70(Usage Maximum) are 101. Both should be 0xE7 to support JIS specific keys(ろ, Eisu, Kana, |) support. position 117 is also 101 but not related(it is Usage 65h). There are no difference of product id between JIS and ANSI. They are same 0x0267. Signed-off-by: Mizuho Mori Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 833fcf07ff35..6ccfa0cb997a 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -336,12 +336,19 @@ static int apple_event(struct hid_device *hdev, struct hid_field *field, /* * MacBook JIS keyboard has wrong logical maximum + * Magic Keyboard JIS has wrong logical maximum */ static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { struct apple_sc *asc = hid_get_drvdata(hdev); + if(*rsize >=71 && rdesc[70] == 0x65 && rdesc[64] == 0x65) { + hid_info(hdev, + "fixing up Magic Keyboard JIS report descriptor\n"); + rdesc[64] = rdesc[70] = 0xe7; + } + if ((asc->quirks & APPLE_RDESC_JIS) && *rsize >= 60 && rdesc[53] == 0x65 && rdesc[59] == 0x65) { hid_info(hdev, -- cgit v1.2.3 From 94f9c3567eba2a2adcaafa936fc86854546580a4 Mon Sep 17 00:00:00 2001 From: Joshua-Dickens Date: Tue, 14 Sep 2021 13:28:25 -0400 Subject: HID: wacom: Add new Intuos BT (CTL-4100WL/CTL-6100WL) device IDs Add the new PIDs to wacom_wac.c to support the new models in the Intuos series. [jkosina@suse.cz: fix changelog] Signed-off-by: Joshua Dickens Reviewed-by: Ping Cheng Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index fd51769d0994..33a6908995b1 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -4746,6 +4746,12 @@ static const struct wacom_features wacom_features_0x393 = { "Wacom Intuos Pro S", 31920, 19950, 8191, 63, INTUOSP2S_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 10 }; +static const struct wacom_features wacom_features_0x3c6 = + { "Wacom Intuos BT S", 15200, 9500, 4095, 63, + INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; +static const struct wacom_features wacom_features_0x3c8 = + { "Wacom Intuos BT M", 21600, 13500, 4095, 63, + INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; static const struct wacom_features wacom_features_HID_ANY_ID = { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID }; @@ -4919,6 +4925,8 @@ const struct hid_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x37A) }, { USB_DEVICE_WACOM(0x37B) }, { BT_DEVICE_WACOM(0x393) }, + { BT_DEVICE_WACOM(0x3c6) }, + { BT_DEVICE_WACOM(0x3c8) }, { USB_DEVICE_WACOM(0x4001) }, { USB_DEVICE_WACOM(0x4004) }, { USB_DEVICE_WACOM(0x5000) }, -- cgit v1.2.3 From ef11357046512918ab876aa0f837b0a6de65a3c6 Mon Sep 17 00:00:00 2001 From: Evgeny Novikov Date: Tue, 1 Jun 2021 19:38:01 +0300 Subject: HID: amd_sfh: Fix potential NULL pointer dereference devm_add_action_or_reset() can suddenly invoke amd_mp2_pci_remove() at registration that will cause NULL pointer dereference since corresponding data is not initialized yet. The patch moves initialization of data before devm_add_action_or_reset(). Found by Linux Driver Verification project (linuxtesting.org). [jkosina@suse.cz: rebase] Signed-off-by: Evgeny Novikov Acked-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index 79b138fd4261..9a1824757aae 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -251,6 +251,10 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i return rc; } + rc = amd_sfh_hid_client_init(privdata); + if (rc) + return rc; + privdata->cl_data = devm_kzalloc(&pdev->dev, sizeof(struct amdtp_cl_data), GFP_KERNEL); if (!privdata->cl_data) return -ENOMEM; @@ -261,7 +265,7 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i mp2_select_ops(privdata); - return amd_sfh_hid_client_init(privdata); + return 0; } static int __maybe_unused amd_mp2_pci_resume(struct device *dev) -- cgit v1.2.3 From 38245d0340ea732057f69b957de609cec56cd061 Mon Sep 17 00:00:00 2001 From: Andrej Shadura Date: Thu, 16 Sep 2021 17:33:11 +0100 Subject: HID: u2fzero: ignore incomplete packets without data Since the actual_length calculation is performed unsigned, packets shorter than 7 bytes (e.g. packets without data or otherwise truncated) or non-received packets ("zero" bytes) can cause buffer overflow. Link: https://bugzilla.kernel.org/show_bug.cgi?id=214437 Fixes: 42337b9d4d958("HID: add driver for U2F Zero built-in LED and RNG") Signed-off-by: Andrej Shadura Signed-off-by: Jiri Kosina --- drivers/hid/hid-u2fzero.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-u2fzero.c b/drivers/hid/hid-u2fzero.c index 95e0807878c7..d70cd3d7f583 100644 --- a/drivers/hid/hid-u2fzero.c +++ b/drivers/hid/hid-u2fzero.c @@ -198,7 +198,9 @@ static int u2fzero_rng_read(struct hwrng *rng, void *data, } ret = u2fzero_recv(dev, &req, &resp); - if (ret < 0) + + /* ignore errors or packets without data */ + if (ret < offsetof(struct u2f_hid_msg, init.data)) return 0; /* only take the minimum amount of data it is safe to take */ -- cgit v1.2.3 From 601e6baaa21c40292a0135963eda7d9b0afb9674 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Thu, 23 Sep 2021 17:59:27 +0530 Subject: HID: amd_sfh: Fix potential NULL pointer dereference The cl_data field of a privdata must be allocated and updated before using in amd_sfh_hid_client_init() function. Hence handling NULL pointer cl_data accordingly. Fixes: d46ef750ed58 ("HID: amd_sfh: Fix potential NULL pointer dereference") Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index 9a1824757aae..05c007b213f2 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -251,21 +251,17 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i return rc; } - rc = amd_sfh_hid_client_init(privdata); - if (rc) - return rc; - privdata->cl_data = devm_kzalloc(&pdev->dev, sizeof(struct amdtp_cl_data), GFP_KERNEL); if (!privdata->cl_data) return -ENOMEM; - rc = devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata); + mp2_select_ops(privdata); + + rc = amd_sfh_hid_client_init(privdata); if (rc) return rc; - mp2_select_ops(privdata); - - return 0; + return devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata); } static int __maybe_unused amd_mp2_pci_resume(struct device *dev) -- cgit v1.2.3 From 135291f36d22962f0966dc9c20a45d9ff312c355 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 27 Sep 2021 11:26:21 -0700 Subject: vboxfs: fix broken legacy mount signature checking Commit 9d682ea6bcc7 ("vboxsf: Fix the check for the old binary mount-arguments struct") was meant to fix a build error due to sign mismatch in 'char' and the use of character constants, but it just moved the error elsewhere, in that on some architectures characters and signed and on others they are unsigned, and that's just how the C standard works. The proper fix is a simple "don't do that then". The code was just being silly and odd, and it should never have cared about signed vs unsigned characters in the first place, since what it is testing is not four "characters", but four bytes. And the way to compare four bytes is by using "memcmp()". Which compilers will know to just turn into a single 32-bit compare with a constant, as long as you don't have crazy debug options enabled. Link: https://lore.kernel.org/lkml/20210927094123.576521-1-arnd@kernel.org/ Cc: Arnd Bergmann Cc: Hans de Goede Signed-off-by: Linus Torvalds --- fs/vboxsf/super.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c index 4f5e59f06284..37dd3fe5b1e9 100644 --- a/fs/vboxsf/super.c +++ b/fs/vboxsf/super.c @@ -21,10 +21,7 @@ #define VBOXSF_SUPER_MAGIC 0x786f4256 /* 'VBox' little endian */ -#define VBSF_MOUNT_SIGNATURE_BYTE_0 ('\000') -#define VBSF_MOUNT_SIGNATURE_BYTE_1 ('\377') -#define VBSF_MOUNT_SIGNATURE_BYTE_2 ('\376') -#define VBSF_MOUNT_SIGNATURE_BYTE_3 ('\375') +static const unsigned char VBSF_MOUNT_SIGNATURE[4] = "\000\377\376\375"; static int follow_symlinks; module_param(follow_symlinks, int, 0444); @@ -386,12 +383,7 @@ fail_nomem: static int vboxsf_parse_monolithic(struct fs_context *fc, void *data) { - unsigned char *options = data; - - if (options && options[0] == VBSF_MOUNT_SIGNATURE_BYTE_0 && - options[1] == VBSF_MOUNT_SIGNATURE_BYTE_1 && - options[2] == VBSF_MOUNT_SIGNATURE_BYTE_2 && - options[3] == VBSF_MOUNT_SIGNATURE_BYTE_3) { + if (data && !memcmp(data, VBSF_MOUNT_SIGNATURE, 4)) { vbg_err("vboxsf: Old binary mount data not supported, remove obsolete mount.vboxsf and/or update your VBoxService.\n"); return -EINVAL; } -- cgit v1.2.3 From a466530b3a1ef20de12b2e2c062a1a84006ced36 Mon Sep 17 00:00:00 2001 From: Jackie Liu Date: Mon, 13 Sep 2021 15:32:20 +0800 Subject: watchdog/sb_watchdog: fix compilation problem due to COMPILE_TEST Compiling sb_watchdog needs to clearly define SIBYTE_HDR_FEATURES. In arch/mips/sibyte/Platform like: cflags-$(CONFIG_SIBYTE_BCM112X) += \ -I$(srctree)/arch/mips/include/asm/mach-sibyte \ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL Otherwise, SIBYTE_HDR_FEATURES is SIBYTE_HDR_FMASK_ALL. SIBYTE_HDR_FMASK_ALL is mean: #define SIBYTE_HDR_FMASK_ALL SIBYTE_HDR_FMASK_1250_ALL | SIBYTE_HDR_FMASK_112x_ALL \ | SIBYTE_HDR_FMASK_1480_ALL) So, If not limited to CPU_SB1, we will get such an error: arch/mips/include/asm/sibyte/bcm1480_scd.h:261: error: "M_SPC_CFG_CLEAR" redefined [-Werror] arch/mips/include/asm/sibyte/bcm1480_scd.h:262: error: "M_SPC_CFG_ENABLE" redefined [-Werror] Fixes: da2a68b3eb47 ("watchdog: Enable COMPILE_TEST where possible") Signed-off-by: Jackie Liu Reviewed-by: Guenter Roeck Signed-off-by: Linus Torvalds --- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index b81fe4f7d434..bf59faeb3de1 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1666,7 +1666,7 @@ config WDT_MTX1 config SIBYTE_WDOG tristate "Sibyte SoC hardware watchdog" - depends on CPU_SB1 || (MIPS && COMPILE_TEST) + depends on CPU_SB1 help Watchdog driver for the built in watchdog hardware in Sibyte SoC processors. There are apparently two watchdog timers -- cgit v1.2.3 From 95a10c4eb307f13c8a58d714e39733831c3288f6 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 5 Aug 2021 21:04:16 +0200 Subject: media: hantro: Fix check for single irq Some cores use only one interrupt and in such case interrupt name in DT is not needed. Driver supposedly accounted that, but due to the wrong field check it never worked. Fix that. Fixes: 18d6c8b7b4c9 ("media: hantro: add fallback handling for single irq/clk") Signed-off-by: Jernej Skrabec Reviewed-by: Ezequiel Garcia Reviewed-by: Emil Velikov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 2d88fbb0445b..f23fc14b3562 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -921,7 +921,7 @@ static int hantro_probe(struct platform_device *pdev) if (!vpu->variant->irqs[i].handler) continue; - if (vpu->variant->num_clocks > 1) { + if (vpu->variant->num_irqs > 1) { irq_name = vpu->variant->irqs[i].name; irq = platform_get_irq_byname(vpu->pdev, irq_name); } else { -- cgit v1.2.3 From 448ea5ee473b9a41ec1235217648bd48096dfcf0 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 19 Aug 2021 16:00:09 +0200 Subject: media: cedrus: Fix SUNXI tile size calculation Tiled formats requires full rows being allocated (even for Chroma planes). When the number of Luma tiles is odd, we need to round up to twice the tile width in order to roundup the number of Chroma tiles. This was notice with a crash running BA1_FT_C compliance test using sunxi tiles using GStreamer. Cedrus driver would allocate 9 rows for Luma, but only 4.5 rows for Chroma, causing userspace to crash. Signed-off-by: Nicolas Dufresne Fixes: 50e761516f2b8 ("media: platform: Add Cedrus VPU decoder driver") Reviewed-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index ee7353086641..66714609b577 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -135,7 +135,7 @@ void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) sizeimage = bytesperline * height; /* Chroma plane size. */ - sizeimage += bytesperline * height / 2; + sizeimage += bytesperline * ALIGN(height, 64) / 2; break; -- cgit v1.2.3 From 218848835699879ed6260ec49bbb22e9e7839017 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 7 Sep 2021 06:40:22 +0200 Subject: media: s5p-jpeg: rename JPEG marker constants to prevent build warnings The use of a macro named 'RST' conflicts with one of the same name in arch/mips/include/asm/mach-rc32434/rb.h. This causes build warnings on some MIPS builds. Change the names of the JPEG marker constants to be in their own namespace to fix these build warnings and to prevent other similar problems in the future. Fixes these build warnings: In file included from ../drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c:14: ../drivers/media/platform/s5p-jpeg/jpeg-core.h:43: warning: "RST" redefined 43 | #define RST 0xd0 | ../arch/mips/include/asm/mach-rc32434/rb.h:13: note: this is the location of the previous definition 13 | #define RST (1 << 15) In file included from ../drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c:13: ../drivers/media/platform/s5p-jpeg/jpeg-core.h:43: warning: "RST" redefined 43 | #define RST 0xd0 ../arch/mips/include/asm/mach-rc32434/rb.h:13: note: this is the location of the previous definition 13 | #define RST (1 << 15) In file included from ../drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c:12: ../drivers/media/platform/s5p-jpeg/jpeg-core.h:43: warning: "RST" redefined 43 | #define RST 0xd0 ../arch/mips/include/asm/mach-rc32434/rb.h:13: note: this is the location of the previous definition 13 | #define RST (1 << 15) In file included from ../drivers/media/platform/s5p-jpeg/jpeg-core.c:31: ../drivers/media/platform/s5p-jpeg/jpeg-core.h:43: warning: "RST" redefined 43 | #define RST 0xd0 ../arch/mips/include/asm/mach-rc32434/rb.h:13: note: this is the location of the previous definition 13 | #define RST (1 << 15) Also update the kernel-doc so that the word "marker" is not repeated. Link: https://lore.kernel.org/linux-media/20210907044022.30602-1-rdunlap@infradead.org Fixes: bb677f3ac434 ("[media] Exynos4 JPEG codec v4l2 driver") Signed-off-by: Randy Dunlap Reported-by: kernel test robot Cc: Andrzej Pietrasiewicz Cc: Jacek Anaszewski Cc: Sylwester Nawrocki Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-core.c | 18 +++++++++--------- drivers/media/platform/s5p-jpeg/jpeg-core.h | 28 ++++++++++++++-------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 1faff037cdf7..ebdfd24e9cd5 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -1140,8 +1140,8 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, continue; length = 0; switch (c) { - /* SOF0: baseline JPEG */ - case SOF0: + /* JPEG_MARKER_SOF0: baseline JPEG */ + case JPEG_MARKER_SOF0: if (get_word_be(&jpeg_buffer, &word)) break; length = (long)word - 2; @@ -1172,7 +1172,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, notfound = 0; break; - case DQT: + case JPEG_MARKER_DQT: if (get_word_be(&jpeg_buffer, &word)) break; length = (long)word - 2; @@ -1185,7 +1185,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, skip(&jpeg_buffer, length); break; - case DHT: + case JPEG_MARKER_DHT: if (get_word_be(&jpeg_buffer, &word)) break; length = (long)word - 2; @@ -1198,15 +1198,15 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, skip(&jpeg_buffer, length); break; - case SOS: + case JPEG_MARKER_SOS: sos = jpeg_buffer.curr - 2; /* 0xffda */ break; /* skip payload-less markers */ - case RST ... RST + 7: - case SOI: - case EOI: - case TEM: + case JPEG_MARKER_RST ... JPEG_MARKER_RST + 7: + case JPEG_MARKER_SOI: + case JPEG_MARKER_EOI: + case JPEG_MARKER_TEM: break; /* skip uninteresting payload markers */ diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h index a77d93c098ce..8473a019bb5f 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h @@ -37,15 +37,15 @@ #define EXYNOS3250_IRQ_TIMEOUT 0x10000000 /* a selection of JPEG markers */ -#define TEM 0x01 -#define SOF0 0xc0 -#define DHT 0xc4 -#define RST 0xd0 -#define SOI 0xd8 -#define EOI 0xd9 -#define SOS 0xda -#define DQT 0xdb -#define DHP 0xde +#define JPEG_MARKER_TEM 0x01 +#define JPEG_MARKER_SOF0 0xc0 +#define JPEG_MARKER_DHT 0xc4 +#define JPEG_MARKER_RST 0xd0 +#define JPEG_MARKER_SOI 0xd8 +#define JPEG_MARKER_EOI 0xd9 +#define JPEG_MARKER_SOS 0xda +#define JPEG_MARKER_DQT 0xdb +#define JPEG_MARKER_DHP 0xde /* Flags that indicate a format can be used for capture/output */ #define SJPEG_FMT_FLAG_ENC_CAPTURE (1 << 0) @@ -187,11 +187,11 @@ struct s5p_jpeg_marker { * @fmt: driver-specific format of this queue * @w: image width * @h: image height - * @sos: SOS marker's position relative to the buffer beginning - * @dht: DHT markers' positions relative to the buffer beginning - * @dqt: DQT markers' positions relative to the buffer beginning - * @sof: SOF0 marker's position relative to the buffer beginning - * @sof_len: SOF0 marker's payload length (without length field itself) + * @sos: JPEG_MARKER_SOS's position relative to the buffer beginning + * @dht: JPEG_MARKER_DHT' positions relative to the buffer beginning + * @dqt: JPEG_MARKER_DQT' positions relative to the buffer beginning + * @sof: JPEG_MARKER_SOF0's position relative to the buffer beginning + * @sof_len: JPEG_MARKER_SOF0's payload length (without length field itself) * @size: image buffer size in bytes */ struct s5p_jpeg_q_data { -- cgit v1.2.3 From 4114978dcd24e72415276bba60ff4ff355970bbc Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 14 Sep 2021 16:57:46 +0200 Subject: media: ir_toy: prevent device from hanging during transmit If the IR Toy is receiving IR while a transmit is done, it may end up hanging. We can prevent this from happening by re-entering sample mode just before issuing the transmit command. Link: https://github.com/bengtmartensson/HarcHardware/discussions/25 Cc: stable@vger.kernel.org [mchehab: renamed: s/STATE_RESET/STATE_COMMAND_NO_RESP/ ] Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir_toy.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c index d2d9346eb8f5..71aced52248f 100644 --- a/drivers/media/rc/ir_toy.c +++ b/drivers/media/rc/ir_toy.c @@ -26,6 +26,7 @@ static const u8 COMMAND_VERSION[] = { 'v' }; // End transmit and repeat reset command so we exit sump mode static const u8 COMMAND_RESET[] = { 0xff, 0xff, 0, 0, 0, 0, 0 }; static const u8 COMMAND_SMODE_ENTER[] = { 's' }; +static const u8 COMMAND_SMODE_EXIT[] = { 0 }; static const u8 COMMAND_TXSTART[] = { 0x26, 0x24, 0x25, 0x03 }; #define REPLY_XMITCOUNT 't' @@ -317,12 +318,30 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count) buf[i] = cpu_to_be16(v); } - buf[count] = cpu_to_be16(0xffff); + buf[count] = 0xffff; irtoy->tx_buf = buf; irtoy->tx_len = size; irtoy->emitted = 0; + // There is an issue where if the unit is receiving IR while the + // first TXSTART command is sent, the device might end up hanging + // with its led on. It does not respond to any command when this + // happens. To work around this, re-enter sample mode. + err = irtoy_command(irtoy, COMMAND_SMODE_EXIT, + sizeof(COMMAND_SMODE_EXIT), STATE_COMMAND_NO_RESP); + if (err) { + dev_err(irtoy->dev, "exit sample mode: %d\n", err); + return err; + } + + err = irtoy_command(irtoy, COMMAND_SMODE_ENTER, + sizeof(COMMAND_SMODE_ENTER), STATE_COMMAND); + if (err) { + dev_err(irtoy->dev, "enter sample mode: %d\n", err); + return err; + } + err = irtoy_command(irtoy, COMMAND_TXSTART, sizeof(COMMAND_TXSTART), STATE_TX); kfree(buf); -- cgit v1.2.3 From fc41665498332ad394b7db37f23e9394096ddc71 Mon Sep 17 00:00:00 2001 From: Nadezda Lutovinova Date: Wed, 11 Aug 2021 19:18:16 +0200 Subject: media: rcar-csi2: Add checking to rcsi2_start_receiver() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If rcsi2_code_to_fmt() return NULL, then null pointer dereference occurs in the next cycle. That should not be possible now but adding checking protects from future bugs. The patch adds checking if format is NULL. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Nadezda Lutovinova Reviewed-by: Jacopo Mondi Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-csi2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index a4952711b7b1..d7f560e312d4 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -651,6 +651,8 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv) /* Code is validated in set_fmt. */ format = rcsi2_code_to_fmt(priv->mf.code); + if (!format) + return -EINVAL; /* * Enable all supported CSI-2 channels with virtual channel and -- cgit v1.2.3 From a240a464eaab701b993df5a1e7f0a0490a2ec930 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 12 Sep 2021 10:20:50 +0200 Subject: media: cedrus: Add H265 10-bit capability flag Currently only H6 variant supports decoding 10-bit H265 videos. Add a capability flag, so driver could determine if 10-bit H265 slices should be allowed or not. Signed-off-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus.c | 1 + drivers/staging/media/sunxi/cedrus/cedrus.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 144286920749..e7741178465b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -556,6 +556,7 @@ static const struct cedrus_variant sun50i_h6_cedrus_variant = { CEDRUS_CAPABILITY_MPEG2_DEC | CEDRUS_CAPABILITY_H264_DEC | CEDRUS_CAPABILITY_H265_DEC | + CEDRUS_CAPABILITY_H265_10_DEC | CEDRUS_CAPABILITY_VP8_DEC, .mod_rate = 600000000, }; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 9c7bfd2b6616..c345f2984041 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -32,6 +32,7 @@ #define CEDRUS_CAPABILITY_H264_DEC BIT(2) #define CEDRUS_CAPABILITY_MPEG2_DEC BIT(3) #define CEDRUS_CAPABILITY_VP8_DEC BIT(4) +#define CEDRUS_CAPABILITY_H265_10_DEC BIT(5) enum cedrus_codec { CEDRUS_CODEC_MPEG2, -- cgit v1.2.3 From 83ffdc3292466d487a3cf38bc33516b6b42b7e5b Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 12 Sep 2021 10:20:51 +0200 Subject: media: cedrus: add check for H264 and H265 limitations Cedrus supports only YUV420 H264/H265 content and mostly only 8-bit colours (except on H6, where 10-bit are also supported). Add validation callback to SPS controls, which will reject unsupported combinations. Signed-off-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus.c | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index e7741178465b..9dd30cb568e8 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -28,6 +28,50 @@ #include "cedrus_dec.h" #include "cedrus_hw.h" +static int cedrus_try_ctrl(struct v4l2_ctrl *ctrl) +{ + if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) { + const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; + + if (sps->chroma_format_idc != 1) + /* Only 4:2:0 is supported */ + return -EINVAL; + if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) + /* Luma and chroma bit depth mismatch */ + return -EINVAL; + if (sps->bit_depth_luma_minus8 != 0) + /* Only 8-bit is supported */ + return -EINVAL; + } else if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_SPS) { + const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps; + struct cedrus_ctx *ctx = container_of(ctrl->handler, struct cedrus_ctx, hdl); + + if (sps->chroma_format_idc != 1) + /* Only 4:2:0 is supported */ + return -EINVAL; + + if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) + /* Luma and chroma bit depth mismatch */ + return -EINVAL; + + if (ctx->dev->capabilities & CEDRUS_CAPABILITY_H265_10_DEC) { + if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2) + /* Only 8-bit and 10-bit are supported */ + return -EINVAL; + } else { + if (sps->bit_depth_luma_minus8 != 0) + /* Only 8-bit is supported */ + return -EINVAL; + } + } + + return 0; +} + +static const struct v4l2_ctrl_ops cedrus_ctrl_ops = { + .try_ctrl = cedrus_try_ctrl, +}; + static const struct cedrus_control cedrus_controls[] = { { .cfg = { @@ -62,6 +106,7 @@ static const struct cedrus_control cedrus_controls[] = { { .cfg = { .id = V4L2_CID_STATELESS_H264_SPS, + .ops = &cedrus_ctrl_ops, }, .codec = CEDRUS_CODEC_H264, }, @@ -120,6 +165,7 @@ static const struct cedrus_control cedrus_controls[] = { { .cfg = { .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS, + .ops = &cedrus_ctrl_ops, }, .codec = CEDRUS_CODEC_H265, }, -- cgit v1.2.3 From 164646a78598071681032ace5fd3c9a1d57d8669 Mon Sep 17 00:00:00 2001 From: Jammy Huang Date: Tue, 14 Sep 2021 11:49:20 +0200 Subject: media: aspeed: refine to avoid full jpeg update The switch of jpeg 420/444 subsampling will update full jpeg header for aspeed now. Just update the 420/444 subsampling part of jpeg header is fine. Signed-off-by: Jammy Huang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index 77611c296a25..ebb5e5af3b93 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -422,6 +422,21 @@ static void aspeed_video_init_jpeg_table(u32 *table, bool yuv420) } } +// just update jpeg dct table per 420/444 +static void aspeed_video_update_jpeg_table(u32 *table, bool yuv420) +{ + int i; + unsigned int base; + + for (i = 0; i < ASPEED_VIDEO_JPEG_NUM_QUALITIES; i++) { + base = 256 * i; /* AST HW requires this header spacing */ + base += ASPEED_VIDEO_JPEG_HEADER_SIZE + + ASPEED_VIDEO_JPEG_DCT_SIZE; + + table[base + 2] = (yuv420) ? 0x00220103 : 0x00110103; + } +} + static void aspeed_video_update(struct aspeed_video *video, u32 reg, u32 clear, u32 bits) { @@ -1289,7 +1304,7 @@ static void aspeed_video_update_jpeg_quality(struct aspeed_video *video) static void aspeed_video_update_subsampling(struct aspeed_video *video) { if (video->jpeg.virt) - aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420); + aspeed_video_update_jpeg_table(video->jpeg.virt, video->yuv420); if (video->yuv420) aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_YUV420); -- cgit v1.2.3 From 984166720eb42e59c0c651f161c291b32dc360fc Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 15 Sep 2021 03:50:12 +0200 Subject: media: rcar-csi2: Cleanup mutex on remove and fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mutex was not destroyed on remove or failed probe, fix this. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-csi2.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index d7f560e312d4..0967ae3bed7e 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -1421,14 +1421,14 @@ static int rcsi2_probe(struct platform_device *pdev) ret = rcsi2_probe_resources(priv, pdev); if (ret) { dev_err(priv->dev, "Failed to get resources\n"); - return ret; + goto error_mutex; } platform_set_drvdata(pdev, priv); ret = rcsi2_parse_dt(priv); if (ret) - return ret; + goto error_mutex; priv->subdev.owner = THIS_MODULE; priv->subdev.dev = &pdev->dev; @@ -1450,21 +1450,23 @@ static int rcsi2_probe(struct platform_device *pdev) ret = media_entity_pads_init(&priv->subdev.entity, num_pads, priv->pads); if (ret) - goto error; + goto error_async; pm_runtime_enable(&pdev->dev); ret = v4l2_async_register_subdev(&priv->subdev); if (ret < 0) - goto error; + goto error_async; dev_info(priv->dev, "%d lanes found\n", priv->lanes); return 0; -error: +error_async: v4l2_async_nf_unregister(&priv->notifier); v4l2_async_nf_cleanup(&priv->notifier); +error_mutex: + mutex_destroy(&priv->lock); return ret; } @@ -1479,6 +1481,8 @@ static int rcsi2_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); + mutex_destroy(&priv->lock); + return 0; } -- cgit v1.2.3 From 5f4eecd5e903ec0f59f71e85f469ee2315b81550 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 15 Sep 2021 03:50:13 +0200 Subject: media: rcar-csi2: Serialize access to set_fmt and get_fmt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The access to the internal storage of the format rcar_csi2.mf should be serialized, extend the existing lock mutex to also cover this. While at it document the mutex. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-csi2.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index 0967ae3bed7e..11848d0c4a55 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -468,9 +468,8 @@ struct rcar_csi2 { struct v4l2_subdev *remote; unsigned int remote_pad; + struct mutex lock; /* Protects mf and stream_count. */ struct v4l2_mbus_framefmt mf; - - struct mutex lock; int stream_count; unsigned short lanes; @@ -836,6 +835,8 @@ static int rcsi2_set_pad_format(struct v4l2_subdev *sd, struct rcar_csi2 *priv = sd_to_csi2(sd); struct v4l2_mbus_framefmt *framefmt; + mutex_lock(&priv->lock); + if (!rcsi2_code_to_fmt(format->format.code)) format->format.code = rcar_csi2_formats[0].code; @@ -846,6 +847,8 @@ static int rcsi2_set_pad_format(struct v4l2_subdev *sd, *framefmt = format->format; } + mutex_unlock(&priv->lock); + return 0; } @@ -855,11 +858,15 @@ static int rcsi2_get_pad_format(struct v4l2_subdev *sd, { struct rcar_csi2 *priv = sd_to_csi2(sd); + mutex_lock(&priv->lock); + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) format->format = priv->mf; else format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0); + mutex_unlock(&priv->lock); + return 0; } -- cgit v1.2.3 From d66302f62f7dfb6dc937311ff80177ffea81ea38 Mon Sep 17 00:00:00 2001 From: Yajun Deng Date: Wed, 15 Sep 2021 11:45:09 +0200 Subject: media: v4l2-dev.h: move open brace after struct video_device The open brace should be after a struct of define, that's good for searching. Signed-off-by: Yajun Deng Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-dev.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 6a4afd4a7df2..5cf1edefb822 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -260,8 +260,7 @@ struct v4l2_file_operations { * Only set @dev_parent if that can't be deduced from @v4l2_dev. */ -struct video_device -{ +struct video_device { #if defined(CONFIG_MEDIA_CONTROLLER) struct media_entity entity; struct media_intf_devnode *intf_devnode; -- cgit v1.2.3 From 3ec54d3f2d8081035ca6116ee3db2dfafb938888 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Sep 2021 19:05:03 +0200 Subject: media: imx: drop unneeded MODULE_ALIAS The MODULE_DEVICE_TABLE already creates proper alias for platform driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-csi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 45f9d797b9da..3daa636b67db 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -2081,4 +2081,3 @@ module_platform_driver(imx_csi_driver); MODULE_DESCRIPTION("i.MX CSI subdev driver"); MODULE_AUTHOR("Steve Longerbeam "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-ipuv3-csi"); -- cgit v1.2.3 From 51fa3b70d27342baf1ea8aaab3e96e5f4f26d5b2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 17 Sep 2021 18:07:02 +0200 Subject: media: em28xx: Don't use ops->suspend if it is NULL The call to ops->suspend for the dev->dev_next case can currently trigger a call on a null function pointer if ops->suspend is null. Skip over the use of function ops->suspend if it is null. Addresses-Coverity: ("Dereference after null check") Fixes: be7fd3c3a8c5 ("media: em28xx: Hauppauge DualHD second tuner functionality") Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 584fa400cd7d..acc0bf7dbe2b 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -1154,8 +1154,9 @@ int em28xx_suspend_extension(struct em28xx *dev) dev_info(&dev->intf->dev, "Suspending extensions\n"); mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->suspend) - ops->suspend(dev); + if (!ops->suspend) + continue; + ops->suspend(dev); if (dev->dev_next) ops->suspend(dev->dev_next); } -- cgit v1.2.3 From d47fed7a848718196c4e588178b8bcede5285f51 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Mon, 20 Sep 2021 22:02:10 +0200 Subject: media: hantro: Constify static struct v4l2_m2m_ops The only usage of vpu_m2m_ops is to pass its address to v4l2_m2m_init() which has a pointer to const struct v4l2_m2m_ops as argument. Make it const to allow the compiler to put it in read-only memory. Signed-off-by: Rikard Falkeborn Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index f23fc14b3562..fb82b9297a2b 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -179,7 +179,7 @@ err_cancel_job: hantro_job_finish_no_pm(ctx->dev, ctx, VB2_BUF_STATE_ERROR); } -static struct v4l2_m2m_ops vpu_m2m_ops = { +static const struct v4l2_m2m_ops vpu_m2m_ops = { .device_run = device_run, }; -- cgit v1.2.3 From 21001fdb7dfa4a94b9ee76a9038ad16388d98f32 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 21 Sep 2021 22:39:44 +0200 Subject: media: vivid: fix an error code in vivid_create_instance() Preserve the error code stored in "dev->kthread_cec" before setting it to NULL. Fixes: 439e520995ab ("media: vivid: add signal-free time for cec message xfer") Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vivid/vivid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index bcf03bea1e3c..04b75666bad4 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -1934,9 +1934,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->kthread_cec = kthread_run(vivid_cec_bus_thread, dev, "vivid_cec-%s", dev->v4l2_dev.name); if (IS_ERR(dev->kthread_cec)) { + ret = PTR_ERR(dev->kthread_cec); dev->kthread_cec = NULL; v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); - ret = PTR_ERR(dev->kthread_cec); goto unreg_dev; } } -- cgit v1.2.3 From 2d080eb6a29fb9c128bf5c4239a1a3c8fd8424f9 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 22 Sep 2021 00:10:40 +0200 Subject: media: CEC: keep related menu entries together Keep all of the CEC menu items grouped together. By grouping all of these menu entries inside a menu/endmenu block, they are forced to be kept together and they are displayed/presented in a group for users. Tested with xconfig, gconfig, menuconfig, and nconfig. Fixes: 46d2a3b964dd ("media: place CEC menu before MEDIA_SUPPORT") Signed-off-by: Randy Dunlap Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/cec/Kconfig b/drivers/media/cec/Kconfig index 9ba3a00dce31..94ef3349b8d6 100644 --- a/drivers/media/cec/Kconfig +++ b/drivers/media/cec/Kconfig @@ -8,6 +8,8 @@ config CEC_NOTIFIER config CEC_PIN bool +menu "CEC support" + config MEDIA_CEC_RC bool "HDMI CEC RC integration" depends on CEC_CORE && RC_CORE @@ -37,3 +39,5 @@ source "drivers/media/cec/i2c/Kconfig" source "drivers/media/cec/platform/Kconfig" source "drivers/media/cec/usb/Kconfig" endif + +endmenu -- cgit v1.2.3 From c93beb5243750911a9a95aac31688ff85512b22e Mon Sep 17 00:00:00 2001 From: Vladimir Barinov Date: Fri, 24 Sep 2021 14:43:17 +0200 Subject: media: rcar-vin: add GREY format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for MEDIA_BUS_FMT_Y8_1X8 input and V4L2_PIX_FMT_GREY output format. Signed-off-by: Vladimir Barinov Signed-off-by: Nikita Yushchenko Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-dma.c | 15 +++++++++++++++ drivers/media/platform/rcar-vin/rcar-v4l2.c | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index e5162bf42bd0..25ead9333d00 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -114,6 +114,7 @@ /* Video n Data Mode Register bits */ #define VNDMR_A8BIT(n) (((n) & 0xff) << 24) #define VNDMR_A8BIT_MASK (0xff << 24) +#define VNDMR_YMODE_Y8 (1 << 12) #define VNDMR_EXRGB (1 << 8) #define VNDMR_BPSM (1 << 4) #define VNDMR_ABIT (1 << 2) @@ -603,6 +604,7 @@ void rvin_crop_scale_comp(struct rvin_dev *vin) case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_GREY: stride /= 2; break; default: @@ -695,6 +697,7 @@ static int rvin_setup(struct rvin_dev *vin) 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; break; default: @@ -774,6 +777,14 @@ static int rvin_setup(struct rvin_dev *vin) case V4L2_PIX_FMT_SRGGB8: dmr = 0; break; + case V4L2_PIX_FMT_GREY: + if (input_is_yuv) { + dmr = VNDMR_DTMD_YCSEP | VNDMR_YMODE_Y8; + output_is_yuv = true; + } else { + dmr = 0; + } + break; default: vin_err(vin, "Invalid pixelformat (0x%x)\n", vin->format.pixelformat); @@ -1148,6 +1159,10 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd, 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; default: return -EPIPE; } diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index 0d141155f0e3..bdeff51bf768 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -82,6 +82,10 @@ static const struct rvin_video_format rvin_formats[] = { .fourcc = V4L2_PIX_FMT_SRGGB8, .bpp = 1, }, + { + .fourcc = V4L2_PIX_FMT_GREY, + .bpp = 1, + }, }; const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, -- cgit v1.2.3 From 51f7be81feafe31c338f95510dfbcaa29e0798d3 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Fri, 24 Sep 2021 15:24:47 +0200 Subject: media: hantro: Auto generate the AXI ID to avoid conflicts The AXI ID is an AXI bus configuration for improve bus performance. If read and write operations use different IDs the operations can be paralleled, whereas when they have the same ID the operations will be serialized. Right now, the write ID is fixed to 0 but we can set it to 0xff to get auto generated IDs to avoid possible conflicts. This change has no functional changes, but seems reasonable to let the hardware to autogenerate the ID instead of hardcoding in software. Signed-off-by: Enric Balletbo i Serra Signed-off-by: Benjamin Gaignard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_g1_h264_dec.c | 2 +- drivers/staging/media/hantro/hantro_g1_regs.h | 2 ++ drivers/staging/media/hantro/hantro_g1_vp8_dec.c | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c index 236ce24ca00c..f49dbfb8a843 100644 --- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c @@ -29,7 +29,7 @@ static void set_params(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) u32 reg; /* Decoder control register 0. */ - reg = G1_REG_DEC_CTRL0_DEC_AXI_WR_ID(0x0); + reg = G1_REG_DEC_CTRL0_DEC_AXI_AUTO; if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) reg |= G1_REG_DEC_CTRL0_SEQ_MBAFF_E; if (sps->profile_idc > 66) { diff --git a/drivers/staging/media/hantro/hantro_g1_regs.h b/drivers/staging/media/hantro/hantro_g1_regs.h index c1756e3d5391..c623b3b0be18 100644 --- a/drivers/staging/media/hantro/hantro_g1_regs.h +++ b/drivers/staging/media/hantro/hantro_g1_regs.h @@ -68,6 +68,8 @@ #define G1_REG_DEC_CTRL0_PICORD_COUNT_E BIT(9) #define G1_REG_DEC_CTRL0_DEC_AHB_HLOCK_E BIT(8) #define G1_REG_DEC_CTRL0_DEC_AXI_WR_ID(x) (((x) & 0xff) << 0) +/* Setting AXI ID to 0xff to get auto generated ID to avoid possible conflicts */ +#define G1_REG_DEC_CTRL0_DEC_AXI_AUTO G1_REG_DEC_CTRL0_DEC_AXI_WR_ID(0xff) #define G1_REG_DEC_CTRL1 0x010 #define G1_REG_DEC_CTRL1_PIC_MB_WIDTH(x) (((x) & 0x1ff) << 23) #define G1_REG_DEC_CTRL1_MB_WIDTH_OFF(x) (((x) & 0xf) << 19) diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c index 6180b23e7d94..851eb67f19f5 100644 --- a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c @@ -463,7 +463,8 @@ int hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) G1_REG_CONFIG_DEC_MAX_BURST(16); vdpu_write_relaxed(vpu, reg, G1_REG_CONFIG); - reg = G1_REG_DEC_CTRL0_DEC_MODE(10); + reg = G1_REG_DEC_CTRL0_DEC_MODE(10) | + G1_REG_DEC_CTRL0_DEC_AXI_AUTO; if (!V4L2_VP8_FRAME_IS_KEY_FRAME(hdr)) reg |= G1_REG_DEC_CTRL0_PIC_INTER_E; if (!(hdr->flags & V4L2_VP8_FRAME_FLAG_MB_NO_SKIP_COEFF)) -- cgit v1.2.3 From 64cdf7e5a3aac0e7c9efdb079e74e22875b0419a Mon Sep 17 00:00:00 2001 From: Irui Wang Date: Sun, 26 Sep 2021 05:39:35 +0200 Subject: media: mtk-vcodec: MT8173 h264/vp8 encoder min/max bitrate settings Set recommend min/max bitrate range for MT8173 h264/vp8 encoder. Signed-off-by: Irui Wang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c index 8bbcb53fe3df..eed67394cf46 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c @@ -392,8 +392,8 @@ static const struct mtk_vcodec_enc_pdata mt8173_avc_pdata = { .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), .output_formats = mtk_video_formats_output, .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), - .min_bitrate = 1, - .max_bitrate = 4000000, + .min_bitrate = 64, + .max_bitrate = 60000000, .core_id = VENC_SYS, }; @@ -404,7 +404,7 @@ static const struct mtk_vcodec_enc_pdata mt8173_vp8_pdata = { .output_formats = mtk_video_formats_output, .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), .min_bitrate = 64, - .max_bitrate = 4000000, + .max_bitrate = 9000000, .core_id = VENC_LT_SYS, }; -- cgit v1.2.3 From 83f5f0633b156c636f5249d3c10f2a9423dd4c96 Mon Sep 17 00:00:00 2001 From: Mirela Rabulea Date: Mon, 27 Sep 2021 20:56:32 +0200 Subject: media: imx-jpeg: Fix possible null pointer dereference Found by Coverity scan. Signed-off-by: Mirela Rabulea Reviewed-by: Laurentiu Palcu Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/imx-jpeg/mxc-jpeg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/imx-jpeg/mxc-jpeg.c index 73e73b6f2e5b..512baf75f9e3 100644 --- a/drivers/media/platform/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.c @@ -575,6 +575,10 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + if (!dst_buf || !src_buf) { + dev_err(dev, "No source or destination buffer.\n"); + goto job_unlock; + } jpeg_src_buf = vb2_to_mxc_buf(&src_buf->vb2_buf); if (dec_ret & SLOT_STATUS_ENC_CONFIG_ERR) { -- cgit v1.2.3 From 34acaf65dc2281400bf97a2f3c894a581ef566e9 Mon Sep 17 00:00:00 2001 From: Mirela Rabulea Date: Mon, 27 Sep 2021 20:56:57 +0200 Subject: media: imx-jpeg: Fix occasional decoder fail on jpegs without DHT Add some body to the dummy jpeg used to inject a default DHT. Use jpeg_image_red as compressed image data, insert it at the end of SOS, before EOI. The pure dummy jpeg was occasionally not working well on 8qxp C0. Signed-off-by: Mirela Rabulea Reviewed-by: Laurentiu Palcu Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/imx-jpeg/mxc-jpeg.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/imx-jpeg/mxc-jpeg.c index 512baf75f9e3..01c085748325 100644 --- a/drivers/media/platform/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.c @@ -282,6 +282,20 @@ static const unsigned char jpeg_sos_maximal[] = { 0x11, 0x04, 0x11, 0x00, 0x3F, 0x00 }; +static const unsigned char jpeg_image_red[] = { + 0xFC, 0x5F, 0xA2, 0xBF, 0xCA, 0x73, 0xFE, 0xFE, + 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00, + 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, + 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28, + 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, + 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0, + 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00, + 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, + 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28, + 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, + 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00 +}; + static const unsigned char jpeg_eoi[] = { 0xFF, 0xD9 }; @@ -764,6 +778,9 @@ static unsigned int mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr, sos = (struct mxc_jpeg_sos *)(cfg + offset); offset += mxc_jpeg_fixup_sos(sos, fourcc); + memcpy(cfg + offset, jpeg_image_red, sizeof(jpeg_image_red)); + offset += sizeof(jpeg_image_red); + memcpy(cfg + offset, jpeg_eoi, sizeof(jpeg_eoi)); offset += sizeof(jpeg_eoi); -- cgit v1.2.3 From ae3cab78dc48958f8fc88ea79e57ec73f2070042 Mon Sep 17 00:00:00 2001 From: Mirela Rabulea Date: Mon, 27 Sep 2021 20:57:19 +0200 Subject: media: imx-jpeg: Remove soft reset between frames encoding Remove soft reset between frames, which was merely a workaround, actually replace it with something less aggressive: clearing of jpeg stream buffer pointer, via STM_CTRL[BITBUF_PTR_CLR]. According to the reference manual, the BITBUF_PTR_CLR is performed on context switch, but, per hardware team recommendation, it is also working without context switch, which is the case for this driver, for now. Without soft reset and without BITBUF_PTR_CLR, successive encoding jobs continue from where the previous left off, basically writing past the v4l2 buffer. Signed-off-by: Mirela Rabulea Reviewed-by: Robert Chiras Reviewed-by: Laurentiu Palcu Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/imx-jpeg/mxc-jpeg.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/imx-jpeg/mxc-jpeg.c index 01c085748325..e45b0c74be55 100644 --- a/drivers/media/platform/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.c @@ -816,6 +816,7 @@ static void mxc_jpeg_config_dec_desc(struct vb2_buffer *out_buf, img_fmt = mxc_jpeg_fourcc_to_imgfmt(q_data_cap->fmt->fourcc); desc->stm_ctrl &= ~STM_CTRL_IMAGE_FORMAT(0xF); /* clear image format */ desc->stm_ctrl |= STM_CTRL_IMAGE_FORMAT(img_fmt); + desc->stm_ctrl |= STM_CTRL_BITBUF_PTR_CLR(1); desc->line_pitch = q_data_cap->bytesperline[0]; mxc_jpeg_addrs(desc, dst_buf, src_buf, 0); mxc_jpeg_set_bufsize(desc, ALIGN(vb2_plane_size(src_buf, 0), 1024)); @@ -842,6 +843,7 @@ static void mxc_jpeg_config_dec_desc(struct vb2_buffer *out_buf, cfg_desc->imgsize |= MXC_JPEG_MIN_HEIGHT; cfg_desc->line_pitch = MXC_JPEG_MIN_WIDTH * 2; cfg_desc->stm_ctrl = STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV422); + cfg_desc->stm_ctrl |= STM_CTRL_BITBUF_PTR_CLR(1); cfg_desc->stm_bufbase = cfg_stream_handle; cfg_desc->stm_bufsize = ALIGN(*cfg_size, 1024); print_descriptor_info(jpeg->dev, cfg_desc); @@ -885,6 +887,7 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf, cfg_desc->stm_bufsize = 0x0; cfg_desc->imgsize = 0; cfg_desc->stm_ctrl = STM_CTRL_CONFIG_MOD(1); + cfg_desc->stm_ctrl |= STM_CTRL_BITBUF_PTR_CLR(1); desc->next_descpt_ptr = 0; /* end of chain */ @@ -899,6 +902,7 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf, dev_err(jpeg->dev, "No valid image format detected\n"); desc->stm_ctrl = STM_CTRL_CONFIG_MOD(0) | STM_CTRL_IMAGE_FORMAT(img_fmt); + desc->stm_ctrl |= STM_CTRL_BITBUF_PTR_CLR(1); mxc_jpeg_addrs(desc, src_buf, dst_buf, 0); dev_dbg(jpeg->dev, "cfg_desc:\n"); print_descriptor_info(jpeg->dev, cfg_desc); @@ -954,11 +958,6 @@ static void mxc_jpeg_device_run(void *priv) return; } - /* - * TODO: this reset should be removed, once we figure out - * how to overcome hardware issues both on encoder and decoder - */ - mxc_jpeg_sw_reset(reg); mxc_jpeg_enable(reg); mxc_jpeg_set_l_endian(reg, 1); -- cgit v1.2.3 From e73396fee2614145e2f77a88cafbfc25183994f8 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Fri, 18 Jun 2021 18:10:41 +0200 Subject: media: vsp1: Fix WPF macro names The WPF IRQ enable and status macros have been incorrectly named WFP. Fix them accordingly, and update all uses of the macros. Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drv.c | 4 ++-- drivers/media/platform/vsp1/vsp1_regs.h | 8 ++++---- drivers/media/platform/vsp1/vsp1_wpf.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 8acd6d45d8d0..bb256e36bda4 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -44,7 +44,7 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data) { - u32 mask = VI6_WFP_IRQ_STA_DFE | VI6_WFP_IRQ_STA_FRE; + u32 mask = VI6_WPF_IRQ_STA_DFE | VI6_WPF_IRQ_STA_FRE; struct vsp1_device *vsp1 = data; irqreturn_t ret = IRQ_NONE; unsigned int i; @@ -59,7 +59,7 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data) status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i)); vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask); - if (status & VI6_WFP_IRQ_STA_DFE) { + if (status & VI6_WPF_IRQ_STA_DFE) { vsp1_pipeline_frame_end(wpf->entity.pipe); ret = IRQ_HANDLED; } diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index fe3130db1fa2..97942436868c 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -32,12 +32,12 @@ #define VI6_STATUS_SYS_ACT(n) BIT((n) + 8) #define VI6_WPF_IRQ_ENB(n) (0x0048 + (n) * 12) -#define VI6_WFP_IRQ_ENB_DFEE BIT(1) -#define VI6_WFP_IRQ_ENB_FREE BIT(0) +#define VI6_WPF_IRQ_ENB_DFEE BIT(1) +#define VI6_WPF_IRQ_ENB_FREE BIT(0) #define VI6_WPF_IRQ_STA(n) (0x004c + (n) * 12) -#define VI6_WFP_IRQ_STA_DFE BIT(1) -#define VI6_WFP_IRQ_STA_FRE BIT(0) +#define VI6_WPF_IRQ_STA_DFE BIT(1) +#define VI6_WPF_IRQ_STA_FRE BIT(0) #define VI6_DISP_IRQ_ENB(n) (0x0078 + (n) * 60) #define VI6_DISP_IRQ_ENB_DSTE BIT(8) diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 208498fa6ed7..94e91d7bb56c 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -342,7 +342,7 @@ static void wpf_configure_stream(struct vsp1_entity *entity, /* Enable interrupts. */ vsp1_dl_body_write(dlb, VI6_WPF_IRQ_STA(index), 0); vsp1_dl_body_write(dlb, VI6_WPF_IRQ_ENB(index), - VI6_WFP_IRQ_ENB_DFEE); + VI6_WPF_IRQ_ENB_DFEE); /* * Configure writeback for display pipelines (the wpf writeback flag is -- cgit v1.2.3 From 168c05a3e6ac4f575298abbf9a6eef7c1b024f70 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Fri, 18 Jun 2021 21:09:05 +0200 Subject: media: vsp1: Simplify DRM UIF handling In commit 6732f3139380 ("media: v4l: vsp1: Fix uif null pointer access") the handling of the UIF was over complicated, and the patch applied before review. Simplify it to keep the conditionals small. Signed-off-by: Kieran Bingham Reviewed-by: Biju Das Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index 06f74d410973..0c2507dc03d6 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -455,6 +455,10 @@ static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1, dev_err(vsp1->dev, "%s: failed to setup UIF after %s\n", __func__, BRX_NAME(pipe->brx)); + /* If the DRM pipe does not have a UIF there is nothing we can update. */ + if (!drm_pipe->uif) + return 0; + /* * If the UIF is not in use schedule it for removal by setting its pipe * pointer to NULL, vsp1_du_pipeline_configure() will remove it from the @@ -462,9 +466,9 @@ static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1, * make sure it is present in the pipeline's list of entities if it * wasn't already. */ - if (drm_pipe->uif && !use_uif) { + if (!use_uif) { drm_pipe->uif->pipe = NULL; - } else if (drm_pipe->uif && !drm_pipe->uif->pipe) { + } else if (!drm_pipe->uif->pipe) { drm_pipe->uif->pipe = pipe; list_add_tail(&drm_pipe->uif->list_pipe, &pipe->entities); } -- cgit v1.2.3 From 8888a2ff634e9cf1d62457109811afc43c2be2ed Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Wed, 23 Jun 2021 01:09:50 +0200 Subject: media: vsp1: Add support for the V3U VSPD The V3U provides two VSPD instances, with a new update to the version register to detect the new SoC. Add the new version and model detection, and detail the features available in this module. Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drv.c | 10 ++++++++++ drivers/media/platform/vsp1/vsp1_regs.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index bb256e36bda4..c9044785b903 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -777,6 +777,16 @@ static const struct vsp1_device_info vsp1_device_infos[] = { .uif_count = 2, .wpf_count = 2, .num_bru_inputs = 5, + }, { + .version = VI6_IP_VERSION_MODEL_VSPD_V3U, + .model = "VSP2-D", + .gen = 3, + .features = VSP1_HAS_BRU | VSP1_HAS_EXT_DL, + .lif_count = 1, + .rpf_count = 5, + .uif_count = 2, + .wpf_count = 1, + .num_bru_inputs = 5, }, }; diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 97942436868c..fae7286eb01e 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -766,6 +766,8 @@ #define VI6_IP_VERSION_MODEL_VSPD_V3 (0x18 << 8) #define VI6_IP_VERSION_MODEL_VSPDL_GEN3 (0x19 << 8) #define VI6_IP_VERSION_MODEL_VSPBS_GEN3 (0x1a << 8) +#define VI6_IP_VERSION_MODEL_VSPD_V3U (0x1c << 8) + #define VI6_IP_VERSION_SOC_MASK (0xff << 0) #define VI6_IP_VERSION_SOC_H2 (0x01 << 0) #define VI6_IP_VERSION_SOC_V2H (0x01 << 0) @@ -777,6 +779,7 @@ #define VI6_IP_VERSION_SOC_D3 (0x04 << 0) #define VI6_IP_VERSION_SOC_M3N (0x04 << 0) #define VI6_IP_VERSION_SOC_E3 (0x04 << 0) +#define VI6_IP_VERSION_SOC_V3U (0x05 << 0) /* ----------------------------------------------------------------------------- * RPF CLUT Registers -- cgit v1.2.3 From 92b7b90c9005b75f8cd48f9a89737fb40ae365f2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 27 Sep 2021 15:41:06 +0200 Subject: media: omap_vout: use dma_addr_t consistently gcc notices that the driver mixes 'dma_addr_t' 'u8 *' and 'u32' to store DMA addresses: drivers/media/platform/omap/omap_vout.c: In function 'omap_vout_vb2_prepare': drivers/media/platform/omap/omap_vout.c:979:37: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] vout->queued_buf_addr[vb->index] = (u8 *)buf_phy_addr; ^ drivers/media/platform/omap/omap_vout.c: In function 'omap_vout_create_video_devices': drivers/media/platform/omap/omap_vout.c:1479:21: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] vout->fbuf.base = (void *)info.paddr; Use dma_addr_t everywhere here to avoid the type conversions and document what the address is used for. Assigning to vout->fbuf.base still requires a cast, since that is part of the driver independent data structure. Signed-off-by: Arnd Bergmann Reviewed-by: Laurent Pinchart Reviewed-by: Peter Ujfalusi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/omap_vout.c | 18 ++++++++++-------- drivers/media/platform/omap/omap_vout_vrfb.c | 2 +- drivers/media/platform/omap/omap_voutdef.h | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 21193f0b7f61..3e0d9af7ffec 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -277,7 +277,7 @@ static int video_mode_to_dss_mode(struct omap_vout_device *vout) */ static int omapvid_setup_overlay(struct omap_vout_device *vout, struct omap_overlay *ovl, int posx, int posy, int outw, - int outh, u32 addr) + int outh, dma_addr_t addr) { int ret = 0; struct omap_overlay_info info; @@ -352,7 +352,7 @@ setup_ovl_err: /* * Initialize the overlay structure */ -static int omapvid_init(struct omap_vout_device *vout, u32 addr) +static int omapvid_init(struct omap_vout_device *vout, dma_addr_t addr) { int ret = 0, i; struct v4l2_window *win; @@ -479,7 +479,8 @@ err: static void omap_vout_isr(void *arg, unsigned int irqstatus) { int ret, fid, mgr_id; - u32 addr, irq; + dma_addr_t addr; + u32 irq; struct omap_overlay *ovl; u64 ts; struct omapvideo_info *ovid; @@ -543,7 +544,7 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) struct omap_vout_buffer, queue); list_del(&vout->next_frm->queue); - addr = (unsigned long)vout->queued_buf_addr[vout->next_frm->vbuf.vb2_buf.index] + addr = vout->queued_buf_addr[vout->next_frm->vbuf.vb2_buf.index] + vout->cropped_offset; /* First save the configuration in ovelray structure */ @@ -976,7 +977,7 @@ static int omap_vout_vb2_prepare(struct vb2_buffer *vb) vb2_set_plane_payload(vb, 0, vout->pix.sizeimage); voutbuf->vbuf.field = V4L2_FIELD_NONE; - vout->queued_buf_addr[vb->index] = (u8 *)buf_phy_addr; + vout->queued_buf_addr[vb->index] = buf_phy_addr; if (ovid->rotation_type == VOUT_ROT_VRFB) return omap_vout_prepare_vrfb(vout, vb); return 0; @@ -995,7 +996,8 @@ static int omap_vout_vb2_start_streaming(struct vb2_queue *vq, unsigned int coun struct omap_vout_device *vout = vb2_get_drv_priv(vq); struct omapvideo_info *ovid = &vout->vid_info; struct omap_vout_buffer *buf, *tmp; - u32 addr = 0, mask = 0; + dma_addr_t addr = 0; + u32 mask = 0; int ret, j; /* Get the next frame from the buffer queue */ @@ -1018,7 +1020,7 @@ static int omap_vout_vb2_start_streaming(struct vb2_queue *vq, unsigned int coun goto out; } - addr = (unsigned long)vout->queued_buf_addr[vout->cur_frm->vbuf.vb2_buf.index] + addr = vout->queued_buf_addr[vout->cur_frm->vbuf.vb2_buf.index] + vout->cropped_offset; mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD @@ -1476,7 +1478,7 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) * To be precise: fbuf.base should match smem_start of * struct fb_fix_screeninfo. */ - vout->fbuf.base = (void *)info.paddr; + vout->fbuf.base = (void *)(uintptr_t)info.paddr; /* Set VRFB as rotation_type for omap2 and omap3 */ if (omap_vout_dss_omap24xx() || omap_vout_dss_omap34xx()) diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c index 6bd672cbdb62..0cfa0169875f 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.c +++ b/drivers/media/platform/omap/omap_vout_vrfb.c @@ -305,7 +305,7 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout, /* Store buffers physical address into an array. Addresses * from this array will be used to configure DSS */ rotation = calc_rotation(vout); - vout->queued_buf_addr[vb->index] = (u8 *) + vout->queued_buf_addr[vb->index] = vout->vrfb_context[vb->index].paddr[rotation]; return 0; } diff --git a/drivers/media/platform/omap/omap_voutdef.h b/drivers/media/platform/omap/omap_voutdef.h index 1cff6dea1879..b586193341d2 100644 --- a/drivers/media/platform/omap/omap_voutdef.h +++ b/drivers/media/platform/omap/omap_voutdef.h @@ -170,7 +170,7 @@ struct omap_vout_device { struct omap_vout_buffer *cur_frm, *next_frm; spinlock_t vbq_lock; /* spinlock for dma_queue */ struct list_head dma_queue; - u8 *queued_buf_addr[VIDEO_MAX_FRAME]; + dma_addr_t queued_buf_addr[VIDEO_MAX_FRAME]; u32 cropped_offset; s32 tv_field1_offset; void *isr_handle; -- cgit v1.2.3 From 799926a123cfe6fcb38979c45b3609c0aea61b84 Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Thu, 29 Jul 2021 11:30:44 +0200 Subject: media: venus: helper: change log level for false warning message In current video driver implementation in calculate_inst_freq() frequency is calculated based on filled_len. The filled_len may vary frame to frame, because of this in load_scale_v4() since frequency is calculated for all instances, driver is throwing false warning like "HW is overloaded". Hence to handle this, changed log level to low log message. Since the actual session rejection is happening in decide_core() based on load. Signed-off-by: Mansur Alisha Shaik Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/pm_helpers.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 3e2345eb47f7..679177e7ad22 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -1139,9 +1139,10 @@ static int load_scale_v4(struct venus_inst *inst) freq = max(freq_core1, freq_core2); if (freq > table[0].freq) { + dev_dbg(dev, VDBGL "requested clock rate: %lu scaling clock rate : %lu\n", + freq, table[0].freq); + freq = table[0].freq; - dev_warn(dev, "HW is overloaded, needed: %lu max: %lu\n", - freq, table[0].freq); goto set_freq; } -- cgit v1.2.3 From 8c404ebae527515ea5274d03e23976b55fdb26fc Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Wed, 25 Aug 2021 10:44:34 +0200 Subject: media: venus: vdec: update output buffer size during vdec_s_fmt() Video driver maintains an internal context for the output buffer size. During S_fmt() on capture plane, the output buffer size is not updated in driver context. As a result, during buf_prepare(), the size of the vb2_plane and internal size of the buffer, as maintained by the driver, does not match. This leads to buf_prepare() failure. Update the instance context for the output buffer size during s_fmt(). Signed-off-by: Mansur Alisha Shaik Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/vdec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 198e47eb63f4..c129b061a325 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -332,8 +332,11 @@ static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f) if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) inst->fmt_out = fmt; - else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { inst->fmt_cap = fmt; + inst->output2_buf_size = + venus_helper_get_framesz(pixfmt_cap, orig_pixmp.width, orig_pixmp.height); + } return 0; } -- cgit v1.2.3 From 1444232152ea33f5ae41fc14bade3e74d642b634 Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Tue, 14 Sep 2021 05:57:07 +0200 Subject: media: venus: fix vpp frequency calculation for decoder In existing video driver implementation vpp frequency calculation in calculate_inst_freq() is always zero because the value of vpp_freq_per_mb is always zero for decoder. Fixed this by correcting the calculating the vpp frequency calculation for decoder. Fixes: 3cfe5815ce0e ("media: venus: Enable low power setting for encoder") Signed-off-by: Mansur Alisha Shaik Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/pm_helpers.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 679177e7ad22..cedc664ba755 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -1085,12 +1085,16 @@ static unsigned long calculate_inst_freq(struct venus_inst *inst, if (inst->state != INST_START) return 0; - if (inst->session_type == VIDC_SESSION_TYPE_ENC) + if (inst->session_type == VIDC_SESSION_TYPE_ENC) { vpp_freq_per_mb = inst->flags & VENUS_LOW_POWER ? inst->clk_data.low_power_freq : inst->clk_data.vpp_freq; - vpp_freq = mbs_per_sec * vpp_freq_per_mb; + vpp_freq = mbs_per_sec * vpp_freq_per_mb; + } else { + vpp_freq = mbs_per_sec * inst->clk_data.vpp_freq; + } + /* 21 / 20 is overhead factor */ vpp_freq += vpp_freq / 20; vsp_freq = mbs_per_sec * inst->clk_data.vsp_freq; -- cgit v1.2.3 From e48b839b6699c2268e545360e06962bb76ff5b8d Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Tue, 28 Sep 2021 07:55:40 +0200 Subject: media: dt-bindings: media: venus: Add sc7280 dt schema Add a schema description for the venus video encoder/decoder on the sc7280. Signed-off-by: Dikshita Agarwal Reviewed-by: Rob Herring Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/qcom,sc7280-venus.yaml | 162 +++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/qcom,sc7280-venus.yaml diff --git a/Documentation/devicetree/bindings/media/qcom,sc7280-venus.yaml b/Documentation/devicetree/bindings/media/qcom,sc7280-venus.yaml new file mode 100644 index 000000000000..fa54c560e0bd --- /dev/null +++ b/Documentation/devicetree/bindings/media/qcom,sc7280-venus.yaml @@ -0,0 +1,162 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/media/qcom,sc7280-venus.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Qualcomm Venus video encode and decode accelerators + +maintainers: + - Stanimir Varbanov + +description: | + The Venus Iris2 IP is a video encode and decode accelerator present + on Qualcomm platforms + +properties: + compatible: + const: qcom,sc7280-venus + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + power-domains: + minItems: 2 + maxItems: 3 + + power-domain-names: + minItems: 2 + maxItems: 3 + items: + - const: venus + - const: vcodec0 + - const: cx + + clocks: + maxItems: 5 + + clock-names: + items: + - const: core + - const: bus + - const: iface + - const: vcodec_core + - const: vcodec_bus + + iommus: + maxItems: 2 + + memory-region: + maxItems: 1 + + interconnects: + maxItems: 2 + + interconnect-names: + items: + - const: cpu-cfg + - const: video-mem + + video-decoder: + type: object + + properties: + compatible: + const: venus-decoder + + required: + - compatible + + additionalProperties: false + + video-encoder: + type: object + + properties: + compatible: + const: venus-encoder + + required: + - compatible + + additionalProperties: false + + video-firmware: + type: object + + description: | + Firmware subnode is needed when the platform does not + have TrustZone. + + properties: + iommus: + maxItems: 1 + + required: + - iommus + +required: + - compatible + - reg + - interrupts + - power-domains + - power-domain-names + - clocks + - clock-names + - iommus + - memory-region + - video-decoder + - video-encoder + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + venus: video-codec@aa00000 { + compatible = "qcom,sc7280-venus"; + reg = <0x0aa00000 0xd0600>; + interrupts = ; + + clocks = <&videocc VIDEO_CC_MVSC_CORE_CLK>, + <&videocc VIDEO_CC_MVSC_CTL_AXI_CLK>, + <&videocc VIDEO_CC_VENUS_AHB_CLK>, + <&videocc VIDEO_CC_MVS0_CORE_CLK>, + <&videocc VIDEO_CC_MVS0_AXI_CLK>; + clock-names = "core", "bus", "iface", + "vcodec_core", "vcodec_bus"; + + power-domains = <&videocc MVSC_GDSC>, + <&videocc MVS0_GDSC>, + <&rpmhpd SC7280_CX>; + power-domain-names = "venus", "vcodec0", "cx"; + + interconnects = <&gem_noc MASTER_APPSS_PROC 0 &cnoc2 SLAVE_VENUS_CFG 0>, + <&mmss_noc MASTER_VIDEO_P0 0 &mc_virt SLAVE_EBI1 0>; + interconnect-names = "cpu-cfg", "video-mem"; + + iommus = <&apps_smmu 0x2180 0x20>, + <&apps_smmu 0x2184 0x20>; + + memory-region = <&video_mem>; + + video-decoder { + compatible = "venus-decoder"; + }; + + video-encoder { + compatible = "venus-encoder"; + }; + + video-firmware { + iommus = <&apps_smmu 0x21a2 0x0>; + }; + }; -- cgit v1.2.3 From afeae6ef07807c2d57ae1115c6993758a6d99525 Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Tue, 10 Aug 2021 11:47:49 +0200 Subject: media: venus: firmware: enable no tz fw loading for sc7280 Enable no tz FW loading and add routine to reset XTSS. Signed-off-by: Dikshita Agarwal Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/firmware.c | 42 +++++++++++++++++------- drivers/media/platform/qcom/venus/hfi_venus_io.h | 2 ++ 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 227bd3b3f84c..14b6f1d05991 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -27,7 +27,12 @@ static void venus_reset_cpu(struct venus_core *core) { u32 fw_size = core->fw.mapped_mem_size; - void __iomem *wrapper_base = core->wrapper_base; + void __iomem *wrapper_base; + + if (IS_V6(core)) + wrapper_base = core->wrapper_tz_base; + else + wrapper_base = core->wrapper_base; writel(0, wrapper_base + WRAPPER_FW_START_ADDR); writel(fw_size, wrapper_base + WRAPPER_FW_END_ADDR); @@ -35,11 +40,17 @@ static void venus_reset_cpu(struct venus_core *core) writel(fw_size, wrapper_base + WRAPPER_CPA_END_ADDR); writel(fw_size, wrapper_base + WRAPPER_NONPIX_START_ADDR); writel(fw_size, wrapper_base + WRAPPER_NONPIX_END_ADDR); - writel(0x0, wrapper_base + WRAPPER_CPU_CGC_DIS); - writel(0x0, wrapper_base + WRAPPER_CPU_CLOCK_CONFIG); - /* Bring ARM9 out of reset */ - writel(0, wrapper_base + WRAPPER_A9SS_SW_RESET); + if (IS_V6(core)) { + /* Bring XTSS out of reset */ + writel(0, wrapper_base + WRAPPER_TZ_XTSS_SW_RESET); + } else { + writel(0x0, wrapper_base + WRAPPER_CPU_CGC_DIS); + writel(0x0, wrapper_base + WRAPPER_CPU_CLOCK_CONFIG); + + /* Bring ARM9 out of reset */ + writel(0, wrapper_base + WRAPPER_A9SS_SW_RESET); + } } int venus_set_hw_state(struct venus_core *core, bool resume) @@ -56,7 +67,9 @@ int venus_set_hw_state(struct venus_core *core, bool resume) if (resume) { venus_reset_cpu(core); } else { - if (!IS_V6(core)) + if (IS_V6(core)) + writel(1, core->wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET); + else writel(1, core->wrapper_base + WRAPPER_A9SS_SW_RESET); } @@ -162,12 +175,19 @@ static int venus_shutdown_no_tz(struct venus_core *core) u32 reg; struct device *dev = core->fw.dev; void __iomem *wrapper_base = core->wrapper_base; + void __iomem *wrapper_tz_base = core->wrapper_tz_base; - /* Assert the reset to ARM9 */ - reg = readl_relaxed(wrapper_base + WRAPPER_A9SS_SW_RESET); - reg |= WRAPPER_A9SS_SW_RESET_BIT; - writel_relaxed(reg, wrapper_base + WRAPPER_A9SS_SW_RESET); - + if (IS_V6(core)) { + /* Assert the reset to XTSS */ + reg = readl_relaxed(wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET); + reg |= WRAPPER_XTSS_SW_RESET_BIT; + writel_relaxed(reg, wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET); + } else { + /* Assert the reset to ARM9 */ + reg = readl_relaxed(wrapper_base + WRAPPER_A9SS_SW_RESET); + reg |= WRAPPER_A9SS_SW_RESET_BIT; + writel_relaxed(reg, wrapper_base + WRAPPER_A9SS_SW_RESET); + } /* Make sure reset is asserted before the mapping is removed */ mb(); diff --git a/drivers/media/platform/qcom/venus/hfi_venus_io.h b/drivers/media/platform/qcom/venus/hfi_venus_io.h index 300c6e47e72f..9735a246ce36 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus_io.h +++ b/drivers/media/platform/qcom/venus/hfi_venus_io.h @@ -149,6 +149,8 @@ /* Wrapper TZ 6xx */ #define WRAPPER_TZ_BASE_V6 0x000c0000 #define WRAPPER_TZ_CPU_STATUS_V6 0x10 +#define WRAPPER_TZ_XTSS_SW_RESET 0x1000 +#define WRAPPER_XTSS_SW_RESET_BIT BIT(0) /* Venus AON */ #define AON_BASE_V6 0x000e0000 -- cgit v1.2.3 From 275ad3b3ed1a7aa435758ac6190db4a55abea811 Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Tue, 10 Aug 2021 11:47:50 +0200 Subject: media: venus: core: Add sc7280 DT compatible and resource data Adds a sm7280 compatible binding to the venus core. Co-developed-by: Mansur Alisha Shaik Signed-off-by: Mansur Alisha Shaik Signed-off-by: Dikshita Agarwal Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.c | 52 ++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 7e54c5d571dc..e5af4d74e504 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -734,12 +734,64 @@ static const struct venus_resources sm8250_res = { .fwname = "qcom/vpu-1.0/venus.mdt", }; +static const struct freq_tbl sc7280_freq_table[] = { + { 0, 460000000 }, + { 0, 424000000 }, + { 0, 335000000 }, + { 0, 240000000 }, + { 0, 133333333 }, +}; + +static const struct bw_tbl sc7280_bw_table_enc[] = { + { 1944000, 1896000, 0, 3657000, 0 }, /* 3840x2160@60 */ + { 972000, 968000, 0, 1848000, 0 }, /* 3840x2160@30 */ + { 489600, 618000, 0, 941000, 0 }, /* 1920x1080@60 */ + { 244800, 318000, 0, 480000, 0 }, /* 1920x1080@30 */ +}; + +static const struct bw_tbl sc7280_bw_table_dec[] = { + { 2073600, 2128000, 0, 3831000, 0 }, /* 4096x2160@60 */ + { 1036800, 1085000, 0, 1937000, 0 }, /* 4096x2160@30 */ + { 489600, 779000, 0, 998000, 0 }, /* 1920x1080@60 */ + { 244800, 400000, 0, 509000, 0 }, /* 1920x1080@30 */ +}; + +static const struct reg_val sm7280_reg_preset[] = { + { 0xb0088, 0 }, +}; + +static const struct venus_resources sc7280_res = { + .freq_tbl = sc7280_freq_table, + .freq_tbl_size = ARRAY_SIZE(sc7280_freq_table), + .reg_tbl = sm7280_reg_preset, + .reg_tbl_size = ARRAY_SIZE(sm7280_reg_preset), + .bw_tbl_enc = sc7280_bw_table_enc, + .bw_tbl_enc_size = ARRAY_SIZE(sc7280_bw_table_enc), + .bw_tbl_dec = sc7280_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sc7280_bw_table_dec), + .clks = {"core", "bus", "iface"}, + .clks_num = 3, + .vcodec0_clks = {"vcodec_core", "vcodec_bus"}, + .vcodec_clks_num = 2, + .vcodec_pmdomains = { "venus", "vcodec0" }, + .vcodec_pmdomains_num = 2, + .opp_pmdomain = (const char *[]) { "cx", NULL }, + .vcodec_num = 1, + .hfi_version = HFI_VERSION_6XX, + .vmem_id = VIDC_RESOURCE_NONE, + .vmem_size = 0, + .vmem_addr = 0, + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/vpu-2.0/venus.mbn", +}; + static const struct of_device_id venus_dt_match[] = { { .compatible = "qcom,msm8916-venus", .data = &msm8916_res, }, { .compatible = "qcom,msm8996-venus", .data = &msm8996_res, }, { .compatible = "qcom,sdm845-venus", .data = &sdm845_res, }, { .compatible = "qcom,sdm845-venus-v2", .data = &sdm845_res_v2, }, { .compatible = "qcom,sc7180-venus", .data = &sc7180_res, }, + { .compatible = "qcom,sc7280-venus", .data = &sc7280_res, }, { .compatible = "qcom,sm8250-venus", .data = &sm8250_res, }, { } }; -- cgit v1.2.3 From 920173c7cfc0aa70787aeecf737cb93f11eedb6d Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Tue, 10 Aug 2021 11:47:51 +0200 Subject: media: venus: Add num_vpp_pipes to resource structure V6 HW can have vpp pipes as 1 or 4, add num_vpp_pipes to resource struture to differentiate. Signed-off-by: Dikshita Agarwal Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.c | 2 ++ drivers/media/platform/qcom/venus/core.h | 1 + drivers/media/platform/qcom/venus/helpers.c | 2 +- drivers/media/platform/qcom/venus/hfi_platform.c | 13 ------------- drivers/media/platform/qcom/venus/hfi_platform.h | 2 -- drivers/media/platform/qcom/venus/hfi_platform_v6.c | 6 ------ 6 files changed, 4 insertions(+), 22 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index e5af4d74e504..de7b32caa8b8 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -727,6 +727,7 @@ static const struct venus_resources sm8250_res = { .vcodec_num = 1, .max_load = 7833600, .hfi_version = HFI_VERSION_6XX, + .num_vpp_pipes = 4, .vmem_id = VIDC_RESOURCE_NONE, .vmem_size = 0, .vmem_addr = 0, @@ -778,6 +779,7 @@ static const struct venus_resources sc7280_res = { .opp_pmdomain = (const char *[]) { "cx", NULL }, .vcodec_num = 1, .hfi_version = HFI_VERSION_6XX, + .num_vpp_pipes = 1, .vmem_id = VIDC_RESOURCE_NONE, .vmem_size = 0, .vmem_addr = 0, diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 5ec851115eca..62228cc6b032 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -68,6 +68,7 @@ struct venus_resources { const char * const resets[VIDC_RESETS_NUM_MAX]; unsigned int resets_num; enum hfi_version hfi_version; + u8 num_vpp_pipes; u32 max_load; unsigned int vmem_id; u32 vmem_size; diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 8012f5c7bf34..1f46a6f4456a 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -583,7 +583,7 @@ static int platform_get_bufreq(struct venus_inst *inst, u32 buftype, return -EINVAL; params.version = version; - params.num_vpp_pipes = hfi_platform_num_vpp_pipes(version); + params.num_vpp_pipes = inst->core->res->num_vpp_pipes; if (is_dec) { params.width = inst->width; diff --git a/drivers/media/platform/qcom/venus/hfi_platform.c b/drivers/media/platform/qcom/venus/hfi_platform.c index f5b4e1f4764f..f16f8962273c 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform.c +++ b/drivers/media/platform/qcom/venus/hfi_platform.c @@ -66,16 +66,3 @@ hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec, u32 session_ return freq; } -u8 hfi_platform_num_vpp_pipes(enum hfi_version version) -{ - const struct hfi_platform *plat; - - plat = hfi_platform_get(version); - if (!plat) - return 0; - - if (plat->num_vpp_pipes) - return plat->num_vpp_pipes(); - - return 0; -} diff --git a/drivers/media/platform/qcom/venus/hfi_platform.h b/drivers/media/platform/qcom/venus/hfi_platform.h index 2dbe608c53af..1dcf4085928c 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform.h +++ b/drivers/media/platform/qcom/venus/hfi_platform.h @@ -52,7 +52,6 @@ struct hfi_platform { unsigned long (*codec_lp_freq)(u32 session_type, u32 codec); void (*codecs)(u32 *enc_codecs, u32 *dec_codecs, u32 *count); const struct hfi_plat_caps *(*capabilities)(unsigned int *entries); - u8 (*num_vpp_pipes)(void); int (*bufreq)(struct hfi_plat_buffers_params *params, u32 session_type, u32 buftype, struct hfi_buffer_requirements *bufreq); }; @@ -67,5 +66,4 @@ unsigned long hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 code u32 session_type); unsigned long hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec, u32 session_type); -u8 hfi_platform_num_vpp_pipes(enum hfi_version version); #endif diff --git a/drivers/media/platform/qcom/venus/hfi_platform_v6.c b/drivers/media/platform/qcom/venus/hfi_platform_v6.c index d8243b22568a..c10618e44f5d 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform_v6.c +++ b/drivers/media/platform/qcom/venus/hfi_platform_v6.c @@ -322,17 +322,11 @@ static unsigned long codec_lp_freq(u32 session_type, u32 codec) return 0; } -static u8 num_vpp_pipes(void) -{ - return 4; -} - const struct hfi_platform hfi_plat_v6 = { .codec_vpp_freq = codec_vpp_freq, .codec_vsp_freq = codec_vsp_freq, .codec_lp_freq = codec_lp_freq, .codecs = get_codecs, .capabilities = get_capabilities, - .num_vpp_pipes = num_vpp_pipes, .bufreq = hfi_plat_bufreq_v6, }; -- cgit v1.2.3 From 78d434ba86599fa0599295c9e73d245c44733557 Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Tue, 10 Aug 2021 11:47:52 +0200 Subject: media: venus: hfi: Skip AON register programming for V6 1pipe AON register programming is used to set NOC to low power mode during V6 power off sequence. However AON register memory map is not applicable to 1pipe, hence skipping AON register programming. Co-developed-by: Mansur Alisha Shaik Signed-off-by: Mansur Alisha Shaik Co-developed-by: Vikash Garodia Signed-off-by: Vikash Garodia Signed-off-by: Dikshita Agarwal Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/hfi_venus.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index ce98c523b3c6..3a75a27632fb 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -551,6 +551,9 @@ static int venus_halt_axi(struct venus_hfi_device *hdev) if (IS_V6(hdev->core)) { writel(0x3, cpu_cs_base + CPU_CS_X2RPMH_V6); + if (hdev->core->res->num_vpp_pipes == 1) + goto skip_aon_mvp_noc; + writel(0x1, aon_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); ret = readl_poll_timeout(aon_base + AON_WRAPPER_MVP_NOC_LPI_STATUS, val, @@ -560,6 +563,7 @@ static int venus_halt_axi(struct venus_hfi_device *hdev) if (ret) return -ETIMEDOUT; +skip_aon_mvp_noc: mask_val = (BIT(2) | BIT(1) | BIT(0)); writel(mask_val, wrapper_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_V6); -- cgit v1.2.3 From 6483a8cbea54854dfa8fa0e9c9673e564bc0b971 Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Tue, 10 Aug 2021 11:47:53 +0200 Subject: media: venus: vdec: set work route to fw Set work route to FW based on num of vpp pipes. Signed-off-by: Dikshita Agarwal Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/hfi_cmds.c | 7 +++++++ drivers/media/platform/qcom/venus/hfi_helper.h | 5 +++++ drivers/media/platform/qcom/venus/vdec.c | 17 +++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c index 60f4b8e4b8d0..5aea07307e02 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.c +++ b/drivers/media/platform/qcom/venus/hfi_cmds.c @@ -1299,6 +1299,13 @@ pkt_session_set_property_6xx(struct hfi_session_set_property_pkt *pkt, pkt->shdr.hdr.size += sizeof(u32) + sizeof(*cq); break; } + case HFI_PROPERTY_PARAM_WORK_ROUTE: { + struct hfi_video_work_route *in = pdata, *wr = prop_data; + + wr->video_work_route = in->video_work_route; + pkt->shdr.hdr.size += sizeof(u32) + sizeof(*wr); + break; + } default: return pkt_session_set_property_4xx(pkt, cookie, ptype, pdata); } diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index bec4feb63ceb..253911272b4c 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -448,6 +448,7 @@ #define HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT 0x100f #define HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED 0x1010 #define HFI_PROPERTY_PARAM_WORK_MODE 0x1015 +#define HFI_PROPERTY_PARAM_WORK_ROUTE 0x1017 /* * HFI_PROPERTY_CONFIG_COMMON_START @@ -873,6 +874,10 @@ struct hfi_video_work_mode { u32 video_work_mode; }; +struct hfi_video_work_route { + u32 video_work_route; +}; + struct hfi_h264_vui_timing_info { u32 enable; u32 fixed_framerate; diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index c129b061a325..88cd9e46c333 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -656,6 +656,19 @@ static int vdec_set_properties(struct venus_inst *inst) return 0; } +static int vdec_set_work_route(struct venus_inst *inst) +{ + u32 ptype = HFI_PROPERTY_PARAM_WORK_ROUTE; + struct hfi_video_work_route wr; + + if (!IS_V6(inst->core)) + return 0; + + wr.video_work_route = inst->core->res->num_vpp_pipes; + + return hfi_session_set_property(inst, ptype, &wr); +} + #define is_ubwc_fmt(fmt) (!!((fmt) & HFI_COLOR_FORMAT_UBWC_BASE)) static int vdec_output_conf(struct venus_inst *inst) @@ -1042,6 +1055,10 @@ static int vdec_start_output(struct venus_inst *inst) if (ret) return ret; + ret = vdec_set_work_route(inst); + if (ret) + return ret; + ret = vdec_output_conf(inst); if (ret) return ret; -- cgit v1.2.3 From fa622c3df44190ec52f7c77f9c24f7b4685203d5 Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Tue, 10 Aug 2021 11:47:54 +0200 Subject: media: venus: helpers: update NUM_MBS macro calculation Consider alignment while calculating NUM_MBS. Co-developed-by: Mansur Alisha Shaik Signed-off-by: Mansur Alisha Shaik Signed-off-by: Dikshita Agarwal Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/helpers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 1f46a6f4456a..196a24892176 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -18,8 +18,8 @@ #include "hfi_platform.h" #include "hfi_parser.h" -#define NUM_MBS_720P (((1280 + 15) >> 4) * ((720 + 15) >> 4)) -#define NUM_MBS_4K (((4096 + 15) >> 4) * ((2304 + 15) >> 4)) +#define NUM_MBS_720P (((ALIGN(1280, 16)) >> 4) * ((ALIGN(736, 16)) >> 4)) +#define NUM_MBS_4K (((ALIGN(4096, 16)) >> 4) * ((ALIGN(2304, 16)) >> 4)) struct intbuf { struct list_head list; -- cgit v1.2.3 From 16545aa3dee5a01f3f42aa566a051096c87f4b6f Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Tue, 10 Aug 2021 11:47:55 +0200 Subject: media: venus: Set buffer to FW based on FW min count requirement. - Get the min buffer count required by FW from source event change and use the same value to decide actual buffer count and for buffer size calculation. - Setup DPB and OPB buffers after session continue incase of reconfig. Signed-off-by: Dikshita Agarwal Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.h | 1 + drivers/media/platform/qcom/venus/helpers.c | 8 +++++++- drivers/media/platform/qcom/venus/hfi_helper.h | 9 +++++++++ drivers/media/platform/qcom/venus/hfi_msgs.c | 7 +++++++ drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c | 6 ++++-- drivers/media/platform/qcom/venus/vdec.c | 20 +++++++++++++------- 6 files changed, 41 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 62228cc6b032..a3f077f64be0 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -409,6 +409,7 @@ struct venus_inst { u32 width; u32 height; struct v4l2_rect crop; + u32 fw_min_cnt; u32 out_width; u32 out_height; u32 colorspace; diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 196a24892176..7f2f5b91caaa 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -623,9 +623,15 @@ int venus_helper_get_bufreq(struct venus_inst *inst, u32 type, if (req) memset(req, 0, sizeof(*req)); + if (type == HFI_BUFFER_OUTPUT || type == HFI_BUFFER_OUTPUT2) + req->count_min = inst->fw_min_cnt; + ret = platform_get_bufreq(inst, type, req); - if (!ret) + if (!ret) { + if (type == HFI_BUFFER_OUTPUT || type == HFI_BUFFER_OUTPUT2) + inst->fw_min_cnt = req->count_min; return 0; + } ret = hfi_session_get_property(inst, ptype, &hprop); if (ret) diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index 253911272b4c..2daa88e3df9f 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -167,6 +167,7 @@ #define HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA 0x120300c #define HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE 0x120300d #define HFI_PROPERTY_PARAM_VDEC_FRAME_ASSEMBLY 0x120300e +#define HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS 0x120300e #define HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA 0x1203011 #define HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA 0x1203012 #define HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA 0x1203013 @@ -915,6 +916,14 @@ struct hfi_extradata_input_crop { u32 height; }; +struct hfi_dpb_counts { + u32 max_dpb_count; + u32 max_ref_frames; + u32 max_dec_buffering; + u32 max_reorder_frames; + u32 fw_min_cnt; +}; + #define HFI_COLOR_FORMAT_MONOCHROME 0x01 #define HFI_COLOR_FORMAT_NV12 0x02 #define HFI_COLOR_FORMAT_NV21 0x03 diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index 9a2bdb002edc..df96db3761a7 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -32,6 +32,7 @@ static void event_seq_changed(struct venus_core *core, struct venus_inst *inst, struct hfi_colour_space *colour_info; struct hfi_buffer_requirements *bufreq; struct hfi_extradata_input_crop *crop; + struct hfi_dpb_counts *dpb_count; u8 *data_ptr; u32 ptype; @@ -110,6 +111,12 @@ static void event_seq_changed(struct venus_core *core, struct venus_inst *inst, event.input_crop.height = crop->height; data_ptr += sizeof(*crop); break; + case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS: + data_ptr += sizeof(u32); + dpb_count = (struct hfi_dpb_counts *)data_ptr; + event.buf_count = dpb_count->fw_min_cnt; + data_ptr += sizeof(*dpb_count); + break; default: break; } diff --git a/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c b/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c index 479178b0600d..ea25c451222b 100644 --- a/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c +++ b/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c @@ -1164,7 +1164,7 @@ static int output_buffer_count(u32 session_type, u32 codec) output_min_count = 6; break; case V4L2_PIX_FMT_VP9: - output_min_count = 9; + output_min_count = 11; break; case V4L2_PIX_FMT_H264: case V4L2_PIX_FMT_HEVC: @@ -1213,6 +1213,8 @@ static int bufreq_dec(struct hfi_plat_buffers_params *params, u32 buftype, } out_min_count = output_buffer_count(VIDC_SESSION_TYPE_DEC, codec); + /* Max of driver and FW count */ + out_min_count = max(out_min_count, bufreq->count_min); bufreq->type = buftype; bufreq->region_size = 0; @@ -1237,7 +1239,7 @@ static int bufreq_dec(struct hfi_plat_buffers_params *params, u32 buftype, } else if (buftype == HFI_BUFFER_INTERNAL_SCRATCH(version)) { bufreq->size = dec_ops->scratch(width, height, is_interlaced); } else if (buftype == HFI_BUFFER_INTERNAL_SCRATCH_1(version)) { - bufreq->size = dec_ops->scratch1(width, height, out_min_count, + bufreq->size = dec_ops->scratch1(width, height, VB2_MAX_FRAME, is_secondary_output, num_vpp_pipes); } else if (buftype == HFI_BUFFER_INTERNAL_PERSIST_1) { diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 88cd9e46c333..41c5a353fcae 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -986,23 +986,23 @@ reconfigure: if (ret) goto err; + venus_pm_load_scale(inst); + + inst->next_buf_last = false; + ret = venus_helper_alloc_dpb_bufs(inst); if (ret) goto err; - ret = venus_helper_queue_dpb_bufs(inst); + ret = hfi_session_continue(inst); if (ret) goto free_dpb_bufs; - ret = venus_helper_process_initial_cap_bufs(inst); + ret = venus_helper_queue_dpb_bufs(inst); if (ret) goto free_dpb_bufs; - venus_pm_load_scale(inst); - - inst->next_buf_last = false; - - ret = hfi_session_continue(inst); + ret = venus_helper_process_initial_cap_bufs(inst); if (ret) goto free_dpb_bufs; @@ -1409,6 +1409,11 @@ static void vdec_event_change(struct venus_inst *inst, inst->crop.height = ev_data->height; } + inst->fw_min_cnt = ev_data->buf_count; + /* overwriting this to 11 for vp9 due to fw bug */ + if (inst->hfi_codec == HFI_VIDEO_CODEC_VP9) + inst->fw_min_cnt = 11; + inst->out_width = ev_data->width; inst->out_height = ev_data->height; @@ -1512,6 +1517,7 @@ static void vdec_inst_init(struct venus_inst *inst) inst->crop.top = 0; inst->crop.width = inst->width; inst->crop.height = inst->height; + inst->fw_min_cnt = 8; inst->out_width = frame_width_min(inst); inst->out_height = frame_height_min(inst); inst->fps = 30; -- cgit v1.2.3 From 485aa3df0dffa62d347ea4e0116f549338accc59 Mon Sep 17 00:00:00 2001 From: Fabian Wüthrich Date: Mon, 12 Jul 2021 11:03:26 +0200 Subject: media: ipu3-cio2: Parse sensor orientation and rotation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sensor orientation is read from the _PLC ACPI buffer and converted to a v4l2 format. The sensor rotation is read from the SSDB ACPI buffer and converted into degrees. Signed-off-by: Fabian Wüthrich Reviewed-by: Daniel Scally Reviewed-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/cio2-bridge.c | 60 ++++++++++++++++++++++++++++-- drivers/media/pci/intel/ipu3/cio2-bridge.h | 9 ++++- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c index 30d29b96a339..67c467d3c81f 100644 --- a/drivers/media/pci/intel/ipu3/cio2-bridge.c +++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c @@ -29,6 +29,7 @@ static const struct cio2_sensor_config cio2_supported_sensors[] = { static const struct cio2_property_names prop_names = { .clock_frequency = "clock-frequency", .rotation = "rotation", + .orientation = "orientation", .bus_type = "bus-type", .data_lanes = "data-lanes", .remote_endpoint = "remote-endpoint", @@ -72,11 +73,51 @@ out_free_buff: return ret; } +static u32 cio2_bridge_parse_rotation(struct cio2_sensor *sensor) +{ + switch (sensor->ssdb.degree) { + case CIO2_SENSOR_ROTATION_NORMAL: + return 0; + case CIO2_SENSOR_ROTATION_INVERTED: + return 180; + default: + dev_warn(&sensor->adev->dev, + "Unknown rotation %d. Assume 0 degree rotation\n", + sensor->ssdb.degree); + return 0; + } +} + +static enum v4l2_fwnode_orientation cio2_bridge_parse_orientation(struct cio2_sensor *sensor) +{ + switch (sensor->pld->panel) { + case ACPI_PLD_PANEL_FRONT: + return V4L2_FWNODE_ORIENTATION_FRONT; + case ACPI_PLD_PANEL_BACK: + return V4L2_FWNODE_ORIENTATION_BACK; + case ACPI_PLD_PANEL_TOP: + case ACPI_PLD_PANEL_LEFT: + case ACPI_PLD_PANEL_RIGHT: + case ACPI_PLD_PANEL_UNKNOWN: + return V4L2_FWNODE_ORIENTATION_EXTERNAL; + default: + dev_warn(&sensor->adev->dev, "Unknown _PLD panel value %d\n", + sensor->pld->panel); + return V4L2_FWNODE_ORIENTATION_EXTERNAL; + } +} + static void cio2_bridge_create_fwnode_properties( struct cio2_sensor *sensor, struct cio2_bridge *bridge, const struct cio2_sensor_config *cfg) { + u32 rotation; + enum v4l2_fwnode_orientation orientation; + + rotation = cio2_bridge_parse_rotation(sensor); + orientation = cio2_bridge_parse_orientation(sensor); + sensor->prop_names = prop_names; sensor->local_ref[0] = SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_CIO2_ENDPOINT]); @@ -85,9 +126,12 @@ static void cio2_bridge_create_fwnode_properties( sensor->dev_properties[0] = PROPERTY_ENTRY_U32( sensor->prop_names.clock_frequency, sensor->ssdb.mclkspeed); - sensor->dev_properties[1] = PROPERTY_ENTRY_U8( + sensor->dev_properties[1] = PROPERTY_ENTRY_U32( sensor->prop_names.rotation, - sensor->ssdb.degree); + rotation); + sensor->dev_properties[2] = PROPERTY_ENTRY_U32( + sensor->prop_names.orientation, + orientation); sensor->ep_properties[0] = PROPERTY_ENTRY_U32( sensor->prop_names.bus_type, @@ -159,6 +203,7 @@ static void cio2_bridge_unregister_sensors(struct cio2_bridge *bridge) for (i = 0; i < bridge->n_sensors; i++) { sensor = &bridge->sensors[i]; software_node_unregister_nodes(sensor->swnodes); + ACPI_FREE(sensor->pld); acpi_dev_put(sensor->adev); } } @@ -170,6 +215,7 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg, struct fwnode_handle *fwnode; struct cio2_sensor *sensor; struct acpi_device *adev; + acpi_status status; int ret; for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) { @@ -191,11 +237,15 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg, if (ret) goto err_put_adev; + status = acpi_get_physical_device_location(adev->handle, &sensor->pld); + if (ACPI_FAILURE(status)) + goto err_put_adev; + if (sensor->ssdb.lanes > CIO2_MAX_LANES) { dev_err(&adev->dev, "Number of lanes in SSDB is invalid\n"); ret = -EINVAL; - goto err_put_adev; + goto err_free_pld; } cio2_bridge_create_fwnode_properties(sensor, bridge, cfg); @@ -203,7 +253,7 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg, ret = software_node_register_nodes(sensor->swnodes); if (ret) - goto err_put_adev; + goto err_free_pld; fwnode = software_node_fwnode(&sensor->swnodes[ SWNODE_SENSOR_HID]); @@ -225,6 +275,8 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg, err_free_swnodes: software_node_unregister_nodes(sensor->swnodes); +err_free_pld: + ACPI_FREE(sensor->pld); err_put_adev: acpi_dev_put(adev); return ret; diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.h b/drivers/media/pci/intel/ipu3/cio2-bridge.h index dd0ffcafa489..202c7d494f7a 100644 --- a/drivers/media/pci/intel/ipu3/cio2-bridge.h +++ b/drivers/media/pci/intel/ipu3/cio2-bridge.h @@ -12,6 +12,10 @@ #define CIO2_MAX_LANES 4 #define MAX_NUM_LINK_FREQS 3 +/* Values are educated guesses as we don't have a spec */ +#define CIO2_SENSOR_ROTATION_NORMAL 0 +#define CIO2_SENSOR_ROTATION_INVERTED 1 + #define CIO2_SENSOR_CONFIG(_HID, _NR, ...) \ (const struct cio2_sensor_config) { \ .hid = _HID, \ @@ -80,6 +84,7 @@ struct cio2_sensor_ssdb { struct cio2_property_names { char clock_frequency[16]; char rotation[9]; + char orientation[12]; char bus_type[9]; char data_lanes[11]; char remote_endpoint[16]; @@ -106,9 +111,11 @@ struct cio2_sensor { struct cio2_node_names node_names; struct cio2_sensor_ssdb ssdb; + struct acpi_pld_info *pld; + struct cio2_property_names prop_names; struct property_entry ep_properties[5]; - struct property_entry dev_properties[3]; + struct property_entry dev_properties[4]; struct property_entry cio2_properties[3]; struct software_node_ref_args local_ref[1]; struct software_node_ref_args remote_ref[1]; -- cgit v1.2.3 From 203492ce398cbaaa6e772dfb71f140ab2e05cda1 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 6 Sep 2021 12:28:34 +0200 Subject: media: dt-bindings: vendor-prefixes: Add SK Hynix Inc. SK Hynix built the already supported hi556 sensor (and probably much more). For more information, see https://www.skhynix.com/ Signed-off-by: Martin Kepplinger Acked-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index a867f7102c35..952553759ac4 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -509,6 +509,8 @@ patternProperties: description: Hycon Technology Corp. "^hydis,.*": description: Hydis Technologies + "^hynix,.*": + description: SK Hynix Inc. "^hyundai,.*": description: Hyundai Technology "^i2se,.*": -- cgit v1.2.3 From f3ce7200ca18094ca7c05c160637e2e2b30e17dd Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 6 Sep 2021 12:28:35 +0200 Subject: media: dt-bindings: media: document SK Hynix Hi-846 MIPI CSI-2 8M pixel sensor Document the bindings used for the SK Hynix Hi-846 CMOS camera driver. Signed-off-by: Martin Kepplinger Reviewed-by: Laurent Pinchart Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/hynix,hi846.yaml | 120 +++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml b/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml new file mode 100644 index 000000000000..85a8877c2f38 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml @@ -0,0 +1,120 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/hynix,hi846.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SK Hynix Hi-846 1/4" 8M Pixel MIPI CSI-2 sensor + +maintainers: + - Martin Kepplinger + +description: |- + The Hi-846 is a raw image sensor with an MIPI CSI-2 image data + interface and CCI (I2C compatible) control bus. The output format + is raw Bayer. + +properties: + compatible: + const: hynix,hi846 + + reg: + maxItems: 1 + + clocks: + items: + - description: Reference to the mclk clock. + + assigned-clocks: + maxItems: 1 + + assigned-clock-rates: + maxItems: 1 + + reset-gpios: + description: Reference to the GPIO connected to the RESETB pin. Active low. + maxItems: 1 + + shutdown-gpios: + description: Reference to the GPIO connected to the XSHUTDOWN pin. Active low. + maxItems: 1 + + vddio-supply: + description: Definition of the regulator used for the VDDIO power supply. + + vdda-supply: + description: Definition of the regulator used for the VDDA power supply. + + vddd-supply: + description: Definition of the regulator used for the VDDD power supply. + + port: + $ref: /schemas/graph.yaml#/properties/port + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + oneOf: + - items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + - items: + - const: 1 + - const: 2 + + required: + - data-lanes + +required: + - compatible + - reg + - clocks + - assigned-clocks + - assigned-clock-rates + - vddio-supply + - vdda-supply + - vddd-supply + - port + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hi846: camera@20 { + compatible = "hynix,hi846"; + reg = <0x20>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_csi1>; + clocks = <&clk 0>; + assigned-clocks = <&clk 0>; + assigned-clock-rates = <25000000>; + vdda-supply = <®_camera_vdda>; + vddd-supply = <®_camera_vddd>; + vddio-supply = <®_camera_vddio>; + reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>; + shutdown-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>; + + port { + camera_out: endpoint { + remote-endpoint = <&csi1_ep1>; + link-frequencies = /bits/ 64 + <80000000 200000000>; + data-lanes = <1 2>; + }; + }; + }; + }; + +... -- cgit v1.2.3 From e8c0882685f9152f0d729664a12bcbe749cb7736 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 6 Sep 2021 12:28:36 +0200 Subject: media: i2c: add driver for the SK Hynix Hi-846 8M pixel camera The SK Hynix Hi-846 is a 1/4" 8M Pixel CMOS Image Sensor. It supports usual features like I2C control, CSI-2 for frame data, digital/analog gain control or test patterns. This driver supports the 640x480, 1280x720 and 1632x1224 resolution modes. It supports runtime PM in order not to draw any unnecessary power. The part is also called YACG4D0C9SHC and a datasheet can be found at https://product.skhynix.com/products/cis/cis.go The large sets of partly undocumented register values are for example found when searching for the hi846_mipi_raw_Sensor.c Android driver. Signed-off-by: Martin Kepplinger Reviewed-by: Pavel Machek Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 6 + drivers/media/i2c/Kconfig | 13 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/hi846.c | 2190 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 2210 insertions(+) create mode 100644 drivers/media/i2c/hi846.c diff --git a/MAINTAINERS b/MAINTAINERS index ee91c5472bc1..60deb26c740f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8661,6 +8661,12 @@ S: Maintained T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/hi556.c +HYNIX HI846 SENSOR DRIVER +M: Martin Kepplinger +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/i2c/hi846.c + Hyper-V/Azure CORE AND DRIVERS M: "K. Y. Srinivasan" M: Haiyang Zhang diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index adb348aa8396..0e56489c97fb 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -743,6 +743,19 @@ config VIDEO_HI556 To compile this driver as a module, choose M here: the module will be called hi556. +config VIDEO_HI846 + tristate "Hynix Hi-846 sensor support" + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the Hynix + Hi-846 camera. + + To compile this driver as a module, choose M here: the + module will be called hi846. + config VIDEO_IMX208 tristate "Sony IMX208 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 5ac8d639e5ca..4d4fe08d7a6a 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -118,6 +118,7 @@ obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o obj-$(CONFIG_VIDEO_OV2659) += ov2659.o obj-$(CONFIG_VIDEO_TC358743) += tc358743.o obj-$(CONFIG_VIDEO_HI556) += hi556.o +obj-$(CONFIG_VIDEO_HI846) += hi846.o obj-$(CONFIG_VIDEO_IMX208) += imx208.o obj-$(CONFIG_VIDEO_IMX214) += imx214.o obj-$(CONFIG_VIDEO_IMX219) += imx219.o diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c new file mode 100644 index 000000000000..822ce3021fde --- /dev/null +++ b/drivers/media/i2c/hi846.c @@ -0,0 +1,2190 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2021 Purism SPC + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HI846_MEDIA_BUS_FORMAT MEDIA_BUS_FMT_SGBRG10_1X10 +#define HI846_RGB_DEPTH 10 + +/* Frame length lines / vertical timings */ +#define HI846_REG_FLL 0x0006 +#define HI846_FLL_MAX 0xffff + +/* Horizontal timing */ +#define HI846_REG_LLP 0x0008 +#define HI846_LINE_LENGTH 3800 + +#define HI846_REG_BINNING_MODE 0x000c + +#define HI846_REG_IMAGE_ORIENTATION 0x000e + +#define HI846_REG_UNKNOWN_0022 0x0022 + +#define HI846_REG_Y_ADDR_START_VACT_H 0x0026 +#define HI846_REG_Y_ADDR_START_VACT_L 0x0027 +#define HI846_REG_UNKNOWN_0028 0x0028 + +#define HI846_REG_Y_ADDR_END_VACT_H 0x002c +#define HI846_REG_Y_ADDR_END_VACT_L 0x002d + +#define HI846_REG_Y_ODD_INC_FOBP 0x002e +#define HI846_REG_Y_EVEN_INC_FOBP 0x002f + +#define HI846_REG_Y_ODD_INC_VACT 0x0032 +#define HI846_REG_Y_EVEN_INC_VACT 0x0033 + +#define HI846_REG_GROUPED_PARA_HOLD 0x0046 + +#define HI846_REG_TG_ENABLE 0x004c + +#define HI846_REG_UNKNOWN_005C 0x005c + +#define HI846_REG_UNKNOWN_006A 0x006a + +/* + * Long exposure time. Actually, exposure is a 20 bit value that + * includes the lower 4 bits of 0x0073 too. Only 16 bits are used + * right now + */ +#define HI846_REG_EXPOSURE 0x0074 +#define HI846_EXPOSURE_MIN 6 +#define HI846_EXPOSURE_MAX_MARGIN 2 +#define HI846_EXPOSURE_STEP 1 + +/* Analog gain controls from sensor */ +#define HI846_REG_ANALOG_GAIN 0x0077 +#define HI846_ANAL_GAIN_MIN 0 +#define HI846_ANAL_GAIN_MAX 240 +#define HI846_ANAL_GAIN_STEP 8 + +/* Digital gain controls from sensor */ +#define HI846_REG_MWB_GR_GAIN_H 0x0078 +#define HI846_REG_MWB_GR_GAIN_L 0x0079 +#define HI846_REG_MWB_GB_GAIN_H 0x007a +#define HI846_REG_MWB_GB_GAIN_L 0x007b +#define HI846_REG_MWB_R_GAIN_H 0x007c +#define HI846_REG_MWB_R_GAIN_L 0x007d +#define HI846_REG_MWB_B_GAIN_H 0x007e +#define HI846_REG_MWB_B_GAIN_L 0x007f +#define HI846_DGTL_GAIN_MIN 512 +#define HI846_DGTL_GAIN_MAX 8191 +#define HI846_DGTL_GAIN_STEP 1 +#define HI846_DGTL_GAIN_DEFAULT 512 + +#define HI846_REG_X_ADDR_START_HACT_H 0x0120 +#define HI846_REG_X_ADDR_END_HACT_H 0x0122 + +#define HI846_REG_UNKNOWN_012A 0x012a + +#define HI846_REG_UNKNOWN_0200 0x0200 + +#define HI846_REG_UNKNOWN_021C 0x021c +#define HI846_REG_UNKNOWN_021E 0x021e + +#define HI846_REG_UNKNOWN_0402 0x0402 +#define HI846_REG_UNKNOWN_0404 0x0404 +#define HI846_REG_UNKNOWN_0408 0x0408 +#define HI846_REG_UNKNOWN_0410 0x0410 +#define HI846_REG_UNKNOWN_0412 0x0412 +#define HI846_REG_UNKNOWN_0414 0x0414 + +#define HI846_REG_UNKNOWN_0418 0x0418 + +#define HI846_REG_UNKNOWN_051E 0x051e + +/* Formatter */ +#define HI846_REG_X_START_H 0x0804 +#define HI846_REG_X_START_L 0x0805 + +/* MIPI */ +#define HI846_REG_UNKNOWN_0900 0x0900 +#define HI846_REG_MIPI_TX_OP_EN 0x0901 +#define HI846_REG_MIPI_TX_OP_MODE 0x0902 +#define HI846_RAW8 BIT(5) + +#define HI846_REG_UNKNOWN_090C 0x090c +#define HI846_REG_UNKNOWN_090E 0x090e + +#define HI846_REG_UNKNOWN_0914 0x0914 +#define HI846_REG_TLPX 0x0915 +#define HI846_REG_TCLK_PREPARE 0x0916 +#define HI846_REG_TCLK_ZERO 0x0917 +#define HI846_REG_UNKNOWN_0918 0x0918 +#define HI846_REG_THS_PREPARE 0x0919 +#define HI846_REG_THS_ZERO 0x091a +#define HI846_REG_THS_TRAIL 0x091b +#define HI846_REG_TCLK_POST 0x091c +#define HI846_REG_TCLK_TRAIL_MIN 0x091d +#define HI846_REG_UNKNOWN_091E 0x091e + +#define HI846_REG_UNKNOWN_0954 0x0954 +#define HI846_REG_UNKNOWN_0956 0x0956 +#define HI846_REG_UNKNOWN_0958 0x0958 +#define HI846_REG_UNKNOWN_095A 0x095a + +/* ISP Common */ +#define HI846_REG_MODE_SELECT 0x0a00 +#define HI846_MODE_STANDBY 0x00 +#define HI846_MODE_STREAMING 0x01 +#define HI846_REG_FAST_STANDBY_MODE 0x0a02 +#define HI846_REG_ISP_EN_H 0x0a04 + +/* Test Pattern Control */ +#define HI846_REG_ISP 0x0a05 +#define HI846_REG_ISP_TPG_EN 0x01 +#define HI846_REG_TEST_PATTERN 0x020a /* 1-9 */ + +#define HI846_REG_UNKNOWN_0A0C 0x0a0c + +/* Windowing */ +#define HI846_REG_X_OUTPUT_SIZE_H 0x0a12 +#define HI846_REG_X_OUTPUT_SIZE_L 0x0a13 +#define HI846_REG_Y_OUTPUT_SIZE_H 0x0a14 +#define HI846_REG_Y_OUTPUT_SIZE_L 0x0a15 + +/* ISP Common */ +#define HI846_REG_PEDESTAL_EN 0x0a1a + +#define HI846_REG_UNKNOWN_0A1E 0x0a1e + +/* Horizontal Binning Mode */ +#define HI846_REG_HBIN_MODE 0x0a22 + +#define HI846_REG_UNKNOWN_0A24 0x0a24 +#define HI846_REG_UNKNOWN_0B02 0x0b02 +#define HI846_REG_UNKNOWN_0B10 0x0b10 +#define HI846_REG_UNKNOWN_0B12 0x0b12 +#define HI846_REG_UNKNOWN_0B14 0x0b14 + +/* BLC (Black Level Calibration) */ +#define HI846_REG_BLC_CTL0 0x0c00 + +#define HI846_REG_UNKNOWN_0C06 0x0c06 +#define HI846_REG_UNKNOWN_0C10 0x0c10 +#define HI846_REG_UNKNOWN_0C12 0x0c12 +#define HI846_REG_UNKNOWN_0C14 0x0c14 +#define HI846_REG_UNKNOWN_0C16 0x0c16 + +#define HI846_REG_UNKNOWN_0E04 0x0e04 + +#define HI846_REG_CHIP_ID_L 0x0f16 +#define HI846_REG_CHIP_ID_H 0x0f17 +#define HI846_CHIP_ID_L 0x46 +#define HI846_CHIP_ID_H 0x08 + +#define HI846_REG_UNKNOWN_0F04 0x0f04 +#define HI846_REG_UNKNOWN_0F08 0x0f08 + +/* PLL */ +#define HI846_REG_PLL_CFG_MIPI2_H 0x0f2a +#define HI846_REG_PLL_CFG_MIPI2_L 0x0f2b + +#define HI846_REG_UNKNOWN_0F30 0x0f30 +#define HI846_REG_PLL_CFG_RAMP1_H 0x0f32 +#define HI846_REG_UNKNOWN_0F36 0x0f36 +#define HI846_REG_PLL_CFG_MIPI1_H 0x0f38 + +#define HI846_REG_UNKNOWN_2008 0x2008 +#define HI846_REG_UNKNOWN_326E 0x326e + +struct hi846_reg { + u16 address; + u16 val; +}; + +struct hi846_reg_list { + u32 num_of_regs; + const struct hi846_reg *regs; +}; + +struct hi846_mode { + /* Frame width in pixels */ + u32 width; + + /* Frame height in pixels */ + u32 height; + + /* Horizontal timing size */ + u32 llp; + + /* Link frequency needed for this resolution */ + u8 link_freq_index; + + u16 fps; + + /* Vertical timining size */ + u16 frame_len; + + const struct hi846_reg_list reg_list_config; + const struct hi846_reg_list reg_list_2lane; + const struct hi846_reg_list reg_list_4lane; + + /* Position inside of the 3264x2448 pixel array */ + struct v4l2_rect crop; +}; + +static const struct hi846_reg hi846_init_2lane[] = { + {HI846_REG_MODE_SELECT, 0x0000}, + /* regs below are unknown */ + {0x2000, 0x100a}, + {0x2002, 0x00ff}, + {0x2004, 0x0007}, + {0x2006, 0x3fff}, + {0x2008, 0x3fff}, + {0x200a, 0xc216}, + {0x200c, 0x1292}, + {0x200e, 0xc01a}, + {0x2010, 0x403d}, + {0x2012, 0x000e}, + {0x2014, 0x403e}, + {0x2016, 0x0b80}, + {0x2018, 0x403f}, + {0x201a, 0x82ae}, + {0x201c, 0x1292}, + {0x201e, 0xc00c}, + {0x2020, 0x4130}, + {0x2022, 0x43e2}, + {0x2024, 0x0180}, + {0x2026, 0x4130}, + {0x2028, 0x7400}, + {0x202a, 0x5000}, + {0x202c, 0x0253}, + {0x202e, 0x0ad1}, + {0x2030, 0x2360}, + {0x2032, 0x0009}, + {0x2034, 0x5020}, + {0x2036, 0x000b}, + {0x2038, 0x0002}, + {0x203a, 0x0044}, + {0x203c, 0x0016}, + {0x203e, 0x1792}, + {0x2040, 0x7002}, + {0x2042, 0x154f}, + {0x2044, 0x00d5}, + {0x2046, 0x000b}, + {0x2048, 0x0019}, + {0x204a, 0x1698}, + {0x204c, 0x000e}, + {0x204e, 0x099a}, + {0x2050, 0x0058}, + {0x2052, 0x7000}, + {0x2054, 0x1799}, + {0x2056, 0x0310}, + {0x2058, 0x03c3}, + {0x205a, 0x004c}, + {0x205c, 0x064a}, + {0x205e, 0x0001}, + {0x2060, 0x0007}, + {0x2062, 0x0bc7}, + {0x2064, 0x0055}, + {0x2066, 0x7000}, + {0x2068, 0x1550}, + {0x206a, 0x158a}, + {0x206c, 0x0004}, + {0x206e, 0x1488}, + {0x2070, 0x7010}, + {0x2072, 0x1508}, + {0x2074, 0x0004}, + {0x2076, 0x0016}, + {0x2078, 0x03d5}, + {0x207a, 0x0055}, + {0x207c, 0x08ca}, + {0x207e, 0x2019}, + {0x2080, 0x0007}, + {0x2082, 0x7057}, + {0x2084, 0x0fc7}, + {0x2086, 0x5041}, + {0x2088, 0x12c8}, + {0x208a, 0x5060}, + {0x208c, 0x5080}, + {0x208e, 0x2084}, + {0x2090, 0x12c8}, + {0x2092, 0x7800}, + {0x2094, 0x0802}, + {0x2096, 0x040f}, + {0x2098, 0x1007}, + {0x209a, 0x0803}, + {0x209c, 0x080b}, + {0x209e, 0x3803}, + {0x20a0, 0x0807}, + {0x20a2, 0x0404}, + {0x20a4, 0x0400}, + {0x20a6, 0xffff}, + {0x20a8, 0xf0b2}, + {0x20aa, 0xffef}, + {0x20ac, 0x0a84}, + {0x20ae, 0x1292}, + {0x20b0, 0xc02e}, + {0x20b2, 0x4130}, + {0x23fe, 0xc056}, + {0x3232, 0xfc0c}, + {0x3236, 0xfc22}, + {0x3248, 0xfca8}, + {0x326a, 0x8302}, + {0x326c, 0x830a}, + {0x326e, 0x0000}, + {0x32ca, 0xfc28}, + {0x32cc, 0xc3bc}, + {0x32ce, 0xc34c}, + {0x32d0, 0xc35a}, + {0x32d2, 0xc368}, + {0x32d4, 0xc376}, + {0x32d6, 0xc3c2}, + {0x32d8, 0xc3e6}, + {0x32da, 0x0003}, + {0x32dc, 0x0003}, + {0x32de, 0x00c7}, + {0x32e0, 0x0031}, + {0x32e2, 0x0031}, + {0x32e4, 0x0031}, + {0x32e6, 0xfc28}, + {0x32e8, 0xc3bc}, + {0x32ea, 0xc384}, + {0x32ec, 0xc392}, + {0x32ee, 0xc3a0}, + {0x32f0, 0xc3ae}, + {0x32f2, 0xc3c4}, + {0x32f4, 0xc3e6}, + {0x32f6, 0x0003}, + {0x32f8, 0x0003}, + {0x32fa, 0x00c7}, + {0x32fc, 0x0031}, + {0x32fe, 0x0031}, + {0x3300, 0x0031}, + {0x3302, 0x82ca}, + {0x3304, 0xc164}, + {0x3306, 0x82e6}, + {0x3308, 0xc19c}, + {0x330a, 0x001f}, + {0x330c, 0x001a}, + {0x330e, 0x0034}, + {0x3310, 0x0000}, + {0x3312, 0x0000}, + {0x3314, 0xfc94}, + {0x3316, 0xc3d8}, + /* regs above are unknown */ + {HI846_REG_MODE_SELECT, 0x0000}, + {HI846_REG_UNKNOWN_0E04, 0x0012}, + {HI846_REG_Y_ODD_INC_FOBP, 0x1111}, + {HI846_REG_Y_ODD_INC_VACT, 0x1111}, + {HI846_REG_UNKNOWN_0022, 0x0008}, + {HI846_REG_Y_ADDR_START_VACT_H, 0x0040}, + {HI846_REG_UNKNOWN_0028, 0x0017}, + {HI846_REG_Y_ADDR_END_VACT_H, 0x09cf}, + {HI846_REG_UNKNOWN_005C, 0x2101}, + {HI846_REG_FLL, 0x09de}, + {HI846_REG_LLP, 0x0ed8}, + {HI846_REG_IMAGE_ORIENTATION, 0x0100}, + {HI846_REG_BINNING_MODE, 0x0022}, + {HI846_REG_HBIN_MODE, 0x0000}, + {HI846_REG_UNKNOWN_0A24, 0x0000}, + {HI846_REG_X_START_H, 0x0000}, + {HI846_REG_X_OUTPUT_SIZE_H, 0x0cc0}, + {HI846_REG_Y_OUTPUT_SIZE_H, 0x0990}, + {HI846_REG_EXPOSURE, 0x09d8}, + {HI846_REG_ANALOG_GAIN, 0x0000}, + {HI846_REG_GROUPED_PARA_HOLD, 0x0000}, + {HI846_REG_UNKNOWN_051E, 0x0000}, + {HI846_REG_UNKNOWN_0200, 0x0400}, + {HI846_REG_PEDESTAL_EN, 0x0c00}, + {HI846_REG_UNKNOWN_0A0C, 0x0010}, + {HI846_REG_UNKNOWN_0A1E, 0x0ccf}, + {HI846_REG_UNKNOWN_0402, 0x0110}, + {HI846_REG_UNKNOWN_0404, 0x00f4}, + {HI846_REG_UNKNOWN_0408, 0x0000}, + {HI846_REG_UNKNOWN_0410, 0x008d}, + {HI846_REG_UNKNOWN_0412, 0x011a}, + {HI846_REG_UNKNOWN_0414, 0x864c}, + {HI846_REG_UNKNOWN_021C, 0x0003}, + {HI846_REG_UNKNOWN_021E, 0x0235}, + {HI846_REG_BLC_CTL0, 0x9150}, + {HI846_REG_UNKNOWN_0C06, 0x0021}, + {HI846_REG_UNKNOWN_0C10, 0x0040}, + {HI846_REG_UNKNOWN_0C12, 0x0040}, + {HI846_REG_UNKNOWN_0C14, 0x0040}, + {HI846_REG_UNKNOWN_0C16, 0x0040}, + {HI846_REG_FAST_STANDBY_MODE, 0x0100}, + {HI846_REG_ISP_EN_H, 0x014a}, + {HI846_REG_UNKNOWN_0418, 0x0000}, + {HI846_REG_UNKNOWN_012A, 0x03b4}, + {HI846_REG_X_ADDR_START_HACT_H, 0x0046}, + {HI846_REG_X_ADDR_END_HACT_H, 0x0376}, + {HI846_REG_UNKNOWN_0B02, 0xe04d}, + {HI846_REG_UNKNOWN_0B10, 0x6821}, + {HI846_REG_UNKNOWN_0B12, 0x0120}, + {HI846_REG_UNKNOWN_0B14, 0x0001}, + {HI846_REG_UNKNOWN_2008, 0x38fd}, + {HI846_REG_UNKNOWN_326E, 0x0000}, + {HI846_REG_UNKNOWN_0900, 0x0320}, + {HI846_REG_MIPI_TX_OP_MODE, 0xc31a}, + {HI846_REG_UNKNOWN_0914, 0xc109}, + {HI846_REG_TCLK_PREPARE, 0x061a}, + {HI846_REG_UNKNOWN_0918, 0x0306}, + {HI846_REG_THS_ZERO, 0x0b09}, + {HI846_REG_TCLK_POST, 0x0c07}, + {HI846_REG_UNKNOWN_091E, 0x0a00}, + {HI846_REG_UNKNOWN_090C, 0x042a}, + {HI846_REG_UNKNOWN_090E, 0x006b}, + {HI846_REG_UNKNOWN_0954, 0x0089}, + {HI846_REG_UNKNOWN_0956, 0x0000}, + {HI846_REG_UNKNOWN_0958, 0xca00}, + {HI846_REG_UNKNOWN_095A, 0x9240}, + {HI846_REG_UNKNOWN_0F08, 0x2f04}, + {HI846_REG_UNKNOWN_0F30, 0x001f}, + {HI846_REG_UNKNOWN_0F36, 0x001f}, + {HI846_REG_UNKNOWN_0F04, 0x3a00}, + {HI846_REG_PLL_CFG_RAMP1_H, 0x025a}, + {HI846_REG_PLL_CFG_MIPI1_H, 0x025a}, + {HI846_REG_PLL_CFG_MIPI2_H, 0x0024}, + {HI846_REG_UNKNOWN_006A, 0x0100}, + {HI846_REG_TG_ENABLE, 0x0100}, +}; + +static const struct hi846_reg hi846_init_4lane[] = { + {0x2000, 0x987a}, + {0x2002, 0x00ff}, + {0x2004, 0x0047}, + {0x2006, 0x3fff}, + {0x2008, 0x3fff}, + {0x200a, 0xc216}, + {0x200c, 0x1292}, + {0x200e, 0xc01a}, + {0x2010, 0x403d}, + {0x2012, 0x000e}, + {0x2014, 0x403e}, + {0x2016, 0x0b80}, + {0x2018, 0x403f}, + {0x201a, 0x82ae}, + {0x201c, 0x1292}, + {0x201e, 0xc00c}, + {0x2020, 0x4130}, + {0x2022, 0x43e2}, + {0x2024, 0x0180}, + {0x2026, 0x4130}, + {0x2028, 0x7400}, + {0x202a, 0x5000}, + {0x202c, 0x0253}, + {0x202e, 0x0ad1}, + {0x2030, 0x2360}, + {0x2032, 0x0009}, + {0x2034, 0x5020}, + {0x2036, 0x000b}, + {0x2038, 0x0002}, + {0x203a, 0x0044}, + {0x203c, 0x0016}, + {0x203e, 0x1792}, + {0x2040, 0x7002}, + {0x2042, 0x154f}, + {0x2044, 0x00d5}, + {0x2046, 0x000b}, + {0x2048, 0x0019}, + {0x204a, 0x1698}, + {0x204c, 0x000e}, + {0x204e, 0x099a}, + {0x2050, 0x0058}, + {0x2052, 0x7000}, + {0x2054, 0x1799}, + {0x2056, 0x0310}, + {0x2058, 0x03c3}, + {0x205a, 0x004c}, + {0x205c, 0x064a}, + {0x205e, 0x0001}, + {0x2060, 0x0007}, + {0x2062, 0x0bc7}, + {0x2064, 0x0055}, + {0x2066, 0x7000}, + {0x2068, 0x1550}, + {0x206a, 0x158a}, + {0x206c, 0x0004}, + {0x206e, 0x1488}, + {0x2070, 0x7010}, + {0x2072, 0x1508}, + {0x2074, 0x0004}, + {0x2076, 0x0016}, + {0x2078, 0x03d5}, + {0x207a, 0x0055}, + {0x207c, 0x08ca}, + {0x207e, 0x2019}, + {0x2080, 0x0007}, + {0x2082, 0x7057}, + {0x2084, 0x0fc7}, + {0x2086, 0x5041}, + {0x2088, 0x12c8}, + {0x208a, 0x5060}, + {0x208c, 0x5080}, + {0x208e, 0x2084}, + {0x2090, 0x12c8}, + {0x2092, 0x7800}, + {0x2094, 0x0802}, + {0x2096, 0x040f}, + {0x2098, 0x1007}, + {0x209a, 0x0803}, + {0x209c, 0x080b}, + {0x209e, 0x3803}, + {0x20a0, 0x0807}, + {0x20a2, 0x0404}, + {0x20a4, 0x0400}, + {0x20a6, 0xffff}, + {0x20a8, 0xf0b2}, + {0x20aa, 0xffef}, + {0x20ac, 0x0a84}, + {0x20ae, 0x1292}, + {0x20b0, 0xc02e}, + {0x20b2, 0x4130}, + {0x20b4, 0xf0b2}, + {0x20b6, 0xffbf}, + {0x20b8, 0x2004}, + {0x20ba, 0x403f}, + {0x20bc, 0x00c3}, + {0x20be, 0x4fe2}, + {0x20c0, 0x8318}, + {0x20c2, 0x43cf}, + {0x20c4, 0x0000}, + {0x20c6, 0x9382}, + {0x20c8, 0xc314}, + {0x20ca, 0x2003}, + {0x20cc, 0x12b0}, + {0x20ce, 0xcab0}, + {0x20d0, 0x4130}, + {0x20d2, 0x12b0}, + {0x20d4, 0xc90a}, + {0x20d6, 0x4130}, + {0x20d8, 0x42d2}, + {0x20da, 0x8318}, + {0x20dc, 0x00c3}, + {0x20de, 0x9382}, + {0x20e0, 0xc314}, + {0x20e2, 0x2009}, + {0x20e4, 0x120b}, + {0x20e6, 0x120a}, + {0x20e8, 0x1209}, + {0x20ea, 0x1208}, + {0x20ec, 0x1207}, + {0x20ee, 0x1206}, + {0x20f0, 0x4030}, + {0x20f2, 0xc15e}, + {0x20f4, 0x4130}, + {0x20f6, 0x1292}, + {0x20f8, 0xc008}, + {0x20fa, 0x4130}, + {0x20fc, 0x42d2}, + {0x20fe, 0x82a1}, + {0x2100, 0x00c2}, + {0x2102, 0x1292}, + {0x2104, 0xc040}, + {0x2106, 0x4130}, + {0x2108, 0x1292}, + {0x210a, 0xc006}, + {0x210c, 0x42a2}, + {0x210e, 0x7324}, + {0x2110, 0x9382}, + {0x2112, 0xc314}, + {0x2114, 0x2011}, + {0x2116, 0x425f}, + {0x2118, 0x82a1}, + {0x211a, 0xf25f}, + {0x211c, 0x00c1}, + {0x211e, 0xf35f}, + {0x2120, 0x2406}, + {0x2122, 0x425f}, + {0x2124, 0x00c0}, + {0x2126, 0xf37f}, + {0x2128, 0x522f}, + {0x212a, 0x4f82}, + {0x212c, 0x7324}, + {0x212e, 0x425f}, + {0x2130, 0x82d4}, + {0x2132, 0xf35f}, + {0x2134, 0x4fc2}, + {0x2136, 0x01b3}, + {0x2138, 0x93c2}, + {0x213a, 0x829f}, + {0x213c, 0x2421}, + {0x213e, 0x403e}, + {0x2140, 0xfffe}, + {0x2142, 0x40b2}, + {0x2144, 0xec78}, + {0x2146, 0x831c}, + {0x2148, 0x40b2}, + {0x214a, 0xec78}, + {0x214c, 0x831e}, + {0x214e, 0x40b2}, + {0x2150, 0xec78}, + {0x2152, 0x8320}, + {0x2154, 0xb3d2}, + {0x2156, 0x008c}, + {0x2158, 0x2405}, + {0x215a, 0x4e0f}, + {0x215c, 0x503f}, + {0x215e, 0xffd8}, + {0x2160, 0x4f82}, + {0x2162, 0x831c}, + {0x2164, 0x90f2}, + {0x2166, 0x0003}, + {0x2168, 0x008c}, + {0x216a, 0x2401}, + {0x216c, 0x4130}, + {0x216e, 0x421f}, + {0x2170, 0x831c}, + {0x2172, 0x5e0f}, + {0x2174, 0x4f82}, + {0x2176, 0x831e}, + {0x2178, 0x5e0f}, + {0x217a, 0x4f82}, + {0x217c, 0x8320}, + {0x217e, 0x3ff6}, + {0x2180, 0x432e}, + {0x2182, 0x3fdf}, + {0x2184, 0x421f}, + {0x2186, 0x7100}, + {0x2188, 0x4f0e}, + {0x218a, 0x503e}, + {0x218c, 0xffd8}, + {0x218e, 0x4e82}, + {0x2190, 0x7a04}, + {0x2192, 0x421e}, + {0x2194, 0x831c}, + {0x2196, 0x5f0e}, + {0x2198, 0x4e82}, + {0x219a, 0x7a06}, + {0x219c, 0x0b00}, + {0x219e, 0x7304}, + {0x21a0, 0x0050}, + {0x21a2, 0x40b2}, + {0x21a4, 0xd081}, + {0x21a6, 0x0b88}, + {0x21a8, 0x421e}, + {0x21aa, 0x831e}, + {0x21ac, 0x5f0e}, + {0x21ae, 0x4e82}, + {0x21b0, 0x7a0e}, + {0x21b2, 0x521f}, + {0x21b4, 0x8320}, + {0x21b6, 0x4f82}, + {0x21b8, 0x7a10}, + {0x21ba, 0x0b00}, + {0x21bc, 0x7304}, + {0x21be, 0x007a}, + {0x21c0, 0x40b2}, + {0x21c2, 0x0081}, + {0x21c4, 0x0b88}, + {0x21c6, 0x4392}, + {0x21c8, 0x7a0a}, + {0x21ca, 0x0800}, + {0x21cc, 0x7a0c}, + {0x21ce, 0x0b00}, + {0x21d0, 0x7304}, + {0x21d2, 0x022b}, + {0x21d4, 0x40b2}, + {0x21d6, 0xd081}, + {0x21d8, 0x0b88}, + {0x21da, 0x0b00}, + {0x21dc, 0x7304}, + {0x21de, 0x0255}, + {0x21e0, 0x40b2}, + {0x21e2, 0x0081}, + {0x21e4, 0x0b88}, + {0x21e6, 0x4130}, + {0x23fe, 0xc056}, + {0x3232, 0xfc0c}, + {0x3236, 0xfc22}, + {0x3238, 0xfcfc}, + {0x323a, 0xfd84}, + {0x323c, 0xfd08}, + {0x3246, 0xfcd8}, + {0x3248, 0xfca8}, + {0x324e, 0xfcb4}, + {0x326a, 0x8302}, + {0x326c, 0x830a}, + {0x326e, 0x0000}, + {0x32ca, 0xfc28}, + {0x32cc, 0xc3bc}, + {0x32ce, 0xc34c}, + {0x32d0, 0xc35a}, + {0x32d2, 0xc368}, + {0x32d4, 0xc376}, + {0x32d6, 0xc3c2}, + {0x32d8, 0xc3e6}, + {0x32da, 0x0003}, + {0x32dc, 0x0003}, + {0x32de, 0x00c7}, + {0x32e0, 0x0031}, + {0x32e2, 0x0031}, + {0x32e4, 0x0031}, + {0x32e6, 0xfc28}, + {0x32e8, 0xc3bc}, + {0x32ea, 0xc384}, + {0x32ec, 0xc392}, + {0x32ee, 0xc3a0}, + {0x32f0, 0xc3ae}, + {0x32f2, 0xc3c4}, + {0x32f4, 0xc3e6}, + {0x32f6, 0x0003}, + {0x32f8, 0x0003}, + {0x32fa, 0x00c7}, + {0x32fc, 0x0031}, + {0x32fe, 0x0031}, + {0x3300, 0x0031}, + {0x3302, 0x82ca}, + {0x3304, 0xc164}, + {0x3306, 0x82e6}, + {0x3308, 0xc19c}, + {0x330a, 0x001f}, + {0x330c, 0x001a}, + {0x330e, 0x0034}, + {0x3310, 0x0000}, + {0x3312, 0x0000}, + {0x3314, 0xfc94}, + {0x3316, 0xc3d8}, + + {0x0a00, 0x0000}, + {0x0e04, 0x0012}, + {0x002e, 0x1111}, + {0x0032, 0x1111}, + {0x0022, 0x0008}, + {0x0026, 0x0040}, + {0x0028, 0x0017}, + {0x002c, 0x09cf}, + {0x005c, 0x2101}, + {0x0006, 0x09de}, + {0x0008, 0x0ed8}, + {0x000e, 0x0100}, + {0x000c, 0x0022}, + {0x0a22, 0x0000}, + {0x0a24, 0x0000}, + {0x0804, 0x0000}, + {0x0a12, 0x0cc0}, + {0x0a14, 0x0990}, + {0x0074, 0x09d8}, + {0x0076, 0x0000}, + {0x051e, 0x0000}, + {0x0200, 0x0400}, + {0x0a1a, 0x0c00}, + {0x0a0c, 0x0010}, + {0x0a1e, 0x0ccf}, + {0x0402, 0x0110}, + {0x0404, 0x00f4}, + {0x0408, 0x0000}, + {0x0410, 0x008d}, + {0x0412, 0x011a}, + {0x0414, 0x864c}, + /* for OTP */ + {0x021c, 0x0003}, + {0x021e, 0x0235}, + /* for OTP */ + {0x0c00, 0x9950}, + {0x0c06, 0x0021}, + {0x0c10, 0x0040}, + {0x0c12, 0x0040}, + {0x0c14, 0x0040}, + {0x0c16, 0x0040}, + {0x0a02, 0x0100}, + {0x0a04, 0x015a}, + {0x0418, 0x0000}, + {0x0128, 0x0028}, + {0x012a, 0xffff}, + {0x0120, 0x0046}, + {0x0122, 0x0376}, + {0x012c, 0x0020}, + {0x012e, 0xffff}, + {0x0124, 0x0040}, + {0x0126, 0x0378}, + {0x0746, 0x0050}, + {0x0748, 0x01d5}, + {0x074a, 0x022b}, + {0x074c, 0x03b0}, + {0x0756, 0x043f}, + {0x0758, 0x3f1d}, + {0x0b02, 0xe04d}, + {0x0b10, 0x6821}, + {0x0b12, 0x0120}, + {0x0b14, 0x0001}, + {0x2008, 0x38fd}, + {0x326e, 0x0000}, + {0x0900, 0x0300}, + {0x0902, 0xc319}, + {0x0914, 0xc109}, + {0x0916, 0x061a}, + {0x0918, 0x0407}, + {0x091a, 0x0a0b}, + {0x091c, 0x0e08}, + {0x091e, 0x0a00}, + {0x090c, 0x0427}, + {0x090e, 0x0059}, + {0x0954, 0x0089}, + {0x0956, 0x0000}, + {0x0958, 0xca80}, + {0x095a, 0x9240}, + {0x0f08, 0x2f04}, + {0x0f30, 0x001f}, + {0x0f36, 0x001f}, + {0x0f04, 0x3a00}, + {0x0f32, 0x025a}, + {0x0f38, 0x025a}, + {0x0f2a, 0x4124}, + {0x006a, 0x0100}, + {0x004c, 0x0100}, + {0x0044, 0x0001}, +}; + +static const struct hi846_reg mode_640x480_config[] = { + {HI846_REG_MODE_SELECT, 0x0000}, + {HI846_REG_Y_ODD_INC_FOBP, 0x7711}, + {HI846_REG_Y_ODD_INC_VACT, 0x7711}, + {HI846_REG_Y_ADDR_START_VACT_H, 0x0148}, + {HI846_REG_Y_ADDR_END_VACT_H, 0x08c7}, + {HI846_REG_UNKNOWN_005C, 0x4404}, + {HI846_REG_FLL, 0x0277}, + {HI846_REG_LLP, 0x0ed8}, + {HI846_REG_BINNING_MODE, 0x0322}, + {HI846_REG_HBIN_MODE, 0x0200}, + {HI846_REG_UNKNOWN_0A24, 0x0000}, + {HI846_REG_X_START_H, 0x0058}, + {HI846_REG_X_OUTPUT_SIZE_H, 0x0280}, + {HI846_REG_Y_OUTPUT_SIZE_H, 0x01e0}, + + /* For OTP */ + {HI846_REG_UNKNOWN_021C, 0x0003}, + {HI846_REG_UNKNOWN_021E, 0x0235}, + + {HI846_REG_ISP_EN_H, 0x016a}, + {HI846_REG_UNKNOWN_0418, 0x0210}, + {HI846_REG_UNKNOWN_0B02, 0xe04d}, + {HI846_REG_UNKNOWN_0B10, 0x7021}, + {HI846_REG_UNKNOWN_0B12, 0x0120}, + {HI846_REG_UNKNOWN_0B14, 0x0001}, + {HI846_REG_UNKNOWN_2008, 0x38fd}, + {HI846_REG_UNKNOWN_326E, 0x0000}, +}; + +static const struct hi846_reg mode_640x480_mipi_2lane[] = { + {HI846_REG_UNKNOWN_0900, 0x0300}, + {HI846_REG_MIPI_TX_OP_MODE, 0x4319}, + {HI846_REG_UNKNOWN_0914, 0xc105}, + {HI846_REG_TCLK_PREPARE, 0x030c}, + {HI846_REG_UNKNOWN_0918, 0x0304}, + {HI846_REG_THS_ZERO, 0x0708}, + {HI846_REG_TCLK_POST, 0x0b04}, + {HI846_REG_UNKNOWN_091E, 0x0500}, + {HI846_REG_UNKNOWN_090C, 0x0208}, + {HI846_REG_UNKNOWN_090E, 0x009a}, + {HI846_REG_UNKNOWN_0954, 0x0089}, + {HI846_REG_UNKNOWN_0956, 0x0000}, + {HI846_REG_UNKNOWN_0958, 0xca80}, + {HI846_REG_UNKNOWN_095A, 0x9240}, + {HI846_REG_PLL_CFG_MIPI2_H, 0x4924}, + {HI846_REG_TG_ENABLE, 0x0100}, +}; + +static const struct hi846_reg mode_1280x720_config[] = { + {HI846_REG_MODE_SELECT, 0x0000}, + {HI846_REG_Y_ODD_INC_FOBP, 0x3311}, + {HI846_REG_Y_ODD_INC_VACT, 0x3311}, + {HI846_REG_Y_ADDR_START_VACT_H, 0x0238}, + {HI846_REG_Y_ADDR_END_VACT_H, 0x07d7}, + {HI846_REG_UNKNOWN_005C, 0x4202}, + {HI846_REG_FLL, 0x034a}, + {HI846_REG_LLP, 0x0ed8}, + {HI846_REG_BINNING_MODE, 0x0122}, + {HI846_REG_HBIN_MODE, 0x0100}, + {HI846_REG_UNKNOWN_0A24, 0x0000}, + {HI846_REG_X_START_H, 0x00b0}, + {HI846_REG_X_OUTPUT_SIZE_H, 0x0500}, + {HI846_REG_Y_OUTPUT_SIZE_H, 0x02d0}, + {HI846_REG_EXPOSURE, 0x0344}, + + /* For OTP */ + {HI846_REG_UNKNOWN_021C, 0x0003}, + {HI846_REG_UNKNOWN_021E, 0x0235}, + + {HI846_REG_ISP_EN_H, 0x016a}, + {HI846_REG_UNKNOWN_0418, 0x0410}, + {HI846_REG_UNKNOWN_0B02, 0xe04d}, + {HI846_REG_UNKNOWN_0B10, 0x6c21}, + {HI846_REG_UNKNOWN_0B12, 0x0120}, + {HI846_REG_UNKNOWN_0B14, 0x0005}, + {HI846_REG_UNKNOWN_2008, 0x38fd}, + {HI846_REG_UNKNOWN_326E, 0x0000}, +}; + +static const struct hi846_reg mode_1280x720_mipi_2lane[] = { + {HI846_REG_UNKNOWN_0900, 0x0300}, + {HI846_REG_MIPI_TX_OP_MODE, 0x4319}, + {HI846_REG_UNKNOWN_0914, 0xc109}, + {HI846_REG_TCLK_PREPARE, 0x061a}, + {HI846_REG_UNKNOWN_0918, 0x0407}, + {HI846_REG_THS_ZERO, 0x0a0b}, + {HI846_REG_TCLK_POST, 0x0e08}, + {HI846_REG_UNKNOWN_091E, 0x0a00}, + {HI846_REG_UNKNOWN_090C, 0x0427}, + {HI846_REG_UNKNOWN_090E, 0x0145}, + {HI846_REG_UNKNOWN_0954, 0x0089}, + {HI846_REG_UNKNOWN_0956, 0x0000}, + {HI846_REG_UNKNOWN_0958, 0xca80}, + {HI846_REG_UNKNOWN_095A, 0x9240}, + {HI846_REG_PLL_CFG_MIPI2_H, 0x4124}, + {HI846_REG_TG_ENABLE, 0x0100}, +}; + +static const struct hi846_reg mode_1280x720_mipi_4lane[] = { + /* 360Mbps */ + {HI846_REG_UNKNOWN_0900, 0x0300}, + {HI846_REG_MIPI_TX_OP_MODE, 0xc319}, + {HI846_REG_UNKNOWN_0914, 0xc105}, + {HI846_REG_TCLK_PREPARE, 0x030c}, + {HI846_REG_UNKNOWN_0918, 0x0304}, + {HI846_REG_THS_ZERO, 0x0708}, + {HI846_REG_TCLK_POST, 0x0b04}, + {HI846_REG_UNKNOWN_091E, 0x0500}, + {HI846_REG_UNKNOWN_090C, 0x0208}, + {HI846_REG_UNKNOWN_090E, 0x008a}, + {HI846_REG_UNKNOWN_0954, 0x0089}, + {HI846_REG_UNKNOWN_0956, 0x0000}, + {HI846_REG_UNKNOWN_0958, 0xca80}, + {HI846_REG_UNKNOWN_095A, 0x9240}, + {HI846_REG_PLL_CFG_MIPI2_H, 0x4924}, + {HI846_REG_TG_ENABLE, 0x0100}, +}; + +static const struct hi846_reg mode_1632x1224_config[] = { + {HI846_REG_MODE_SELECT, 0x0000}, + {HI846_REG_Y_ODD_INC_FOBP, 0x3311}, + {HI846_REG_Y_ODD_INC_VACT, 0x3311}, + {HI846_REG_Y_ADDR_START_VACT_H, 0x0040}, + {HI846_REG_Y_ADDR_END_VACT_H, 0x09cf}, + {HI846_REG_UNKNOWN_005C, 0x4202}, + {HI846_REG_FLL, 0x09de}, + {HI846_REG_LLP, 0x0ed8}, + {HI846_REG_BINNING_MODE, 0x0122}, + {HI846_REG_HBIN_MODE, 0x0100}, + {HI846_REG_UNKNOWN_0A24, 0x0000}, + {HI846_REG_X_START_H, 0x0000}, + {HI846_REG_X_OUTPUT_SIZE_H, 0x0660}, + {HI846_REG_Y_OUTPUT_SIZE_H, 0x04c8}, + {HI846_REG_EXPOSURE, 0x09d8}, + + /* For OTP */ + {HI846_REG_UNKNOWN_021C, 0x0003}, + {HI846_REG_UNKNOWN_021E, 0x0235}, + + {HI846_REG_ISP_EN_H, 0x016a}, + {HI846_REG_UNKNOWN_0418, 0x0000}, + {HI846_REG_UNKNOWN_0B02, 0xe04d}, + {HI846_REG_UNKNOWN_0B10, 0x6c21}, + {HI846_REG_UNKNOWN_0B12, 0x0120}, + {HI846_REG_UNKNOWN_0B14, 0x0005}, + {HI846_REG_UNKNOWN_2008, 0x38fd}, + {HI846_REG_UNKNOWN_326E, 0x0000}, +}; + +static const struct hi846_reg mode_1632x1224_mipi_2lane[] = { + {HI846_REG_UNKNOWN_0900, 0x0300}, + {HI846_REG_MIPI_TX_OP_MODE, 0x4319}, + {HI846_REG_UNKNOWN_0914, 0xc109}, + {HI846_REG_TCLK_PREPARE, 0x061a}, + {HI846_REG_UNKNOWN_0918, 0x0407}, + {HI846_REG_THS_ZERO, 0x0a0b}, + {HI846_REG_TCLK_POST, 0x0e08}, + {HI846_REG_UNKNOWN_091E, 0x0a00}, + {HI846_REG_UNKNOWN_090C, 0x0427}, + {HI846_REG_UNKNOWN_090E, 0x0069}, + {HI846_REG_UNKNOWN_0954, 0x0089}, + {HI846_REG_UNKNOWN_0956, 0x0000}, + {HI846_REG_UNKNOWN_0958, 0xca80}, + {HI846_REG_UNKNOWN_095A, 0x9240}, + {HI846_REG_PLL_CFG_MIPI2_H, 0x4124}, + {HI846_REG_TG_ENABLE, 0x0100}, +}; + +static const struct hi846_reg mode_1632x1224_mipi_4lane[] = { + {HI846_REG_UNKNOWN_0900, 0x0300}, + {HI846_REG_MIPI_TX_OP_MODE, 0xc319}, + {HI846_REG_UNKNOWN_0914, 0xc105}, + {HI846_REG_TCLK_PREPARE, 0x030c}, + {HI846_REG_UNKNOWN_0918, 0x0304}, + {HI846_REG_THS_ZERO, 0x0708}, + {HI846_REG_TCLK_POST, 0x0b04}, + {HI846_REG_UNKNOWN_091E, 0x0500}, + {HI846_REG_UNKNOWN_090C, 0x0208}, + {HI846_REG_UNKNOWN_090E, 0x001c}, + {HI846_REG_UNKNOWN_0954, 0x0089}, + {HI846_REG_UNKNOWN_0956, 0x0000}, + {HI846_REG_UNKNOWN_0958, 0xca80}, + {HI846_REG_UNKNOWN_095A, 0x9240}, + {HI846_REG_PLL_CFG_MIPI2_H, 0x4924}, + {HI846_REG_TG_ENABLE, 0x0100}, +}; + +static const char * const hi846_test_pattern_menu[] = { + "Disabled", + "Solid Colour", + "100% Colour Bars", + "Fade To Grey Colour Bars", + "PN9", + "Gradient Horizontal", + "Gradient Vertical", + "Check Board", + "Slant Pattern", + "Resolution Pattern", +}; + +#define FREQ_INDEX_640 0 +#define FREQ_INDEX_1280 1 +static const s64 hi846_link_freqs[] = { + [FREQ_INDEX_640] = 80000000, + [FREQ_INDEX_1280] = 200000000, +}; + +static const struct hi846_reg_list hi846_init_regs_list_2lane = { + .num_of_regs = ARRAY_SIZE(hi846_init_2lane), + .regs = hi846_init_2lane, +}; + +static const struct hi846_reg_list hi846_init_regs_list_4lane = { + .num_of_regs = ARRAY_SIZE(hi846_init_4lane), + .regs = hi846_init_4lane, +}; + +static const struct hi846_mode supported_modes[] = { + { + .width = 640, + .height = 480, + .link_freq_index = FREQ_INDEX_640, + .fps = 120, + .frame_len = 631, + .llp = HI846_LINE_LENGTH, + .reg_list_config = { + .num_of_regs = ARRAY_SIZE(mode_640x480_config), + .regs = mode_640x480_config, + }, + .reg_list_2lane = { + .num_of_regs = ARRAY_SIZE(mode_640x480_mipi_2lane), + .regs = mode_640x480_mipi_2lane, + }, + .reg_list_4lane = { + .num_of_regs = 0, + }, + .crop = { + .left = 0x58, + .top = 0x148, + .width = 640 * 4, + .height = 480 * 4, + }, + }, + { + .width = 1280, + .height = 720, + .link_freq_index = FREQ_INDEX_1280, + .fps = 90, + .frame_len = 842, + .llp = HI846_LINE_LENGTH, + .reg_list_config = { + .num_of_regs = ARRAY_SIZE(mode_1280x720_config), + .regs = mode_1280x720_config, + }, + .reg_list_2lane = { + .num_of_regs = ARRAY_SIZE(mode_1280x720_mipi_2lane), + .regs = mode_1280x720_mipi_2lane, + }, + .reg_list_4lane = { + .num_of_regs = ARRAY_SIZE(mode_1280x720_mipi_4lane), + .regs = mode_1280x720_mipi_4lane, + }, + .crop = { + .left = 0xb0, + .top = 0x238, + .width = 1280 * 2, + .height = 720 * 2, + }, + }, + { + .width = 1632, + .height = 1224, + .link_freq_index = FREQ_INDEX_1280, + .fps = 30, + .frame_len = 2526, + .llp = HI846_LINE_LENGTH, + .reg_list_config = { + .num_of_regs = ARRAY_SIZE(mode_1632x1224_config), + .regs = mode_1632x1224_config, + }, + .reg_list_2lane = { + .num_of_regs = ARRAY_SIZE(mode_1632x1224_mipi_2lane), + .regs = mode_1632x1224_mipi_2lane, + }, + .reg_list_4lane = { + .num_of_regs = ARRAY_SIZE(mode_1632x1224_mipi_4lane), + .regs = mode_1632x1224_mipi_4lane, + }, + .crop = { + .left = 0x0, + .top = 0x0, + .width = 1632 * 2, + .height = 1224 * 2, + }, + } +}; + +struct hi846_datafmt { + u32 code; + enum v4l2_colorspace colorspace; +}; + +static const char * const hi846_supply_names[] = { + "vddio", /* Digital I/O (1.8V or 2.8V) */ + "vdda", /* Analog (2.8V) */ + "vddd", /* Digital Core (1.2V) */ +}; + +#define HI846_NUM_SUPPLIES ARRAY_SIZE(hi846_supply_names) + +struct hi846 { + struct gpio_desc *rst_gpio; + struct gpio_desc *shutdown_gpio; + struct regulator_bulk_data supplies[HI846_NUM_SUPPLIES]; + struct clk *clock; + const struct hi846_datafmt *fmt; + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_ctrl_handler ctrl_handler; + u8 nr_lanes; + + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *exposure; + + struct mutex mutex; /* protect cur_mode, streaming and chip access */ + const struct hi846_mode *cur_mode; + bool streaming; +}; + +static inline struct hi846 *to_hi846(struct v4l2_subdev *sd) +{ + return container_of(sd, struct hi846, sd); +} + +static const struct hi846_datafmt hi846_colour_fmts[] = { + { HI846_MEDIA_BUS_FORMAT, V4L2_COLORSPACE_RAW }, +}; + +static const struct hi846_datafmt *hi846_find_datafmt(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(hi846_colour_fmts); i++) + if (hi846_colour_fmts[i].code == code) + return &hi846_colour_fmts[i]; + + return NULL; +} + +static inline u8 hi846_get_link_freq_index(struct hi846 *hi846) +{ + return hi846->cur_mode->link_freq_index; +} + +static u64 hi846_get_link_freq(struct hi846 *hi846) +{ + u8 index = hi846_get_link_freq_index(hi846); + + return hi846_link_freqs[index]; +} + +static u64 hi846_calc_pixel_rate(struct hi846 *hi846) +{ + u64 link_freq = hi846_get_link_freq(hi846); + u64 pixel_rate = link_freq * 2 * hi846->nr_lanes; + + do_div(pixel_rate, HI846_RGB_DEPTH); + + return pixel_rate; +} + +static int hi846_read_reg(struct hi846 *hi846, u16 reg, u8 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd); + struct i2c_msg msgs[2]; + u8 addr_buf[2]; + u8 data_buf[1] = {0}; + int ret; + + put_unaligned_be16(reg, addr_buf); + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(addr_buf); + msgs[0].buf = addr_buf; + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = 1; + msgs[1].buf = data_buf; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) { + dev_err(&client->dev, "i2c read error: %d\n", ret); + return -EIO; + } + + *val = data_buf[0]; + + return 0; +} + +static int hi846_write_reg(struct hi846 *hi846, u16 reg, u8 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd); + u8 buf[3] = { reg >> 8, reg & 0xff, val }; + struct i2c_msg msg[] = { + { .addr = client->addr, .flags = 0, + .len = ARRAY_SIZE(buf), .buf = buf }, + }; + int ret; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + dev_err(&client->dev, "i2c write error\n"); + return -EIO; + } + + return 0; +} + +static void hi846_write_reg_16(struct hi846 *hi846, u16 reg, u16 val, int *err) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd); + u8 buf[4]; + int ret; + + if (*err < 0) + return; + + put_unaligned_be16(reg, buf); + put_unaligned_be16(val, buf + 2); + ret = i2c_master_send(client, buf, sizeof(buf)); + if (ret != sizeof(buf)) { + dev_err(&client->dev, "i2c_master_send != %zu: %d\n", + sizeof(buf), ret); + *err = -EIO; + } +} + +static int hi846_write_reg_list(struct hi846 *hi846, + const struct hi846_reg_list *r_list) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd); + unsigned int i; + int ret = 0; + + for (i = 0; i < r_list->num_of_regs; i++) { + hi846_write_reg_16(hi846, r_list->regs[i].address, + r_list->regs[i].val, &ret); + if (ret) { + dev_err_ratelimited(&client->dev, + "failed to write reg 0x%4.4x: %d", + r_list->regs[i].address, ret); + return ret; + } + } + + return 0; +} + +static int hi846_update_digital_gain(struct hi846 *hi846, u16 d_gain) +{ + int ret = 0; + + hi846_write_reg_16(hi846, HI846_REG_MWB_GR_GAIN_H, d_gain, &ret); + hi846_write_reg_16(hi846, HI846_REG_MWB_GB_GAIN_H, d_gain, &ret); + hi846_write_reg_16(hi846, HI846_REG_MWB_R_GAIN_H, d_gain, &ret); + hi846_write_reg_16(hi846, HI846_REG_MWB_B_GAIN_H, d_gain, &ret); + + return ret; +} + +static int hi846_test_pattern(struct hi846 *hi846, u32 pattern) +{ + int ret; + u8 val; + + if (pattern) { + ret = hi846_read_reg(hi846, HI846_REG_ISP, &val); + if (ret) + return ret; + + ret = hi846_write_reg(hi846, HI846_REG_ISP, + val | HI846_REG_ISP_TPG_EN); + if (ret) + return ret; + } + + return hi846_write_reg(hi846, HI846_REG_TEST_PATTERN, pattern); +} + +static int hi846_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct hi846 *hi846 = container_of(ctrl->handler, + struct hi846, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd); + s64 exposure_max; + int ret = 0; + u32 shutter, frame_len; + + /* Propagate change of current control to all related controls */ + if (ctrl->id == V4L2_CID_VBLANK) { + /* Update max exposure while meeting expected vblanking */ + exposure_max = hi846->cur_mode->height + ctrl->val - + HI846_EXPOSURE_MAX_MARGIN; + __v4l2_ctrl_modify_range(hi846->exposure, + hi846->exposure->minimum, + exposure_max, hi846->exposure->step, + exposure_max); + } + + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = hi846_write_reg(hi846, HI846_REG_ANALOG_GAIN, ctrl->val); + break; + + case V4L2_CID_DIGITAL_GAIN: + ret = hi846_update_digital_gain(hi846, ctrl->val); + break; + + case V4L2_CID_EXPOSURE: + shutter = ctrl->val; + frame_len = hi846->cur_mode->frame_len; + + if (shutter > frame_len - 6) { /* margin */ + frame_len = shutter + 6; + if (frame_len > 0xffff) { /* max frame len */ + frame_len = 0xffff; + } + } + + if (shutter < 6) + shutter = 6; + if (shutter > (0xffff - 6)) + shutter = 0xffff - 6; + + hi846_write_reg_16(hi846, HI846_REG_FLL, frame_len, &ret); + hi846_write_reg_16(hi846, HI846_REG_EXPOSURE, shutter, &ret); + break; + + case V4L2_CID_VBLANK: + /* Update FLL that meets expected vertical blanking */ + hi846_write_reg_16(hi846, HI846_REG_FLL, + hi846->cur_mode->height + ctrl->val, &ret); + break; + case V4L2_CID_TEST_PATTERN: + ret = hi846_test_pattern(hi846, ctrl->val); + break; + + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops hi846_ctrl_ops = { + .s_ctrl = hi846_set_ctrl, +}; + +static int hi846_init_controls(struct hi846 *hi846) +{ + struct v4l2_ctrl_handler *ctrl_hdlr; + s64 exposure_max, h_blank; + int ret; + struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd); + struct v4l2_fwnode_device_properties props; + + ctrl_hdlr = &hi846->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10); + if (ret) + return ret; + + ctrl_hdlr->lock = &hi846->mutex; + + hi846->link_freq = + v4l2_ctrl_new_int_menu(ctrl_hdlr, &hi846_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(hi846_link_freqs) - 1, + 0, hi846_link_freqs); + if (hi846->link_freq) + hi846->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + hi846->pixel_rate = + v4l2_ctrl_new_std(ctrl_hdlr, &hi846_ctrl_ops, + V4L2_CID_PIXEL_RATE, 0, + hi846_calc_pixel_rate(hi846), 1, + hi846_calc_pixel_rate(hi846)); + hi846->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &hi846_ctrl_ops, + V4L2_CID_VBLANK, + hi846->cur_mode->frame_len - + hi846->cur_mode->height, + HI846_FLL_MAX - + hi846->cur_mode->height, 1, + hi846->cur_mode->frame_len - + hi846->cur_mode->height); + + h_blank = hi846->cur_mode->llp - hi846->cur_mode->width; + + hi846->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &hi846_ctrl_ops, + V4L2_CID_HBLANK, h_blank, h_blank, 1, + h_blank); + if (hi846->hblank) + hi846->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(ctrl_hdlr, &hi846_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + HI846_ANAL_GAIN_MIN, HI846_ANAL_GAIN_MAX, + HI846_ANAL_GAIN_STEP, HI846_ANAL_GAIN_MIN); + v4l2_ctrl_new_std(ctrl_hdlr, &hi846_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + HI846_DGTL_GAIN_MIN, HI846_DGTL_GAIN_MAX, + HI846_DGTL_GAIN_STEP, HI846_DGTL_GAIN_DEFAULT); + exposure_max = hi846->cur_mode->frame_len - HI846_EXPOSURE_MAX_MARGIN; + hi846->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &hi846_ctrl_ops, + V4L2_CID_EXPOSURE, + HI846_EXPOSURE_MIN, exposure_max, + HI846_EXPOSURE_STEP, + exposure_max); + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &hi846_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(hi846_test_pattern_menu) - 1, + 0, 0, hi846_test_pattern_menu); + if (ctrl_hdlr->error) { + dev_err(&client->dev, "v4l ctrl handler error: %d\n", + ctrl_hdlr->error); + return ctrl_hdlr->error; + } + + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + return ret; + + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &hi846_ctrl_ops, + &props); + if (ret) + return ret; + + hi846->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +static int hi846_set_video_mode(struct hi846 *hi846, int fps) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd); + u64 frame_length; + int ret = 0; + int dummy_lines; + u64 link_freq = hi846_get_link_freq(hi846); + + dev_dbg(&client->dev, "%s: link freq: %llu\n", __func__, + hi846_get_link_freq(hi846)); + + do_div(link_freq, fps); + frame_length = link_freq; + do_div(frame_length, HI846_LINE_LENGTH); + + dummy_lines = (frame_length > hi846->cur_mode->frame_len) ? + (frame_length - hi846->cur_mode->frame_len) : 0; + + frame_length = hi846->cur_mode->frame_len + dummy_lines; + + dev_dbg(&client->dev, "%s: frame length calculated: %llu\n", __func__, + frame_length); + + hi846_write_reg_16(hi846, HI846_REG_FLL, frame_length & 0xFFFF, &ret); + hi846_write_reg_16(hi846, HI846_REG_LLP, + HI846_LINE_LENGTH & 0xFFFF, &ret); + + return ret; +} + +static int hi846_start_streaming(struct hi846 *hi846) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd); + int ret = 0; + u8 val; + + if (hi846->nr_lanes == 2) + ret = hi846_write_reg_list(hi846, &hi846_init_regs_list_2lane); + else + ret = hi846_write_reg_list(hi846, &hi846_init_regs_list_4lane); + if (ret) { + dev_err(&client->dev, "failed to set plls: %d\n", ret); + return ret; + } + + ret = hi846_write_reg_list(hi846, &hi846->cur_mode->reg_list_config); + if (ret) { + dev_err(&client->dev, "failed to set mode: %d\n", ret); + return ret; + } + + if (hi846->nr_lanes == 2) + ret = hi846_write_reg_list(hi846, + &hi846->cur_mode->reg_list_2lane); + else + ret = hi846_write_reg_list(hi846, + &hi846->cur_mode->reg_list_4lane); + if (ret) { + dev_err(&client->dev, "failed to set mipi mode: %d\n", ret); + return ret; + } + + hi846_set_video_mode(hi846, hi846->cur_mode->fps); + + ret = __v4l2_ctrl_handler_setup(hi846->sd.ctrl_handler); + if (ret) + return ret; + + /* + * Reading 0x0034 is purely done for debugging reasons: It is not + * documented in the DS but only mentioned once: + * "If 0x0034[2] bit is disabled , Visible pixel width and height is 0." + * So even though that sounds like we won't see anything, we don't + * know more about this, so in that case only inform the user but do + * nothing more. + */ + ret = hi846_read_reg(hi846, 0x0034, &val); + if (ret) + return ret; + if (!(val & BIT(2))) + dev_info(&client->dev, "visible pixel width and height is 0\n"); + + ret = hi846_write_reg(hi846, HI846_REG_MODE_SELECT, + HI846_MODE_STREAMING); + if (ret) { + dev_err(&client->dev, "failed to start stream"); + return ret; + } + + hi846->streaming = 1; + + dev_dbg(&client->dev, "%s: started streaming successfully\n", __func__); + + return ret; +} + +static void hi846_stop_streaming(struct hi846 *hi846) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd); + + if (hi846_write_reg(hi846, HI846_REG_MODE_SELECT, HI846_MODE_STANDBY)) + dev_err(&client->dev, "failed to stop stream"); + + hi846->streaming = 0; +} + +static int hi846_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct hi846 *hi846 = to_hi846(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (hi846->streaming == enable) + return 0; + + mutex_lock(&hi846->mutex); + + if (enable) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto out; + } + + ret = hi846_start_streaming(hi846); + } + + if (!enable || ret) { + hi846_stop_streaming(hi846); + pm_runtime_put(&client->dev); + } + +out: + mutex_unlock(&hi846->mutex); + + return ret; +} + +static int hi846_power_on(struct hi846 *hi846) +{ + int ret; + + ret = regulator_bulk_enable(HI846_NUM_SUPPLIES, hi846->supplies); + if (ret < 0) + return ret; + + ret = clk_prepare_enable(hi846->clock); + if (ret < 0) + goto err_reg; + + if (hi846->shutdown_gpio) + gpiod_set_value_cansleep(hi846->shutdown_gpio, 0); + + /* 30us = 2400 cycles at 80Mhz */ + usleep_range(30, 60); + if (hi846->rst_gpio) + gpiod_set_value_cansleep(hi846->rst_gpio, 0); + usleep_range(30, 60); + + return 0; + +err_reg: + regulator_bulk_disable(HI846_NUM_SUPPLIES, hi846->supplies); + + return ret; +} + +static void hi846_power_off(struct hi846 *hi846) +{ + if (hi846->rst_gpio) + gpiod_set_value_cansleep(hi846->rst_gpio, 1); + + if (hi846->shutdown_gpio) + gpiod_set_value_cansleep(hi846->shutdown_gpio, 1); + + clk_disable_unprepare(hi846->clock); + regulator_bulk_disable(HI846_NUM_SUPPLIES, hi846->supplies); +} + +static int __maybe_unused hi846_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct hi846 *hi846 = to_hi846(sd); + + if (hi846->streaming) + hi846_stop_streaming(hi846); + + hi846_power_off(hi846); + + return 0; +} + +static int __maybe_unused hi846_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct hi846 *hi846 = to_hi846(sd); + int ret; + + ret = hi846_power_on(hi846); + if (ret) + return ret; + + if (hi846->streaming) { + ret = hi846_start_streaming(hi846); + if (ret) { + dev_err(dev, "%s: start streaming failed: %d\n", + __func__, ret); + goto error; + } + } + + return 0; + +error: + hi846_power_off(hi846); + return ret; +} + +static int hi846_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct hi846 *hi846 = to_hi846(sd); + struct v4l2_mbus_framefmt *mf = &format->format; + struct i2c_client *client = v4l2_get_subdevdata(sd); + const struct hi846_datafmt *fmt = hi846_find_datafmt(mf->code); + u32 tgt_fps; + s32 vblank_def, h_blank; + + if (!fmt) { + mf->code = hi846_colour_fmts[0].code; + mf->colorspace = hi846_colour_fmts[0].colorspace; + fmt = &hi846_colour_fmts[0]; + } + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + *v4l2_subdev_get_try_format(sd, sd_state, format->pad) = *mf; + return 0; + } + + if (hi846->nr_lanes == 2) { + if (!hi846->cur_mode->reg_list_2lane.num_of_regs) { + dev_err(&client->dev, + "this mode is not supported for 2 lanes\n"); + return -EINVAL; + } + } else { + if (!hi846->cur_mode->reg_list_4lane.num_of_regs) { + dev_err(&client->dev, + "this mode is not supported for 4 lanes\n"); + return -EINVAL; + } + } + + mutex_lock(&hi846->mutex); + + if (hi846->streaming) { + mutex_unlock(&hi846->mutex); + return -EBUSY; + } + + hi846->fmt = fmt; + + hi846->cur_mode = + v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, mf->width, mf->height); + dev_dbg(&client->dev, "%s: found mode: %dx%d\n", __func__, + hi846->cur_mode->width, hi846->cur_mode->height); + + tgt_fps = hi846->cur_mode->fps; + dev_dbg(&client->dev, "%s: target fps: %d\n", __func__, tgt_fps); + + mf->width = hi846->cur_mode->width; + mf->height = hi846->cur_mode->height; + mf->code = HI846_MEDIA_BUS_FORMAT; + mf->field = V4L2_FIELD_NONE; + + __v4l2_ctrl_s_ctrl(hi846->link_freq, hi846_get_link_freq_index(hi846)); + __v4l2_ctrl_s_ctrl_int64(hi846->pixel_rate, + hi846_calc_pixel_rate(hi846)); + + /* Update limits and set FPS to default */ + vblank_def = hi846->cur_mode->frame_len - hi846->cur_mode->height; + __v4l2_ctrl_modify_range(hi846->vblank, + hi846->cur_mode->frame_len - + hi846->cur_mode->height, + HI846_FLL_MAX - hi846->cur_mode->height, 1, + vblank_def); + __v4l2_ctrl_s_ctrl(hi846->vblank, vblank_def); + + h_blank = hi846->cur_mode->llp - hi846->cur_mode->width; + + __v4l2_ctrl_modify_range(hi846->hblank, h_blank, h_blank, 1, + h_blank); + + dev_dbg(&client->dev, "Set fmt w=%d h=%d code=0x%x colorspace=0x%x\n", + mf->width, mf->height, + fmt->code, fmt->colorspace); + + mutex_unlock(&hi846->mutex); + + return 0; +} + +static int hi846_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct hi846 *hi846 = to_hi846(sd); + struct v4l2_mbus_framefmt *mf = &format->format; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + format->format = *v4l2_subdev_get_try_format(&hi846->sd, + sd_state, + format->pad); + return 0; + } + + mutex_lock(&hi846->mutex); + mf->code = HI846_MEDIA_BUS_FORMAT; + mf->colorspace = V4L2_COLORSPACE_RAW; + mf->field = V4L2_FIELD_NONE; + mf->width = hi846->cur_mode->width; + mf->height = hi846->cur_mode->height; + mutex_unlock(&hi846->mutex); + dev_dbg(&client->dev, + "Get format w=%d h=%d code=0x%x colorspace=0x%x\n", + mf->width, mf->height, mf->code, mf->colorspace); + + return 0; +} + +static int hi846_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->pad || code->index > 0) + return -EINVAL; + + code->code = HI846_MEDIA_BUS_FORMAT; + + return 0; +} + +static int hi846_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (fse->pad || fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != HI846_MEDIA_BUS_FORMAT) { + dev_err(&client->dev, "frame size enum not matching\n"); + return -EINVAL; + } + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = supported_modes[fse->index].width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = supported_modes[fse->index].height; + + dev_dbg(&client->dev, "%s: max width: %d max height: %d\n", __func__, + fse->max_width, fse->max_height); + + return 0; +} + +static int hi846_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + struct hi846 *hi846 = to_hi846(sd); + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_CROP_DEFAULT: + mutex_lock(&hi846->mutex); + switch (sel->which) { + case V4L2_SUBDEV_FORMAT_TRY: + v4l2_subdev_get_try_crop(sd, sd_state, sel->pad); + break; + case V4L2_SUBDEV_FORMAT_ACTIVE: + sel->r = hi846->cur_mode->crop; + break; + } + mutex_unlock(&hi846->mutex); + return 0; + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = 3264; + sel->r.height = 2448; + return 0; + default: + return -EINVAL; + } +} + +static int hi846_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct hi846 *hi846 = to_hi846(sd); + struct v4l2_mbus_framefmt *mf; + + mf = v4l2_subdev_get_try_format(sd, sd_state, 0); + + mutex_lock(&hi846->mutex); + mf->code = HI846_MEDIA_BUS_FORMAT; + mf->colorspace = V4L2_COLORSPACE_RAW; + mf->field = V4L2_FIELD_NONE; + mf->width = hi846->cur_mode->width; + mf->height = hi846->cur_mode->height; + mutex_unlock(&hi846->mutex); + + return 0; +} + +static const struct v4l2_subdev_video_ops hi846_video_ops = { + .s_stream = hi846_set_stream, +}; + +static const struct v4l2_subdev_pad_ops hi846_pad_ops = { + .init_cfg = hi846_init_cfg, + .enum_frame_size = hi846_enum_frame_size, + .enum_mbus_code = hi846_enum_mbus_code, + .set_fmt = hi846_set_format, + .get_fmt = hi846_get_format, + .get_selection = hi846_get_selection, +}; + +static const struct v4l2_subdev_ops hi846_subdev_ops = { + .video = &hi846_video_ops, + .pad = &hi846_pad_ops, +}; + +static const struct media_entity_operations hi846_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static int hi846_identify_module(struct hi846 *hi846) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd); + int ret; + u8 hi, lo; + + ret = hi846_read_reg(hi846, HI846_REG_CHIP_ID_L, &lo); + if (ret) + return ret; + + if (lo != HI846_CHIP_ID_L) { + dev_err(&client->dev, "wrong chip id low byte: %x", lo); + return -ENXIO; + } + + ret = hi846_read_reg(hi846, HI846_REG_CHIP_ID_H, &hi); + if (ret) + return ret; + + if (hi != HI846_CHIP_ID_H) { + dev_err(&client->dev, "wrong chip id high byte: %x", hi); + return -ENXIO; + } + + dev_info(&client->dev, "chip id %02X %02X using %d mipi lanes\n", + hi, lo, hi846->nr_lanes); + + return 0; +} + +static s64 hi846_check_link_freqs(struct hi846 *hi846, + struct v4l2_fwnode_endpoint *ep) +{ + const s64 *freqs = hi846_link_freqs; + int freqs_count = ARRAY_SIZE(hi846_link_freqs); + int i, j; + + for (i = 0; i < freqs_count; i++) { + for (j = 0; j < ep->nr_of_link_frequencies; j++) + if (freqs[i] == ep->link_frequencies[j]) + break; + if (j == ep->nr_of_link_frequencies) + return freqs[i]; + } + + return 0; +} + +static int hi846_parse_dt(struct hi846 *hi846, struct device *dev) +{ + struct fwnode_handle *ep; + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + int ret; + s64 fq; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) { + dev_err(dev, "unable to find endpoint node\n"); + return -ENXIO; + } + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) { + dev_err(dev, "failed to parse endpoint node: %d\n", ret); + return ret; + } + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2 && + bus_cfg.bus.mipi_csi2.num_data_lanes != 4) { + dev_err(dev, "number of CSI2 data lanes %d is not supported", + bus_cfg.bus.mipi_csi2.num_data_lanes); + v4l2_fwnode_endpoint_free(&bus_cfg); + return -EINVAL; + } + + hi846->nr_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "link-frequency property not found in DT\n"); + return -EINVAL; + } + + /* Check that link frequences for all the modes are in device tree */ + fq = hi846_check_link_freqs(hi846, &bus_cfg); + if (fq) { + dev_err(dev, "Link frequency of %lld is not supported\n", fq); + return -EINVAL; + } + + v4l2_fwnode_endpoint_free(&bus_cfg); + + hi846->rst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(hi846->rst_gpio)) { + dev_err(dev, "failed to get reset gpio: %pe\n", + hi846->rst_gpio); + return PTR_ERR(hi846->rst_gpio); + } + + hi846->shutdown_gpio = devm_gpiod_get_optional(dev, "shutdown", + GPIOD_OUT_LOW); + if (IS_ERR(hi846->shutdown_gpio)) { + dev_err(dev, "failed to get shutdown gpio: %pe\n", + hi846->shutdown_gpio); + return PTR_ERR(hi846->shutdown_gpio); + } + + return 0; +} + +static int hi846_probe(struct i2c_client *client) +{ + struct hi846 *hi846; + int ret; + int i; + u32 mclk_freq; + + hi846 = devm_kzalloc(&client->dev, sizeof(*hi846), GFP_KERNEL); + if (!hi846) + return -ENOMEM; + + ret = hi846_parse_dt(hi846, &client->dev); + if (ret) { + dev_err(&client->dev, "failed to check HW configuration: %d", + ret); + return ret; + } + + hi846->clock = devm_clk_get(&client->dev, NULL); + if (IS_ERR(hi846->clock)) { + dev_err(&client->dev, "failed to get clock: %pe\n", + hi846->clock); + return PTR_ERR(hi846->clock); + } + + mclk_freq = clk_get_rate(hi846->clock); + if (mclk_freq != 25000000) + dev_warn(&client->dev, + "External clock freq should be 25000000, not %u.\n", + mclk_freq); + + for (i = 0; i < HI846_NUM_SUPPLIES; i++) + hi846->supplies[i].supply = hi846_supply_names[i]; + + ret = devm_regulator_bulk_get(&client->dev, HI846_NUM_SUPPLIES, + hi846->supplies); + if (ret < 0) + return ret; + + v4l2_i2c_subdev_init(&hi846->sd, client, &hi846_subdev_ops); + + mutex_init(&hi846->mutex); + + ret = hi846_power_on(hi846); + if (ret) + goto err_mutex; + + ret = hi846_identify_module(hi846); + if (ret) + goto err_power_off; + + hi846->cur_mode = &supported_modes[0]; + + ret = hi846_init_controls(hi846); + if (ret) { + dev_err(&client->dev, "failed to init controls: %d", ret); + goto err_power_off; + } + + hi846->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + hi846->sd.entity.ops = &hi846_subdev_entity_ops; + hi846->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + hi846->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&hi846->sd.entity, 1, &hi846->pad); + if (ret) { + dev_err(&client->dev, "failed to init entity pads: %d", ret); + goto err_v4l2_ctrl_handler_free; + } + + ret = v4l2_async_register_subdev_sensor(&hi846->sd); + if (ret < 0) { + dev_err(&client->dev, "failed to register V4L2 subdev: %d", + ret); + goto err_media_entity_cleanup; + } + + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + + return 0; + +err_media_entity_cleanup: + media_entity_cleanup(&hi846->sd.entity); + +err_v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(hi846->sd.ctrl_handler); + +err_power_off: + hi846_power_off(hi846); + +err_mutex: + mutex_destroy(&hi846->mutex); + + return ret; +} + +static int hi846_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct hi846 *hi846 = to_hi846(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + hi846_suspend(&client->dev); + pm_runtime_set_suspended(&client->dev); + + mutex_destroy(&hi846->mutex); + + return 0; +} + +static UNIVERSAL_DEV_PM_OPS(hi846_pm_ops, hi846_suspend, hi846_resume, NULL); + +static const struct of_device_id hi846_of_match[] = { + { .compatible = "hynix,hi846", }, + {}, +}; +MODULE_DEVICE_TABLE(of, hi846_of_match); + +static struct i2c_driver hi846_i2c_driver = { + .driver = { + .name = "hi846", + .pm = &hi846_pm_ops, + .of_match_table = of_match_ptr(hi846_of_match), + }, + .probe_new = hi846_probe, + .remove = hi846_remove, +}; + +module_i2c_driver(hi846_i2c_driver); + +MODULE_AUTHOR("Angus Ainslie "); +MODULE_AUTHOR("Martin Kepplinger "); +MODULE_DESCRIPTION("Hynix HI846 sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 5fe23d700db7770d6e2f645eff5d52aa7ab47fd0 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 6 Sep 2021 12:28:37 +0200 Subject: media: Documentation: i2c-cardlist: add the Hynix hi846 sensor Add the SK Hynix Hi-846 8M Pixel CMOS image sensor to the i2c-cardlist. Signed-off-by: Martin Kepplinger Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/admin-guide/media/i2c-cardlist.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/admin-guide/media/i2c-cardlist.rst b/Documentation/admin-guide/media/i2c-cardlist.rst index e60d459d18a9..185e07a3da43 100644 --- a/Documentation/admin-guide/media/i2c-cardlist.rst +++ b/Documentation/admin-guide/media/i2c-cardlist.rst @@ -60,6 +60,7 @@ Driver Name ============ ========================================================== et8ek8 ET8EK8 camera sensor hi556 Hynix Hi-556 sensor +hi846 Hynix Hi-846 sensor imx214 Sony IMX214 sensor imx219 Sony IMX219 sensor imx258 Sony IMX258 sensor -- cgit v1.2.3 From 566778bc1da7bad0b2509b4b89176c5c93caf72c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 20 Aug 2021 14:56:26 +0200 Subject: media: admin-guide: Update i2c-cardlist Add MIPI CCS compliant devices, a few Sony IMX, Hynix Hi-846 and Omnivision ov13b10 sensors and the DW9768 lens driver to the list of supported devices. Also drop SMIA since as a standard it is obsolete. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/admin-guide/media/i2c-cardlist.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/media/i2c-cardlist.rst b/Documentation/admin-guide/media/i2c-cardlist.rst index 185e07a3da43..db17f39b56cf 100644 --- a/Documentation/admin-guide/media/i2c-cardlist.rst +++ b/Documentation/admin-guide/media/i2c-cardlist.rst @@ -58,16 +58,20 @@ Camera sensor devices ============ ========================================================== Driver Name ============ ========================================================== +ccs MIPI CCS compliant camera sensors (also SMIA++ and SMIA) et8ek8 ET8EK8 camera sensor hi556 Hynix Hi-556 sensor hi846 Hynix Hi-846 sensor +imx208 Sony IMX208 sensor imx214 Sony IMX214 sensor imx219 Sony IMX219 sensor imx258 Sony IMX258 sensor imx274 Sony IMX274 sensor imx290 Sony IMX290 sensor imx319 Sony IMX319 sensor +imx334 Sony IMX334 sensor imx355 Sony IMX355 sensor +imx412 Sony IMX412 sensor m5mols Fujitsu M-5MOLS 8MP sensor mt9m001 mt9m001 mt9m032 MT9M032 camera sensor @@ -80,6 +84,7 @@ mt9v032 Micron MT9V032 sensor mt9v111 Aptina MT9V111 sensor noon010pc30 Siliconfile NOON010PC30 sensor ov13858 OmniVision OV13858 sensor +ov13b10 OmniVision OV13B10 sensor ov2640 OmniVision OV2640 sensor ov2659 OmniVision OV2659 sensor ov2680 OmniVision OV2680 sensor @@ -105,7 +110,6 @@ s5k4ecgx Samsung S5K4ECGX sensor s5k5baf Samsung S5K5BAF sensor s5k6a3 Samsung S5K6A3 sensor s5k6aa Samsung S5K6AAFX sensor -smiapp SMIA++/SMIA sensor sr030pc30 Siliconfile SR030PC30 sensor vs6624 ST VS6624 sensor ============ ========================================================== @@ -139,6 +143,7 @@ Driver Name ad5820 AD5820 lens voice coil ak7375 AK7375 lens voice coil dw9714 DW9714 lens voice coil +dw9768 DW9768 lens voice coil dw9807-vcm DW9807 lens voice coil ============ ========================================================== -- cgit v1.2.3 From c96651a00208f80afeb3d093c946b2aa0f2fd2f6 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Tue, 5 Oct 2021 23:45:01 +0200 Subject: media: staging/intel-ipu3: Constify static struct v4l2_subdev_internal_ops The only usage of imgu_subdev_internal_ops is to assign its address to the internal_ops field in the v4l2_subdev struct, which is a pointer to const v4l2_subdev_internal_ops. Make it const to allow the compiler to put it in read-only memory. Signed-off-by: Rikard Falkeborn Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/ipu3/ipu3-v4l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c index 38a240764509..b723186d2134 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -864,7 +864,7 @@ static int imgu_vidioc_g_meta_fmt(struct file *file, void *fh, /******************** function pointers ********************/ -static struct v4l2_subdev_internal_ops imgu_subdev_internal_ops = { +static const struct v4l2_subdev_internal_ops imgu_subdev_internal_ops = { .open = imgu_subdev_open, }; -- cgit v1.2.3 From af1ffd628adfb26f7dafe8e94e0f4bad99f44c3e Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Tue, 5 Oct 2021 21:04:27 +0200 Subject: media: rcar-isp: Add Renesas R-Car Image Signal Processor driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a V4L2 driver for Renesas R-Car Image Signal Processor. The driver supports the R-Car V3U SoC where the ISP IP sits between the R-Car CSI-2 receiver and VIN and filters the CSI-2 data based on VC/DT and directs the video stream to different VIN IPs. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 1 + drivers/media/platform/Kconfig | 16 ++ drivers/media/platform/Makefile | 1 + drivers/media/platform/rcar-isp.c | 515 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 533 insertions(+) create mode 100644 drivers/media/platform/rcar-isp.c diff --git a/MAINTAINERS b/MAINTAINERS index 60deb26c740f..cb51ebb3fb42 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11681,6 +11681,7 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/renesas,csi2.yaml F: Documentation/devicetree/bindings/media/renesas,isp.yaml F: Documentation/devicetree/bindings/media/renesas,vin.yaml +F: drivers/media/platform/rcar-isp.c F: drivers/media/platform/rcar-vin/ MEDIA DRIVERS FOR RENESAS - VSP1 diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index d9f90084c2f6..499c673fa02a 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -200,6 +200,22 @@ config VIDEO_TI_CAL_MC endif # VIDEO_TI_CAL +config VIDEO_RCAR_ISP + tristate "R-Car Image Signal Processor (ISP)" + depends on VIDEO_V4L2 && OF + depends on ARCH_RENESAS || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select RESET_CONTROLLER + select V4L2_FWNODE + help + Support for Renesas R-Car Image Signal Processor (ISP). + Enable this to support the Renesas R-Car Image Signal + Processor (ISP). + + To compile this driver as a module, choose M here: the + module will be called rcar-isp. + endif # V4L_PLATFORM_DRIVERS menuconfig V4L_MEM2MEM_DRIVERS diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 73ce083c2fc6..a148553babfc 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ obj-$(CONFIG_VIDEO_XILINX) += xilinx/ +obj-$(CONFIG_VIDEO_RCAR_ISP) += rcar-isp.o obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin/ obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel/ diff --git a/drivers/media/platform/rcar-isp.c b/drivers/media/platform/rcar-isp.c new file mode 100644 index 000000000000..2ffab30bc011 --- /dev/null +++ b/drivers/media/platform/rcar-isp.c @@ -0,0 +1,515 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Renesas Electronics Corp. + * + * Driver for Renesas R-Car ISP Channel Selector + * + * The ISP hardware is capable of more than just channel selection, features + * such as demosaicing, white balance control and color space conversion are + * also possible. These more advanced features are not supported by the driver + * due to lack of documentation. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define ISPINPUTSEL0_REG 0x0008 +#define ISPINPUTSEL0_SEL_CSI0 BIT(31) + +#define ISPSTART_REG 0x0014 +#define ISPSTART_START 0xffff +#define ISPSTART_STOP 0x0000 + +#define ISPPROCMODE_DT_REG(n) (0x1100 + (0x4 * (n))) +#define ISPPROCMODE_DT_PROC_MODE_VC3(pm) (((pm) & 0x3f) << 24) +#define ISPPROCMODE_DT_PROC_MODE_VC2(pm) (((pm) & 0x3f) << 16) +#define ISPPROCMODE_DT_PROC_MODE_VC1(pm) (((pm) & 0x3f) << 8) +#define ISPPROCMODE_DT_PROC_MODE_VC0(pm) ((pm) & 0x3f) + +#define ISPCS_FILTER_ID_CH_REG(n) (0x3000 + (0x0100 * (n))) + +#define ISPCS_DT_CODE03_CH_REG(n) (0x3008 + (0x100 * (n))) +#define ISPCS_DT_CODE03_EN3 BIT(31) +#define ISPCS_DT_CODE03_DT3(dt) (((dt) & 0x3f) << 24) +#define ISPCS_DT_CODE03_EN2 BIT(23) +#define ISPCS_DT_CODE03_DT2(dt) (((dt) & 0x3f) << 16) +#define ISPCS_DT_CODE03_EN1 BIT(15) +#define ISPCS_DT_CODE03_DT1(dt) (((dt) & 0x3f) << 8) +#define ISPCS_DT_CODE03_EN0 BIT(7) +#define ISPCS_DT_CODE03_DT0(dt) ((dt) & 0x3f) + +struct rcar_isp_format { + u32 code; + unsigned int datatype; + unsigned int procmode; +}; + +static const struct rcar_isp_format rcar_isp_formats[] = { + { .code = MEDIA_BUS_FMT_RGB888_1X24, .datatype = 0x24, .procmode = 0x15 }, + { .code = MEDIA_BUS_FMT_Y10_1X10, .datatype = 0x2b, .procmode = 0x10 }, + { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .procmode = 0x0c }, + { .code = MEDIA_BUS_FMT_YUYV8_1X16, .datatype = 0x1e, .procmode = 0x0c }, + { .code = MEDIA_BUS_FMT_UYVY8_2X8, .datatype = 0x1e, .procmode = 0x0c }, + { .code = MEDIA_BUS_FMT_YUYV10_2X10, .datatype = 0x1e, .procmode = 0x0c }, +}; + +static const struct rcar_isp_format *risp_code_to_fmt(unsigned int code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rcar_isp_formats); i++) { + if (rcar_isp_formats[i].code == code) + return &rcar_isp_formats[i]; + } + + return NULL; +} + +enum rcar_isp_input { + RISP_CSI_INPUT0, + RISP_CSI_INPUT1, +}; + +enum rcar_isp_pads { + RCAR_ISP_SINK, + RCAR_ISP_PORT0, + RCAR_ISP_PORT1, + RCAR_ISP_PORT2, + RCAR_ISP_PORT3, + RCAR_ISP_PORT4, + RCAR_ISP_PORT5, + RCAR_ISP_PORT6, + RCAR_ISP_PORT7, + RCAR_ISP_NUM_PADS, +}; + +struct rcar_isp { + struct device *dev; + void __iomem *base; + struct reset_control *rstc; + + enum rcar_isp_input csi_input; + + struct v4l2_subdev subdev; + struct media_pad pads[RCAR_ISP_NUM_PADS]; + + struct v4l2_async_notifier notifier; + struct v4l2_subdev *remote; + + struct mutex lock; /* Protects mf and stream_count. */ + struct v4l2_mbus_framefmt mf; + int stream_count; +}; + +static inline struct rcar_isp *sd_to_isp(struct v4l2_subdev *sd) +{ + return container_of(sd, struct rcar_isp, subdev); +} + +static inline struct rcar_isp *notifier_to_isp(struct v4l2_async_notifier *n) +{ + return container_of(n, struct rcar_isp, notifier); +} + +static void risp_write(struct rcar_isp *isp, u32 offset, u32 value) +{ + iowrite32(value, isp->base + offset); +} + +static u32 risp_read(struct rcar_isp *isp, u32 offset) +{ + return ioread32(isp->base + offset); +} + +static int risp_power_on(struct rcar_isp *isp) +{ + int ret; + + ret = pm_runtime_resume_and_get(isp->dev); + if (ret < 0) + return ret; + + ret = reset_control_deassert(isp->rstc); + if (ret < 0) { + pm_runtime_put(isp->dev); + return ret; + } + + return 0; +} + +static void risp_power_off(struct rcar_isp *isp) +{ + reset_control_assert(isp->rstc); + pm_runtime_put(isp->dev); +} + +static int risp_start(struct rcar_isp *isp) +{ + const struct rcar_isp_format *format; + unsigned int vc; + u32 sel_csi = 0; + int ret; + + format = risp_code_to_fmt(isp->mf.code); + if (!format) { + dev_err(isp->dev, "Unsupported bus format\n"); + return -EINVAL; + } + + ret = risp_power_on(isp); + if (ret) { + dev_err(isp->dev, "Failed to power on ISP\n"); + return ret; + } + + /* Select CSI-2 input source. */ + if (isp->csi_input == RISP_CSI_INPUT1) + sel_csi = ISPINPUTSEL0_SEL_CSI0; + + risp_write(isp, ISPINPUTSEL0_REG, + risp_read(isp, ISPINPUTSEL0_REG) | sel_csi); + + /* Configure Channel Selector. */ + for (vc = 0; vc < 4; vc++) { + u8 ch = vc + 4; + u8 dt = format->datatype; + + risp_write(isp, ISPCS_FILTER_ID_CH_REG(ch), BIT(vc)); + risp_write(isp, ISPCS_DT_CODE03_CH_REG(ch), + ISPCS_DT_CODE03_EN3 | ISPCS_DT_CODE03_DT3(dt) | + ISPCS_DT_CODE03_EN2 | ISPCS_DT_CODE03_DT2(dt) | + ISPCS_DT_CODE03_EN1 | ISPCS_DT_CODE03_DT1(dt) | + ISPCS_DT_CODE03_EN0 | ISPCS_DT_CODE03_DT0(dt)); + } + + /* Setup processing method. */ + risp_write(isp, ISPPROCMODE_DT_REG(format->datatype), + ISPPROCMODE_DT_PROC_MODE_VC3(format->procmode) | + ISPPROCMODE_DT_PROC_MODE_VC2(format->procmode) | + ISPPROCMODE_DT_PROC_MODE_VC1(format->procmode) | + ISPPROCMODE_DT_PROC_MODE_VC0(format->procmode)); + + /* Start ISP. */ + risp_write(isp, ISPSTART_REG, ISPSTART_START); + + ret = v4l2_subdev_call(isp->remote, video, s_stream, 1); + if (ret) + risp_power_off(isp); + + return ret; +} + +static void risp_stop(struct rcar_isp *isp) +{ + v4l2_subdev_call(isp->remote, video, s_stream, 0); + + /* Stop ISP. */ + risp_write(isp, ISPSTART_REG, ISPSTART_STOP); + + risp_power_off(isp); +} + +static int risp_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct rcar_isp *isp = sd_to_isp(sd); + int ret = 0; + + mutex_lock(&isp->lock); + + if (!isp->remote) { + ret = -ENODEV; + goto out; + } + + if (enable && isp->stream_count == 0) { + ret = risp_start(isp); + if (ret) + goto out; + } else if (!enable && isp->stream_count == 1) { + risp_stop(isp); + } + + isp->stream_count += enable ? 1 : -1; +out: + mutex_unlock(&isp->lock); + + return ret; +} + +static const struct v4l2_subdev_video_ops risp_video_ops = { + .s_stream = risp_s_stream, +}; + +static int risp_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct rcar_isp *isp = sd_to_isp(sd); + struct v4l2_mbus_framefmt *framefmt; + + mutex_lock(&isp->lock); + + if (!risp_code_to_fmt(format->format.code)) + format->format.code = rcar_isp_formats[0].code; + + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + isp->mf = format->format; + } else { + framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0); + *framefmt = format->format; + } + + mutex_unlock(&isp->lock); + + return 0; +} + +static int risp_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct rcar_isp *isp = sd_to_isp(sd); + + mutex_lock(&isp->lock); + + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + format->format = isp->mf; + else + format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0); + + mutex_unlock(&isp->lock); + + return 0; +} + +static const struct v4l2_subdev_pad_ops risp_pad_ops = { + .set_fmt = risp_set_pad_format, + .get_fmt = risp_get_pad_format, + .link_validate = v4l2_subdev_link_validate_default, +}; + +static const struct v4l2_subdev_ops rcar_isp_subdev_ops = { + .video = &risp_video_ops, + .pad = &risp_pad_ops, +}; + +/* ----------------------------------------------------------------------------- + * Async handling and registration of subdevices and links + */ + +static int risp_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct rcar_isp *isp = notifier_to_isp(notifier); + int pad; + + pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode, + MEDIA_PAD_FL_SOURCE); + if (pad < 0) { + dev_err(isp->dev, "Failed to find pad for %s\n", subdev->name); + return pad; + } + + isp->remote = subdev; + + dev_dbg(isp->dev, "Bound %s pad: %d\n", subdev->name, pad); + + return media_create_pad_link(&subdev->entity, pad, + &isp->subdev.entity, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); +} + +static void risp_notify_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct rcar_isp *isp = notifier_to_isp(notifier); + + isp->remote = NULL; + + dev_dbg(isp->dev, "Unbind %s\n", subdev->name); +} + +static const struct v4l2_async_notifier_operations risp_notify_ops = { + .bound = risp_notify_bound, + .unbind = risp_notify_unbind, +}; + +static int risp_parse_dt(struct rcar_isp *isp) +{ + struct v4l2_async_subdev *asd; + struct fwnode_handle *fwnode; + struct fwnode_handle *ep; + unsigned int id; + int ret; + + for (id = 0; id < 2; id++) { + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(isp->dev), + 0, id, 0); + if (ep) + break; + } + + if (!ep) { + dev_err(isp->dev, "Not connected to subdevice\n"); + return -EINVAL; + } + + if (id == 1) + isp->csi_input = RISP_CSI_INPUT1; + + fwnode = fwnode_graph_get_remote_endpoint(ep); + fwnode_handle_put(ep); + + dev_dbg(isp->dev, "Found '%pOF'\n", to_of_node(fwnode)); + + v4l2_async_nf_init(&isp->notifier); + isp->notifier.ops = &risp_notify_ops; + + asd = v4l2_async_nf_add_fwnode(&isp->notifier, fwnode, + struct v4l2_async_subdev); + fwnode_handle_put(fwnode); + if (IS_ERR(asd)) + return PTR_ERR(asd); + + ret = v4l2_async_subdev_nf_register(&isp->subdev, &isp->notifier); + if (ret) + v4l2_async_nf_cleanup(&isp->notifier); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * Platform Device Driver + */ + +static const struct media_entity_operations risp_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static int risp_probe_resources(struct rcar_isp *isp, + struct platform_device *pdev) +{ + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + isp->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(isp->base)) + return PTR_ERR(isp->base); + + isp->rstc = devm_reset_control_get(&pdev->dev, NULL); + + return PTR_ERR_OR_ZERO(isp->rstc); +} + +static const struct of_device_id risp_of_id_table[] = { + { .compatible = "renesas,r8a779a0-isp" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, risp_of_id_table); + +static int risp_probe(struct platform_device *pdev) +{ + struct rcar_isp *isp; + unsigned int i; + int ret; + + isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); + if (!isp) + return -ENOMEM; + + isp->dev = &pdev->dev; + + mutex_init(&isp->lock); + + ret = risp_probe_resources(isp, pdev); + if (ret) { + dev_err(isp->dev, "Failed to get resources\n"); + goto error_mutex; + } + + platform_set_drvdata(pdev, isp); + + pm_runtime_enable(&pdev->dev); + + ret = risp_parse_dt(isp); + if (ret) + goto error_pm; + + isp->subdev.owner = THIS_MODULE; + isp->subdev.dev = &pdev->dev; + v4l2_subdev_init(&isp->subdev, &rcar_isp_subdev_ops); + v4l2_set_subdevdata(&isp->subdev, &pdev->dev); + snprintf(isp->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s %s", + KBUILD_MODNAME, dev_name(&pdev->dev)); + isp->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + + isp->subdev.entity.function = MEDIA_ENT_F_VID_MUX; + isp->subdev.entity.ops = &risp_entity_ops; + + isp->pads[RCAR_ISP_SINK].flags = MEDIA_PAD_FL_SINK; + for (i = RCAR_ISP_PORT0; i < RCAR_ISP_NUM_PADS; i++) + isp->pads[i].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&isp->subdev.entity, RCAR_ISP_NUM_PADS, + isp->pads); + if (ret) + goto error_notifier; + + ret = v4l2_async_register_subdev(&isp->subdev); + if (ret < 0) + goto error_notifier; + + dev_info(isp->dev, "Using CSI-2 input: %u\n", isp->csi_input); + + return 0; +error_notifier: + v4l2_async_nf_unregister(&isp->notifier); + v4l2_async_nf_cleanup(&isp->notifier); +error_pm: + pm_runtime_disable(&pdev->dev); +error_mutex: + mutex_destroy(&isp->lock); + + return ret; +} + +static int risp_remove(struct platform_device *pdev) +{ + struct rcar_isp *isp = platform_get_drvdata(pdev); + + v4l2_async_nf_unregister(&isp->notifier); + v4l2_async_nf_cleanup(&isp->notifier); + + v4l2_async_unregister_subdev(&isp->subdev); + + pm_runtime_disable(&pdev->dev); + + mutex_destroy(&isp->lock); + + return 0; +} + +static struct platform_driver rcar_isp_driver = { + .driver = { + .name = "rcar-isp", + .of_match_table = risp_of_id_table, + }, + .probe = risp_probe, + .remove = risp_remove, +}; + +module_platform_driver(rcar_isp_driver); + +MODULE_AUTHOR("Niklas Söderlund "); +MODULE_DESCRIPTION("Renesas R-Car ISP Channel Selector driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 37b198eeb0d41382d80b45101bac3a2e400e67a8 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Thu, 7 Oct 2021 00:26:18 +0200 Subject: media: ipu3-cio2 Check num_planes and sizes in queue_setup If num_planes is different than zero num_planes and sizes must be checked to support the format. Fix the following v4l2-compliance error: Buffer ioctls (Input 0): fail: v4l2-test-buffers.cpp(717): q.create_bufs(node, 1, &fmt) != EINVAL test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: FAIL Reviewed-by: Bingbu Cao Signed-off-by: Ricardo Ribalda Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index 98cb3bc834db..356ea966cf8d 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -797,13 +797,17 @@ static int cio2_vb2_queue_setup(struct vb2_queue *vq, struct cio2_queue *q = vb2q_to_cio2_queue(vq); unsigned int i; - *num_planes = q->format.num_planes; + if (*num_planes && *num_planes < q->format.num_planes) + return -EINVAL; - for (i = 0; i < *num_planes; ++i) { + for (i = 0; i < q->format.num_planes; ++i) { + if (*num_planes && sizes[i] < q->format.plane_fmt[i].sizeimage) + return -EINVAL; sizes[i] = q->format.plane_fmt[i].sizeimage; alloc_devs[i] = dev; } + *num_planes = q->format.num_planes; *num_buffers = clamp_val(*num_buffers, 1, CIO2_MAX_BUFFERS); /* Initialize buffer queue */ -- cgit v1.2.3 From 3eacb6028e84ade9da6469a31404acb1b43d2a00 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Thu, 7 Oct 2021 00:26:19 +0200 Subject: media: ipu3-imgu: Refactor bytesperpixel calculation Move the calculation to an inline function, to it can be used by other parts of the driver. Signed-off-by: Ricardo Ribalda Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/ipu3/ipu3-css.c | 19 +++---------------- drivers/staging/media/ipu3/ipu3-css.h | 1 - drivers/staging/media/ipu3/ipu3.h | 12 ++++++++++++ 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/staging/media/ipu3/ipu3-css.c b/drivers/staging/media/ipu3/ipu3-css.c index 608dcacf12b2..8c70497d744c 100644 --- a/drivers/staging/media/ipu3/ipu3-css.c +++ b/drivers/staging/media/ipu3/ipu3-css.c @@ -5,6 +5,7 @@ #include #include +#include "ipu3.h" #include "ipu3-css.h" #include "ipu3-css-fw.h" #include "ipu3-css-params.h" @@ -53,7 +54,6 @@ static const struct imgu_css_format imgu_css_formats[] = { .frame_format = IMGU_ABI_FRAME_FORMAT_NV12, .osys_format = IMGU_ABI_OSYS_FORMAT_NV12, .osys_tiling = IMGU_ABI_OSYS_TILING_NONE, - .bytesperpixel_num = 1 * IPU3_CSS_FORMAT_BPP_DEN, .chroma_decim = 4, .width_align = IPU3_UAPI_ISP_VEC_ELEMS, .flags = IPU3_CSS_FORMAT_FL_OUT | IPU3_CSS_FORMAT_FL_VF, @@ -64,7 +64,6 @@ static const struct imgu_css_format imgu_css_formats[] = { .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED, .bayer_order = IMGU_ABI_BAYER_ORDER_BGGR, .bit_depth = 10, - .bytesperpixel_num = 64, .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS, .flags = IPU3_CSS_FORMAT_FL_IN, }, { @@ -73,7 +72,6 @@ static const struct imgu_css_format imgu_css_formats[] = { .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED, .bayer_order = IMGU_ABI_BAYER_ORDER_GBRG, .bit_depth = 10, - .bytesperpixel_num = 64, .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS, .flags = IPU3_CSS_FORMAT_FL_IN, }, { @@ -82,7 +80,6 @@ static const struct imgu_css_format imgu_css_formats[] = { .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED, .bayer_order = IMGU_ABI_BAYER_ORDER_GRBG, .bit_depth = 10, - .bytesperpixel_num = 64, .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS, .flags = IPU3_CSS_FORMAT_FL_IN, }, { @@ -91,7 +88,6 @@ static const struct imgu_css_format imgu_css_formats[] = { .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED, .bayer_order = IMGU_ABI_BAYER_ORDER_RGGB, .bit_depth = 10, - .bytesperpixel_num = 64, .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS, .flags = IPU3_CSS_FORMAT_FL_IN, }, @@ -150,17 +146,8 @@ static int imgu_css_queue_init(struct imgu_css_queue *queue, f->height = ALIGN(clamp_t(u32, f->height, IPU3_CSS_MIN_RES, IPU3_CSS_MAX_H), 2); queue->width_pad = ALIGN(f->width, queue->css_fmt->width_align); - if (queue->css_fmt->frame_format != IMGU_ABI_FRAME_FORMAT_RAW_PACKED) - f->plane_fmt[0].bytesperline = DIV_ROUND_UP(queue->width_pad * - queue->css_fmt->bytesperpixel_num, - IPU3_CSS_FORMAT_BPP_DEN); - else - /* For packed raw, alignment for bpl is by 50 to the width */ - f->plane_fmt[0].bytesperline = - DIV_ROUND_UP(f->width, - IPU3_CSS_FORMAT_BPP_DEN) * - queue->css_fmt->bytesperpixel_num; - + f->plane_fmt[0].bytesperline = + imgu_bytesperline(f->width, queue->css_fmt->frame_format); sizeimage = f->height * f->plane_fmt[0].bytesperline; if (queue->css_fmt->chroma_decim) sizeimage += 2 * sizeimage / queue->css_fmt->chroma_decim; diff --git a/drivers/staging/media/ipu3/ipu3-css.h b/drivers/staging/media/ipu3/ipu3-css.h index 6108a068b228..ab64e9521203 100644 --- a/drivers/staging/media/ipu3/ipu3-css.h +++ b/drivers/staging/media/ipu3/ipu3-css.h @@ -82,7 +82,6 @@ struct imgu_css_format { enum imgu_abi_bayer_order bayer_order; enum imgu_abi_osys_format osys_format; enum imgu_abi_osys_tiling osys_tiling; - u32 bytesperpixel_num; /* Bytes per pixel in first plane * 50 */ u8 bit_depth; /* Effective bits per pixel */ u8 chroma_decim; /* Chroma plane decimation, 0=no chroma plane */ u8 width_align; /* Alignment requirement for width_pad */ diff --git a/drivers/staging/media/ipu3/ipu3.h b/drivers/staging/media/ipu3/ipu3.h index eb46b527dd23..d2ad0a95c5aa 100644 --- a/drivers/staging/media/ipu3/ipu3.h +++ b/drivers/staging/media/ipu3/ipu3.h @@ -164,4 +164,16 @@ void imgu_v4l2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state); int imgu_s_stream(struct imgu_device *imgu, int enable); +static inline u32 imgu_bytesperline(const unsigned int width, + enum imgu_abi_frame_format frame_format) +{ + if (frame_format == IMGU_ABI_FRAME_FORMAT_NV12) + return ALIGN(width, IPU3_UAPI_ISP_VEC_ELEMS); + /* + * 64 bytes for every 50 pixels, the line length + * in bytes is multiple of 64 (line end alignment). + */ + return DIV_ROUND_UP(width, 50) * 64; +} + #endif -- cgit v1.2.3 From 6c0f6c424fcac470cb6f444a53d549d227f46910 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Thu, 7 Oct 2021 00:26:20 +0200 Subject: media: ipu3-imgu: Set valid initial format The initial format did not have a valid size. Fixes v4l2-compliance: fail: v4l2-test-formats.cpp(723): Video Output Multiplanar: TRY_FMT(G_FMT) != G_FMT test VIDIOC_TRY_FMT: FAIL Signed-off-by: Ricardo Ribalda Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/ipu3/ipu3-v4l2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c index b723186d2134..d9f7a854d68c 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -1136,7 +1136,9 @@ static int imgu_v4l2_node_setup(struct imgu_device *imgu, unsigned int pipe, def_pix_fmt.height = def_bus_fmt.height; def_pix_fmt.field = def_bus_fmt.field; def_pix_fmt.num_planes = 1; - def_pix_fmt.plane_fmt[0].bytesperline = def_pix_fmt.width * 2; + def_pix_fmt.plane_fmt[0].bytesperline = + imgu_bytesperline(def_pix_fmt.width, + IMGU_ABI_FRAME_FORMAT_RAW_PACKED); def_pix_fmt.plane_fmt[0].sizeimage = def_pix_fmt.height * def_pix_fmt.plane_fmt[0].bytesperline; def_pix_fmt.flags = 0; -- cgit v1.2.3 From 553481e38045f349bb9aa596d03bebd020020c9c Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Thu, 7 Oct 2021 00:26:21 +0200 Subject: media: ipu3-imgu: imgu_fmt: Handle properly try For a try_fmt call, the node noes not need to be enabled. Fixes v4l2-compliance fail: v4l2-test-formats.cpp(717): Video Output Multiplanar is valid, but no TRY_FMT was implemented test VIDIOC_TRY_FMT: FAIL Signed-off-by: Ricardo Ribalda Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/ipu3/ipu3-v4l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c index d9f7a854d68c..69ef820619ab 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -696,7 +696,7 @@ static int imgu_fmt(struct imgu_device *imgu, unsigned int pipe, int node, /* CSS expects some format on OUT queue */ if (i != IPU3_CSS_QUEUE_OUT && - !imgu_pipe->nodes[inode].enabled) { + !imgu_pipe->nodes[inode].enabled && !try) { fmts[i] = NULL; continue; } -- cgit v1.2.3 From ea2b9a33711604e91f8c826f4dcb3c12baa1990a Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Thu, 7 Oct 2021 00:26:22 +0200 Subject: media: ipu3-imgu: VIDIOC_QUERYCAP: Fix bus_info bus_info field had a different value for the media entity and the video device. Fixes v4l2-compliance: v4l2-compliance.cpp(637): media bus_info 'PCI:0000:00:05.0' differs from V4L2 bus_info 'PCI:viewfinder' Reviewed-by: Bingbu Cao Signed-off-by: Ricardo Ribalda Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/ipu3/ipu3-v4l2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c index 69ef820619ab..0473457b4e64 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -592,11 +592,12 @@ static const struct imgu_fmt *find_format(struct v4l2_format *f, u32 type) static int imgu_vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct imgu_video_device *node = file_to_intel_imgu_node(file); + struct imgu_device *imgu = video_drvdata(file); strscpy(cap->driver, IMGU_NAME, sizeof(cap->driver)); strscpy(cap->card, IMGU_NAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", node->name); + snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", + pci_name(imgu->pci_dev)); return 0; } -- cgit v1.2.3 From 98442bd098c28b576c111cc5f5d3cb40e0790e74 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Thu, 7 Oct 2021 00:26:23 +0200 Subject: media: dw9714: Add implementation for events Use v4l2 control API helpers to support the events. Fixes v4l2-compliance: test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL Signed-off-by: Ricardo Ribalda Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/dw9714.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/dw9714.c b/drivers/media/i2c/dw9714.c index c8b4292512dc..3863dfeb8293 100644 --- a/drivers/media/i2c/dw9714.c +++ b/drivers/media/i2c/dw9714.c @@ -7,6 +7,7 @@ #include #include #include +#include #define DW9714_NAME "dw9714" #define DW9714_MAX_FOCUS_POS 1023 @@ -100,7 +101,15 @@ static const struct v4l2_subdev_internal_ops dw9714_int_ops = { .close = dw9714_close, }; -static const struct v4l2_subdev_ops dw9714_ops = { }; +static const struct v4l2_subdev_core_ops dw9714_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_ops dw9714_ops = { + .core = &dw9714_core_ops, +}; static void dw9714_subdev_cleanup(struct dw9714_device *dw9714_dev) { @@ -137,7 +146,8 @@ static int dw9714_probe(struct i2c_client *client) return -ENOMEM; v4l2_i2c_subdev_init(&dw9714_dev->sd, client, &dw9714_ops); - dw9714_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dw9714_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; dw9714_dev->sd.internal_ops = &dw9714_int_ops; rval = dw9714_init_controls(dw9714_dev); -- cgit v1.2.3 From 5bd4098c3d92be0c0124cfc13bd2a11ba3c39323 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Thu, 7 Oct 2021 00:26:24 +0200 Subject: media: ov13858: Add implementation for events Use v4l2 control API helpers to support the events. Fixes v4l2-compliance: test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL Signed-off-by: Ricardo Ribalda Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov13858.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 7fc70af53e45..b4d22f5d9933 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #define OV13858_REG_VALUE_08BIT 1 @@ -1553,6 +1554,12 @@ static int ov13858_identify_module(struct ov13858 *ov13858) return 0; } +static const struct v4l2_subdev_core_ops ov13858_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + static const struct v4l2_subdev_video_ops ov13858_video_ops = { .s_stream = ov13858_set_stream, }; @@ -1569,6 +1576,7 @@ static const struct v4l2_subdev_sensor_ops ov13858_sensor_ops = { }; static const struct v4l2_subdev_ops ov13858_subdev_ops = { + .core = &ov13858_core_ops, .video = &ov13858_video_ops, .pad = &ov13858_pad_ops, .sensor = &ov13858_sensor_ops, @@ -1724,7 +1732,8 @@ static int ov13858_probe(struct i2c_client *client, /* Initialize subdev */ ov13858->sd.internal_ops = &ov13858_internal_ops; - ov13858->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov13858->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; ov13858->sd.entity.ops = &ov13858_subdev_entity_ops; ov13858->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; -- cgit v1.2.3 From dce6dd4493d613165cefefc52494043517c816b6 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Thu, 7 Oct 2021 00:26:25 +0200 Subject: media: ov5670: Add implementation for events Use v4l2 control API helpers to support the events. Fixes v4l2-compliance: test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL Signed-off-by: Ricardo Ribalda Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 49189926afd6..251f459ab484 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #define OV5670_REG_CHIP_ID 0x300a @@ -2420,6 +2421,12 @@ static int ov5670_identify_module(struct ov5670 *ov5670) return 0; } +static const struct v4l2_subdev_core_ops ov5670_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + static const struct v4l2_subdev_video_ops ov5670_video_ops = { .s_stream = ov5670_set_stream, }; @@ -2436,6 +2443,7 @@ static const struct v4l2_subdev_sensor_ops ov5670_sensor_ops = { }; static const struct v4l2_subdev_ops ov5670_subdev_ops = { + .core = &ov5670_core_ops, .video = &ov5670_video_ops, .pad = &ov5670_pad_ops, .sensor = &ov5670_sensor_ops, @@ -2489,7 +2497,8 @@ static int ov5670_probe(struct i2c_client *client) } ov5670->sd.internal_ops = &ov5670_internal_ops; - ov5670->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov5670->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; ov5670->sd.entity.ops = &ov5670_subdev_entity_ops; ov5670->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; -- cgit v1.2.3 From 57b660b22f1b3ae203eba620d0b87a9371c651cb Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 15 Sep 2021 13:56:00 +0200 Subject: media: mb86a20s: make arrays static const Don't populate the read-only arrays on the stack but instead them static const. Also makes the object code smaller by 154 bytes: Before: text data bss dec hex filename 42949 22424 0 65373 ff5d media/dvb-frontends/mb86a20s.o After: text data bss dec hex filename 42731 22488 0 65219 fec3 media/dvb-frontends/mb86a20s.o (gcc version 11.2.0) Signed-off-by: Colin Ian King Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index a7faf0cf8788..b74b9afed9a2 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -444,11 +444,11 @@ static int mb86a20s_get_interleaving(struct mb86a20s_state *state, unsigned layer) { int rc; - int interleaving[] = { + static const int interleaving[] = { 0, 1, 2, 4, 8 }; - static unsigned char reg[] = { + static const unsigned char reg[] = { [0] = 0x88, /* Layer A */ [1] = 0x8c, /* Layer B */ [2] = 0x90, /* Layer C */ -- cgit v1.2.3 From 69a10678e2fba3d182e78ea041f2d1b1a6058764 Mon Sep 17 00:00:00 2001 From: Evgeny Novikov Date: Sun, 22 Aug 2021 11:48:03 +0200 Subject: media: dvb-frontends: mn88443x: Handle errors of clk_prepare_enable() mn88443x_cmn_power_on() did not handle possible errors of clk_prepare_enable() and always finished successfully so that its caller mn88443x_probe() did not care about failed preparing/enabling of clocks as well. Add missed error handling in both mn88443x_cmn_power_on() and mn88443x_probe(). This required to change the return value of the former from "void" to "int". Found by Linux Driver Verification project (linuxtesting.org). Fixes: 0f408ce8941f ("media: dvb-frontends: add Socionext MN88443x ISDB-S/T demodulator driver") Signed-off-by: Evgeny Novikov Co-developed-by: Kirill Shilimanov Signed-off-by: Kirill Shilimanov Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mn88443x.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb-frontends/mn88443x.c b/drivers/media/dvb-frontends/mn88443x.c index e4528784f847..fff212c0bf3b 100644 --- a/drivers/media/dvb-frontends/mn88443x.c +++ b/drivers/media/dvb-frontends/mn88443x.c @@ -204,11 +204,18 @@ struct mn88443x_priv { struct regmap *regmap_t; }; -static void mn88443x_cmn_power_on(struct mn88443x_priv *chip) +static int mn88443x_cmn_power_on(struct mn88443x_priv *chip) { + struct device *dev = &chip->client_s->dev; struct regmap *r_t = chip->regmap_t; + int ret; - clk_prepare_enable(chip->mclk); + ret = clk_prepare_enable(chip->mclk); + if (ret) { + dev_err(dev, "Failed to prepare and enable mclk: %d\n", + ret); + return ret; + } gpiod_set_value_cansleep(chip->reset_gpio, 1); usleep_range(100, 1000); @@ -222,6 +229,8 @@ static void mn88443x_cmn_power_on(struct mn88443x_priv *chip) } else { regmap_write(r_t, HIZSET3, 0x8f); } + + return 0; } static void mn88443x_cmn_power_off(struct mn88443x_priv *chip) @@ -738,7 +747,10 @@ static int mn88443x_probe(struct i2c_client *client, chip->fe.demodulator_priv = chip; i2c_set_clientdata(client, chip); - mn88443x_cmn_power_on(chip); + ret = mn88443x_cmn_power_on(chip); + if (ret) + goto err_i2c_t; + mn88443x_s_sleep(chip); mn88443x_t_sleep(chip); -- cgit v1.2.3 From cefdc9510a16f59de6ff82ed90c841545ec0aa13 Mon Sep 17 00:00:00 2001 From: Nil Yi Date: Sat, 14 Aug 2021 11:40:09 +0200 Subject: media: rtl2832_sdr: clean the freed pointer and counter After freed the dev->urb_list, we should set it to NULL as well as set counter to zero. Requested-by: Sean Young Signed-off-by: Nil Yi Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832_sdr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 1a2f0d2adadf..6a4f2997d6f5 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -376,8 +376,11 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_dev *dev) dev_dbg(&pdev->dev, "alloc urb=%d\n", i); dev->urb_list[i] = usb_alloc_urb(0, GFP_KERNEL); if (!dev->urb_list[i]) { - for (j = 0; j < i; j++) + for (j = 0; j < i; j++) { usb_free_urb(dev->urb_list[j]); + dev->urb_list[j] = NULL; + } + dev->urbs_initialized = 0; return -ENOMEM; } usb_fill_bulk_urb(dev->urb_list[i], -- cgit v1.2.3 From 899a61a3305d49e8a712e9ab20d0db94bde5929f Mon Sep 17 00:00:00 2001 From: Anant Thazhemadam Date: Mon, 7 Dec 2020 07:16:06 +0100 Subject: media: usb: dvd-usb: fix uninit-value bug in dibusb_read_eeprom_byte() In dibusb_read_eeprom_byte(), if dibusb_i2c_msg() fails, val gets assigned an value that's not properly initialized. Using kzalloc() in place of kmalloc() for the buffer fixes this issue, as the val can now be set to 0 in the event dibusb_i2c_msg() fails. Reported-by: syzbot+e27b4fd589762b0b9329@syzkaller.appspotmail.com Tested-by: syzbot+e27b4fd589762b0b9329@syzkaller.appspotmail.com Signed-off-by: Anant Thazhemadam Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dibusb-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c index 02b51d1a1b67..aff60c10cb0b 100644 --- a/drivers/media/usb/dvb-usb/dibusb-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-common.c @@ -223,7 +223,7 @@ int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) u8 *buf; int rc; - buf = kmalloc(2, GFP_KERNEL); + buf = kzalloc(2, GFP_KERNEL); if (!buf) return -ENOMEM; -- cgit v1.2.3 From fd2eda71a47b095e81b9170c3f8b7ae82b04e785 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 7 Oct 2021 13:02:25 +0200 Subject: media: remove myself from dvb media maintainers I have not been able to give dvb the attention it needs, and now I have even less time. Of course I will continue to maintain rc-core (infrared). Unfortunately this means that dvb will have maintainance issues. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/maintainer-entry-profile.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/driver-api/media/maintainer-entry-profile.rst b/Documentation/driver-api/media/maintainer-entry-profile.rst index eb1cdfd280ba..ffc712a5f632 100644 --- a/Documentation/driver-api/media/maintainer-entry-profile.rst +++ b/Documentation/driver-api/media/maintainer-entry-profile.rst @@ -71,7 +71,7 @@ media maintainers do the review. The media maintainers that work on specific areas of the subsystem are: -- Digital TV and remote controllers: +- Remote Controllers (infrared): Sean Young - HDMI CEC: -- cgit v1.2.3 From fe47b6d7582ad1a608d8341c3e02c3e06f5678e6 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Fri, 2 Jul 2021 03:01:28 +0100 Subject: media: cedrus: fix double free If v4l2_ctrl_new_custom fails in cedrus_init_ctrls the error path will free ctx->ctrls, which is also freed in cedrus release. Fix this by setting ctx->ctrls to NULL instead of inadvertently removing kfree calls. Signed-off-by: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 9dd30cb568e8..c76fc97d97a0 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -259,6 +259,7 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx) v4l2_ctrl_handler_free(hdl); kfree(ctx->ctrls); + ctx->ctrls = NULL; return hdl->error; } -- cgit v1.2.3 From 112024a3b6dcfc62ec36ea0cf58b897f2ce54c59 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 14 Sep 2021 08:21:25 +0100 Subject: media: vidtv: move kfree(dvb) to vidtv_bridge_dev_release() Adding kfree(dvb) to vidtv_bridge_remove() will remove the memory too soon: if an application still has an open filehandle to the device when the driver is unloaded, then when that filehandle is closed, a use-after-free access takes place to the freed memory. Move the kfree(dvb) to vidtv_bridge_dev_release() instead. Signed-off-by: Hans Verkuil Fixes: 76e21bb8be4f ("media: vidtv: Fix memory leak in remove") Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vidtv/vidtv_bridge.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c index 0f6d998d18dc..82620613d56b 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c +++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c @@ -557,7 +557,6 @@ static int vidtv_bridge_remove(struct platform_device *pdev) dvb_dmxdev_release(&dvb->dmx_dev); dvb_dmx_release(&dvb->demux); dvb_unregister_adapter(&dvb->adapter); - kfree(dvb); dev_info(&pdev->dev, "Successfully removed vidtv\n"); return 0; @@ -565,6 +564,10 @@ static int vidtv_bridge_remove(struct platform_device *pdev) static void vidtv_bridge_dev_release(struct device *dev) { + struct vidtv_dvb *dvb; + + dvb = dev_get_drvdata(dev); + kfree(dvb); } static struct platform_device vidtv_bridge_dev = { -- cgit v1.2.3 From 570a82b9c36f76a5959b5e47900629b0d413931d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 20 Sep 2021 10:58:24 +0100 Subject: media: i2c: select V4L2_ASYNC where needed I came across a link failure from randconfig builds: x86_64-linux-ld: drivers/media/i2c/ths8200.o: in function `ths8200_remove': ths8200.c:(.text+0x491): undefined reference to `v4l2_async_unregister_subdev' x86_64-linux-ld: drivers/media/i2c/ths8200.o: in function `ths8200_probe': ths8200.c:(.text+0xe49): undefined reference to `v4l2_async_register_subdev' x86_64-linux-ld: drivers/media/i2c/tw9910.o: in function `tw9910_remove': tw9910.c:(.text+0x467): undefined reference to `v4l2_async_unregister_subdev' x86_64-linux-ld: drivers/media/i2c/tw9910.o: in function `tw9910_probe': tw9910.c:(.text+0x1123): undefined reference to `v4l2_async_register_subdev' These clearly lack a 'select' statement, but I don't know why this started happening only now. I had a bit of a look around to find other configs that have the same problem, but could not come up with a reliable way and found nothing else through experimentation. It is likely that other symbols like these exist that need an extra select. Signed-off-by: Arnd Bergmann Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 0e56489c97fb..d6a5d4ca439a 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -450,6 +450,7 @@ config VIDEO_TW9906 config VIDEO_TW9910 tristate "Techwell TW9910 video decoder" depends on VIDEO_V4L2 && I2C + select V4L2_ASYNC help Support for Techwell TW9910 NTSC/PAL/SECAM video decoder. @@ -611,6 +612,7 @@ menu "Video improvement chips" config VIDEO_UPD64031A tristate "NEC Electronics uPD64031A Ghost Reduction" depends on VIDEO_V4L2 && I2C + select V4L2_ASYNC help Support for the NEC Electronics uPD64031A Ghost Reduction video chip. It is most often found in NTSC TV cards made for -- cgit v1.2.3 From cd0e5e8c4281375f1aa94ff5fabe02963b025a71 Mon Sep 17 00:00:00 2001 From: Vladimir Barinov Date: Fri, 24 Sep 2021 14:51:38 +0100 Subject: media: rcar-vin: add G/S_PARM ioctls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds g/s_parm ioctls for parallel interface. Signed-off-by: Vladimir Barinov Signed-off-by: Nikita Yushchenko Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-v4l2.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index bdeff51bf768..a5bfa76fdac6 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -527,6 +527,24 @@ static int rvin_s_selection(struct file *file, void *fh, return 0; } +static int rvin_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) +{ + struct rvin_dev *vin = video_drvdata(file); + struct v4l2_subdev *sd = vin_to_source(vin); + + return v4l2_g_parm_cap(&vin->vdev, sd, parm); +} + +static int rvin_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) +{ + struct rvin_dev *vin = video_drvdata(file); + struct v4l2_subdev *sd = vin_to_source(vin); + + return v4l2_s_parm_cap(&vin->vdev, sd, parm); +} + static int rvin_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f) { @@ -743,6 +761,9 @@ static const struct v4l2_ioctl_ops rvin_ioctl_ops = { .vidioc_g_selection = rvin_g_selection, .vidioc_s_selection = rvin_s_selection, + .vidioc_g_parm = rvin_g_parm, + .vidioc_s_parm = rvin_s_parm, + .vidioc_g_pixelaspect = rvin_g_pixelaspect, .vidioc_enum_input = rvin_enum_input, -- cgit v1.2.3 From 67f85135c57c8ea20b5417b28ae65e53dc2ec2c3 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 28 Sep 2021 04:46:34 +0100 Subject: media: videobuf2: always set buffer vb2 pointer We need to always link allocated vb2_dc_buf back to vb2_buffer because we dereference vb2 in prepare() and finish() callbacks. Signed-off-by: Sergey Senozhatsky Tested-by: Chen-Yu Tsai Acked-by: Tomasz Figa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-dma-contig.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index b052a4e36961..38767791955d 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -600,6 +600,7 @@ static void *vb2_dc_get_userptr(struct vb2_buffer *vb, struct device *dev, buf->dev = dev; buf->dma_dir = vb->vb2_queue->dma_dir; + buf->vb = vb; offset = lower_32_bits(offset_in_page(vaddr)); vec = vb2_create_framevec(vaddr, size); @@ -788,6 +789,8 @@ static void *vb2_dc_attach_dmabuf(struct vb2_buffer *vb, struct device *dev, return ERR_PTR(-ENOMEM); buf->dev = dev; + buf->vb = vb; + /* create attachment for the dmabuf with the user device */ dba = dma_buf_attach(dbuf, buf->dev); if (IS_ERR(dba)) { -- cgit v1.2.3 From 52fed10ad7566ca8b59549c64bd3d2caa5c9c476 Mon Sep 17 00:00:00 2001 From: Jammy Huang Date: Fri, 1 Oct 2021 07:34:32 +0100 Subject: media: aspeed: add debugfs To show video real-time information as below: Capture: Signal : Unlock Width : 1920 Height : 1080 FRC : 30 Performance: Frame# : 0 Frame Duration(ms) : Now : 0 Min : 0 Max : 0 FPS : 0 [hverkuil: make aspeed_video_proc_open() static, fixes sparse warning] Signed-off-by: Jammy Huang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 100 ++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index ebb5e5af3b93..cad3f97515ae 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include #include @@ -201,6 +203,14 @@ struct aspeed_video_buffer { struct list_head link; }; +struct aspeed_video_perf { + ktime_t last_sample; + u32 totaltime; + u32 duration; + u32 duration_min; + u32 duration_max; +}; + #define to_aspeed_video_buffer(x) \ container_of((x), struct aspeed_video_buffer, vb) @@ -242,6 +252,8 @@ struct aspeed_video { unsigned int frame_left; unsigned int frame_right; unsigned int frame_top; + + struct aspeed_video_perf perf; }; #define to_aspeed_video(x) container_of((x), struct aspeed_video, v4l2_dev) @@ -465,6 +477,16 @@ static void aspeed_video_write(struct aspeed_video *video, u32 reg, u32 val) readl(video->base + reg)); } +static void update_perf(struct aspeed_video_perf *p) +{ + p->duration = + ktime_to_ms(ktime_sub(ktime_get(), p->last_sample)); + p->totaltime += p->duration; + + p->duration_max = max(p->duration, p->duration_max); + p->duration_min = min(p->duration, p->duration_min); +} + static int aspeed_video_start_frame(struct aspeed_video *video) { dma_addr_t addr; @@ -503,6 +525,8 @@ static int aspeed_video_start_frame(struct aspeed_video *video) aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, VE_INTERRUPT_COMP_COMPLETE); + video->perf.last_sample = ktime_get(); + aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP); @@ -618,6 +642,8 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) u32 frame_size = aspeed_video_read(video, video->comp_size_read); + update_perf(&video->perf); + spin_lock(&video->lock); clear_bit(VIDEO_FRAME_INPRG, &video->flags); buf = list_first_entry_or_null(&video->buffers, @@ -775,6 +801,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) det->width = MIN_WIDTH; det->height = MIN_HEIGHT; video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + memset(&video->perf, 0, sizeof(video->perf)); do { if (tries) { @@ -1465,6 +1492,8 @@ static int aspeed_video_start_streaming(struct vb2_queue *q, struct aspeed_video *video = vb2_get_drv_priv(q); video->sequence = 0; + video->perf.duration_max = 0; + video->perf.duration_min = 0xffffffff; rc = aspeed_video_start_frame(video); if (rc) { @@ -1532,6 +1561,71 @@ static const struct vb2_ops aspeed_video_vb2_ops = { .buf_queue = aspeed_video_buf_queue, }; +#ifdef CONFIG_DEBUG_FS +static int aspeed_video_debugfs_show(struct seq_file *s, void *data) +{ + struct aspeed_video *v = s->private; + + seq_puts(s, "\n"); + + seq_printf(s, " %-20s:\t%s\n", "Signal", + v->v4l2_input_status ? "Unlock" : "Lock"); + seq_printf(s, " %-20s:\t%d\n", "Width", v->pix_fmt.width); + seq_printf(s, " %-20s:\t%d\n", "Height", v->pix_fmt.height); + seq_printf(s, " %-20s:\t%d\n", "FRC", v->frame_rate); + + seq_puts(s, "\n"); + + seq_puts(s, "Performance:\n"); + seq_printf(s, " %-20s:\t%d\n", "Frame#", v->sequence); + seq_printf(s, " %-20s:\n", "Frame Duration(ms)"); + seq_printf(s, " %-18s:\t%d\n", "Now", v->perf.duration); + seq_printf(s, " %-18s:\t%d\n", "Min", v->perf.duration_min); + seq_printf(s, " %-18s:\t%d\n", "Max", v->perf.duration_max); + seq_printf(s, " %-20s:\t%d\n", "FPS", 1000 / (v->perf.totaltime / v->sequence)); + + return 0; +} + +static int aspeed_video_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, aspeed_video_debugfs_show, inode->i_private); +} + +static const struct file_operations aspeed_video_debugfs_ops = { + .owner = THIS_MODULE, + .open = aspeed_video_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct dentry *debugfs_entry; + +static void aspeed_video_debugfs_remove(struct aspeed_video *video) +{ + debugfs_remove_recursive(debugfs_entry); + debugfs_entry = NULL; +} + +static int aspeed_video_debugfs_create(struct aspeed_video *video) +{ + debugfs_entry = debugfs_create_file(DEVICE_NAME, 0444, NULL, + video, + &aspeed_video_debugfs_ops); + if (!debugfs_entry) + aspeed_video_debugfs_remove(video); + + return !debugfs_entry ? -EIO : 0; +} +#else +static void aspeed_video_debugfs_remove(struct aspeed_video *video) { } +static int aspeed_video_debugfs_create(struct aspeed_video *video) +{ + return 0; +} +#endif /* CONFIG_DEBUG_FS */ + static int aspeed_video_setup_video(struct aspeed_video *video) { const u64 mask = ~(BIT(V4L2_JPEG_CHROMA_SUBSAMPLING_444) | @@ -1736,6 +1830,10 @@ static int aspeed_video_probe(struct platform_device *pdev) return rc; } + rc = aspeed_video_debugfs_create(video); + if (rc) + dev_err(video->dev, "debugfs create failed\n"); + return 0; } @@ -1747,6 +1845,8 @@ static int aspeed_video_remove(struct platform_device *pdev) aspeed_video_off(video); + aspeed_video_debugfs_remove(video); + clk_unprepare(video->vclk); clk_unprepare(video->eclk); -- cgit v1.2.3 From 1cab969d55df67fc368f28918c1ec20126937867 Mon Sep 17 00:00:00 2001 From: Scott K Logan Date: Sun, 3 Oct 2021 01:08:26 +0100 Subject: media: saa7134: Add support for Leadtek WinFast HDTV200 H Similar configuration to Kworld PC150-U. Tested: Composite, S-Video, NTSC, ATSC Unsupported: IR remote Signed-off-by: Scott K Logan Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-cards.c | 53 +++++++++++++++++++++++++++++++ drivers/media/pci/saa7134/saa7134-dvb.c | 29 +++++++++++++++++ drivers/media/pci/saa7134/saa7134.h | 1 + 3 files changed, 83 insertions(+) diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index ce449c941171..0d82a4b27d5b 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c @@ -5765,6 +5765,33 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x0200000, }, }, + [SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H] = { + .name = "Leadtek Winfast HDTV200 H", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .ts_type = SAA7134_MPEG_TS_PARALLEL, + .gpiomask = 0x00200700, + .inputs = { { + .type = SAA7134_INPUT_TV, + .vmux = 1, + .amux = TV, + .gpio = 0x00000300, + }, { + .type = SAA7134_INPUT_COMPOSITE, + .vmux = 3, + .amux = LINE1, + .gpio = 0x00200300, + }, { + .type = SAA7134_INPUT_SVIDEO, + .vmux = 8, + .amux = LINE1, + .gpio = 0x00200300, + } }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -7040,6 +7067,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1779, /* V One Multimedia PTE Ltd */ .subdevice = 0x13cf, .driver_data = SAA7134_BOARD_SNAZIO_TVPVR_PRO, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x107d, + .subdevice = 0x6f2e, + .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H, }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -7245,6 +7278,22 @@ static int saa7134_kworld_pc150u_toggle_agc(struct saa7134_dev *dev, return 0; } +static int saa7134_leadtek_hdtv200h_toggle_agc(struct saa7134_dev *dev, + enum tda18271_mode mode) +{ + switch (mode) { + case TDA18271_ANALOG: + saa7134_set_gpio(dev, 10, 0); + break; + case TDA18271_DIGITAL: + saa7134_set_gpio(dev, 10, 1); + break; + default: + return -EINVAL; + } + return 0; +} + static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev, int command, int arg) { @@ -7264,6 +7313,9 @@ static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev, case SAA7134_BOARD_KWORLD_PC150U: ret = saa7134_kworld_pc150u_toggle_agc(dev, arg); break; + case SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H: + ret = saa7134_leadtek_hdtv200h_toggle_agc(dev, arg); + break; default: break; } @@ -7287,6 +7339,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev, case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: case SAA7134_BOARD_KWORLD_PC150U: case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2: + case SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H: /* tda8290 + tda18271 */ ret = saa7134_tda8290_18271_callback(dev, command, arg); break; diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c index f359cd5c006a..d17a1b15faee 100644 --- a/drivers/media/pci/saa7134/saa7134-dvb.c +++ b/drivers/media/pci/saa7134/saa7134-dvb.c @@ -1189,6 +1189,22 @@ static struct s5h1411_config kworld_s5h1411_config = { S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; +static struct tda18271_config hdtv200h_tda18271_config = { + .gate = TDA18271_GATE_ANALOG, + .config = 3 /* Use tuner callback for AGC */ +}; + +static struct s5h1411_config hdtv200h_s5h1411_config = { + .output_mode = S5H1411_PARALLEL_OUTPUT, + .gpio = S5H1411_GPIO_OFF, + .qam_if = S5H1411_IF_4000, + .vsb_if = S5H1411_IF_3250, + .inversion = S5H1411_INVERSION_ON, + .status_mode = S5H1411_DEMODLOCKING, + .mpeg_timing = + S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, +}; + /* ================================================================== * Core code @@ -1854,6 +1870,19 @@ static int dvb_init(struct saa7134_dev *dev) __func__); } break; + case SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H: + fe0->dvb.frontend = dvb_attach(s5h1411_attach, + &hdtv200h_s5h1411_config, + &dev->i2c_adap); + if (fe0->dvb.frontend) { + dvb_attach(tda829x_attach, fe0->dvb.frontend, + &dev->i2c_adap, 0x4b, + &tda829x_no_probe); + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_adap, + &hdtv200h_tda18271_config); + } + break; default: pr_warn("Huh? unknown DVB card?\n"); break; diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index d29499cd7370..49fe0f6bacba 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -328,6 +328,7 @@ struct saa7134_card_ir { #define SAA7134_BOARD_AVERMEDIA_505 194 #define SAA7134_BOARD_LEADTEK_WINFAST_TV2100_FM 195 #define SAA7134_BOARD_SNAZIO_TVPVR_PRO 196 +#define SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H 197 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3 From 3ae5c3bc07f602c7abbfad1c75f3d288851a9611 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Oct 2021 15:09:33 +0100 Subject: media: gspca/gl860-mi1320/ov9655: avoid -Wstring-concatenation warning Newer clang versions are suspicious of definitions that mix concatenated strings with comma-separated arrays of strings, this has found real bugs elsewhere, but this seems to be a false positive: drivers/media/usb/gspca/gl860/gl860-mi1320.c:62:37: error: suspicious concatenation of string literals in an array initialization; did you mean to separate the elements with a comma? [-Werror,-Wstring-concatenation] "\xd3\x02\xd4\x28\xd5\x01\xd0\x02" "\xd1\x18\xd2\xc1" ^ , drivers/media/usb/gspca/gl860/gl860-mi1320.c:62:2: note: place parentheses around the string literal to silence warning "\xd3\x02\xd4\x28\xd5\x01\xd0\x02" "\xd1\x18\xd2\xc1" Replace the string literals by compound initializers, using normal hex numbers. Signed-off-by: Hans Verkuil Reported-by: Arnd Bergmann Reviewed-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/gl860/gl860-mi1320.c | 87 +++++++++----- drivers/media/usb/gspca/gl860/gl860-ov9655.c | 169 +++++++++++++++++---------- 2 files changed, 166 insertions(+), 90 deletions(-) diff --git a/drivers/media/usb/gspca/gl860/gl860-mi1320.c b/drivers/media/usb/gspca/gl860/gl860-mi1320.c index 0749fe13160f..d6a540ed378c 100644 --- a/drivers/media/usb/gspca/gl860/gl860-mi1320.c +++ b/drivers/media/usb/gspca/gl860/gl860-mi1320.c @@ -50,42 +50,69 @@ static struct validx tbl_post_unset_alt[] = { }; static u8 *tbl_1280[] = { - "\x0d\x80\xf1\x08\x03\x04\xf1\x00" "\x04\x05\xf1\x02\x05\x00\xf1\xf1" - "\x06\x00\xf1\x0d\x20\x01\xf1\x00" "\x21\x84\xf1\x00\x0d\x00\xf1\x08" - "\xf0\x00\xf1\x01\x34\x00\xf1\x00" "\x9b\x43\xf1\x00\xa6\x05\xf1\x00" - "\xa9\x04\xf1\x00\xa1\x05\xf1\x00" "\xa4\x04\xf1\x00\xae\x0a\xf1\x08" - , - "\xf0\x00\xf1\x02\x3a\x05\xf1\xf1" "\x3c\x05\xf1\xf1\x59\x01\xf1\x47" - "\x5a\x01\xf1\x88\x5c\x0a\xf1\x06" "\x5d\x0e\xf1\x0a\x64\x5e\xf1\x1c" - "\xd2\x00\xf1\xcf\xcb\x00\xf1\x01" - , - "\xd3\x02\xd4\x28\xd5\x01\xd0\x02" "\xd1\x18\xd2\xc1" + (u8[]){ + 0x0d, 0x80, 0xf1, 0x08, 0x03, 0x04, 0xf1, 0x00, + 0x04, 0x05, 0xf1, 0x02, 0x05, 0x00, 0xf1, 0xf1, + 0x06, 0x00, 0xf1, 0x0d, 0x20, 0x01, 0xf1, 0x00, + 0x21, 0x84, 0xf1, 0x00, 0x0d, 0x00, 0xf1, 0x08, + 0xf0, 0x00, 0xf1, 0x01, 0x34, 0x00, 0xf1, 0x00, + 0x9b, 0x43, 0xf1, 0x00, 0xa6, 0x05, 0xf1, 0x00, + 0xa9, 0x04, 0xf1, 0x00, 0xa1, 0x05, 0xf1, 0x00, + 0xa4, 0x04, 0xf1, 0x00, 0xae, 0x0a, 0xf1, 0x08 + }, (u8[]){ + 0xf0, 0x00, 0xf1, 0x02, 0x3a, 0x05, 0xf1, 0xf1, + 0x3c, 0x05, 0xf1, 0xf1, 0x59, 0x01, 0xf1, 0x47, + 0x5a, 0x01, 0xf1, 0x88, 0x5c, 0x0a, 0xf1, 0x06, + 0x5d, 0x0e, 0xf1, 0x0a, 0x64, 0x5e, 0xf1, 0x1c, + 0xd2, 0x00, 0xf1, 0xcf, 0xcb, 0x00, 0xf1, 0x01 + }, (u8[]){ + 0xd3, 0x02, 0xd4, 0x28, 0xd5, 0x01, 0xd0, 0x02, + 0xd1, 0x18, 0xd2, 0xc1 + } }; static u8 *tbl_800[] = { - "\x0d\x80\xf1\x08\x03\x03\xf1\xc0" "\x04\x05\xf1\x02\x05\x00\xf1\xf1" - "\x06\x00\xf1\x0d\x20\x01\xf1\x00" "\x21\x84\xf1\x00\x0d\x00\xf1\x08" - "\xf0\x00\xf1\x01\x34\x00\xf1\x00" "\x9b\x43\xf1\x00\xa6\x05\xf1\x00" - "\xa9\x03\xf1\xc0\xa1\x03\xf1\x20" "\xa4\x02\xf1\x5a\xae\x0a\xf1\x08" - , - "\xf0\x00\xf1\x02\x3a\x05\xf1\xf1" "\x3c\x05\xf1\xf1\x59\x01\xf1\x47" - "\x5a\x01\xf1\x88\x5c\x0a\xf1\x06" "\x5d\x0e\xf1\x0a\x64\x5e\xf1\x1c" - "\xd2\x00\xf1\xcf\xcb\x00\xf1\x01" - , - "\xd3\x02\xd4\x18\xd5\x21\xd0\x02" "\xd1\x10\xd2\x59" + (u8[]){ + 0x0d, 0x80, 0xf1, 0x08, 0x03, 0x03, 0xf1, 0xc0, + 0x04, 0x05, 0xf1, 0x02, 0x05, 0x00, 0xf1, 0xf1, + 0x06, 0x00, 0xf1, 0x0d, 0x20, 0x01, 0xf1, 0x00, + 0x21, 0x84, 0xf1, 0x00, 0x0d, 0x00, 0xf1, 0x08, + 0xf0, 0x00, 0xf1, 0x01, 0x34, 0x00, 0xf1, 0x00, + 0x9b, 0x43, 0xf1, 0x00, 0xa6, 0x05, 0xf1, 0x00, + 0xa9, 0x03, 0xf1, 0xc0, 0xa1, 0x03, 0xf1, 0x20, + 0xa4, 0x02, 0xf1, 0x5a, 0xae, 0x0a, 0xf1, 0x08 + }, (u8[]){ + 0xf0, 0x00, 0xf1, 0x02, 0x3a, 0x05, 0xf1, 0xf1, + 0x3c, 0x05, 0xf1, 0xf1, 0x59, 0x01, 0xf1, 0x47, + 0x5a, 0x01, 0xf1, 0x88, 0x5c, 0x0a, 0xf1, 0x06, + 0x5d, 0x0e, 0xf1, 0x0a, 0x64, 0x5e, 0xf1, 0x1c, + 0xd2, 0x00, 0xf1, 0xcf, 0xcb, 0x00, 0xf1, 0x01 + }, (u8[]){ + 0xd3, 0x02, 0xd4, 0x18, 0xd5, 0x21, 0xd0, 0x02, + 0xd1, 0x10, 0xd2, 0x59 + } }; static u8 *tbl_640[] = { - "\x0d\x80\xf1\x08\x03\x04\xf1\x04" "\x04\x05\xf1\x02\x07\x01\xf1\x7c" - "\x08\x00\xf1\x0e\x21\x80\xf1\x00" "\x0d\x00\xf1\x08\xf0\x00\xf1\x01" - "\x34\x10\xf1\x10\x3a\x43\xf1\x00" "\xa6\x05\xf1\x02\xa9\x04\xf1\x04" - "\xa7\x02\xf1\x81\xaa\x01\xf1\xe2" "\xae\x0c\xf1\x09" - , - "\xf0\x00\xf1\x02\x39\x03\xf1\xfc" "\x3b\x04\xf1\x04\x57\x01\xf1\xb6" - "\x58\x02\xf1\x0d\x5c\x1f\xf1\x19" "\x5d\x24\xf1\x1e\x64\x5e\xf1\x1c" - "\xd2\x00\xf1\x00\xcb\x00\xf1\x01" - , - "\xd3\x02\xd4\x10\xd5\x81\xd0\x02" "\xd1\x08\xd2\xe1" + (u8[]){ + 0x0d, 0x80, 0xf1, 0x08, 0x03, 0x04, 0xf1, 0x04, + 0x04, 0x05, 0xf1, 0x02, 0x07, 0x01, 0xf1, 0x7c, + 0x08, 0x00, 0xf1, 0x0e, 0x21, 0x80, 0xf1, 0x00, + 0x0d, 0x00, 0xf1, 0x08, 0xf0, 0x00, 0xf1, 0x01, + 0x34, 0x10, 0xf1, 0x10, 0x3a, 0x43, 0xf1, 0x00, + 0xa6, 0x05, 0xf1, 0x02, 0xa9, 0x04, 0xf1, 0x04, + 0xa7, 0x02, 0xf1, 0x81, 0xaa, 0x01, 0xf1, 0xe2, + 0xae, 0x0c, 0xf1, 0x09 + }, (u8[]){ + 0xf0, 0x00, 0xf1, 0x02, 0x39, 0x03, 0xf1, 0xfc, + 0x3b, 0x04, 0xf1, 0x04, 0x57, 0x01, 0xf1, 0xb6, + 0x58, 0x02, 0xf1, 0x0d, 0x5c, 0x1f, 0xf1, 0x19, + 0x5d, 0x24, 0xf1, 0x1e, 0x64, 0x5e, 0xf1, 0x1c, + 0xd2, 0x00, 0xf1, 0x00, 0xcb, 0x00, 0xf1, 0x01 + }, (u8[]){ + 0xd3, 0x02, 0xd4, 0x10, 0xd5, 0x81, 0xd0, 0x02, + 0xd1, 0x08, 0xd2, 0xe1 + } }; static s32 tbl_sat[] = {0x25, 0x1d, 0x15, 0x0d, 0x05, 0x4d, 0x55, 0x5d, 0x2d}; diff --git a/drivers/media/usb/gspca/gl860/gl860-ov9655.c b/drivers/media/usb/gspca/gl860/gl860-ov9655.c index 59b87d066187..766677ebcb34 100644 --- a/drivers/media/usb/gspca/gl860/gl860-ov9655.c +++ b/drivers/media/usb/gspca/gl860/gl860-ov9655.c @@ -25,69 +25,118 @@ static struct validx tbl_commmon[] = { static s32 tbl_length[] = {12, 56, 52, 54, 56, 42, 32, 12}; static u8 *tbl_640[] = { - "\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01" - , - "\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x03\x0b\x57\x0e\x61" - "\x0f\x42\x11\x01\x12\x60\x13\x00" "\x14\x3a\x16\x24\x17\x14\x18\x00" - "\x19\x01\x1a\x3d\x1e\x04\x24\x3c" "\x25\x36\x26\x72\x27\x08\x28\x08" - "\x29\x15\x2a\x00\x2b\x00\x2c\x08" - , - "\x32\xff\x33\x00\x34\x3d\x35\x00" "\x36\xfa\x38\x72\x39\x57\x3a\x00" - "\x3b\x0c\x3d\x99\x3e\x0c\x3f\xc1" "\x40\xc0\x41\x00\x42\xc0\x43\x0a" - "\x44\xf0\x45\x46\x46\x62\x47\x2a" "\x48\x3c\x4a\xee\x4b\xe7\x4c\xe7" - "\x4d\xe7\x4e\xe7" - , - "\x4f\x98\x50\x98\x51\x00\x52\x28" "\x53\x70\x54\x98\x58\x1a\x59\x85" - "\x5a\xa9\x5b\x64\x5c\x84\x5d\x53" "\x5e\x0e\x5f\xf0\x60\xf0\x61\xf0" - "\x62\x00\x63\x00\x64\x02\x65\x20" "\x66\x00\x69\x0a\x6b\x5a\x6c\x04" - "\x6d\x55\x6e\x00\x6f\x9d" - , - "\x70\x15\x71\x78\x72\x00\x73\x00" "\x74\x3a\x75\x35\x76\x01\x77\x02" - "\x7a\x24\x7b\x04\x7c\x07\x7d\x10" "\x7e\x28\x7f\x36\x80\x44\x81\x52" - "\x82\x60\x83\x6c\x84\x78\x85\x8c" "\x86\x9e\x87\xbb\x88\xd2\x89\xe5" - "\x8a\x23\x8c\x8d\x90\x7c\x91\x7b" - , - "\x9d\x02\x9e\x02\x9f\x74\xa0\x73" "\xa1\x40\xa4\x50\xa5\x68\xa6\x70" - "\xa8\xc1\xa9\xef\xaa\x92\xab\x04" "\xac\x80\xad\x80\xae\x80\xaf\x80" - "\xb2\xf2\xb3\x20\xb4\x20\xb5\x00" "\xb6\xaf" - , - "\xbb\xae\xbc\x4f\xbd\x4e\xbe\x6a" "\xbf\x68\xc0\xaa\xc1\xc0\xc2\x01" - "\xc3\x4e\xc6\x85\xc7\x81\xc9\xe0" "\xca\xe8\xcb\xf0\xcc\xd8\xcd\x93" - , - "\xd0\x01\xd1\x08\xd2\xe0\xd3\x01" "\xd4\x10\xd5\x80" + (u8[]){ + 0x00, 0x40, 0x07, 0x6a, 0x06, 0xf3, 0x0d, 0x6a, + 0x10, 0x10, 0xc1, 0x01 + }, (u8[]){ + 0x12, 0x80, 0x00, 0x00, 0x01, 0x98, 0x02, 0x80, + 0x03, 0x12, 0x04, 0x03, 0x0b, 0x57, 0x0e, 0x61, + 0x0f, 0x42, 0x11, 0x01, 0x12, 0x60, 0x13, 0x00, + 0x14, 0x3a, 0x16, 0x24, 0x17, 0x14, 0x18, 0x00, + 0x19, 0x01, 0x1a, 0x3d, 0x1e, 0x04, 0x24, 0x3c, + 0x25, 0x36, 0x26, 0x72, 0x27, 0x08, 0x28, 0x08, + 0x29, 0x15, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x08 + }, (u8[]){ + 0x32, 0xff, 0x33, 0x00, 0x34, 0x3d, 0x35, 0x00, + 0x36, 0xfa, 0x38, 0x72, 0x39, 0x57, 0x3a, 0x00, + 0x3b, 0x0c, 0x3d, 0x99, 0x3e, 0x0c, 0x3f, 0xc1, + 0x40, 0xc0, 0x41, 0x00, 0x42, 0xc0, 0x43, 0x0a, + 0x44, 0xf0, 0x45, 0x46, 0x46, 0x62, 0x47, 0x2a, + 0x48, 0x3c, 0x4a, 0xee, 0x4b, 0xe7, 0x4c, 0xe7, + 0x4d, 0xe7, 0x4e, 0xe7 + }, (u8[]){ + 0x4f, 0x98, 0x50, 0x98, 0x51, 0x00, 0x52, 0x28, + 0x53, 0x70, 0x54, 0x98, 0x58, 0x1a, 0x59, 0x85, + 0x5a, 0xa9, 0x5b, 0x64, 0x5c, 0x84, 0x5d, 0x53, + 0x5e, 0x0e, 0x5f, 0xf0, 0x60, 0xf0, 0x61, 0xf0, + 0x62, 0x00, 0x63, 0x00, 0x64, 0x02, 0x65, 0x20, + 0x66, 0x00, 0x69, 0x0a, 0x6b, 0x5a, 0x6c, 0x04, + 0x6d, 0x55, 0x6e, 0x00, 0x6f, 0x9d + }, (u8[]){ + 0x70, 0x15, 0x71, 0x78, 0x72, 0x00, 0x73, 0x00, + 0x74, 0x3a, 0x75, 0x35, 0x76, 0x01, 0x77, 0x02, + 0x7a, 0x24, 0x7b, 0x04, 0x7c, 0x07, 0x7d, 0x10, + 0x7e, 0x28, 0x7f, 0x36, 0x80, 0x44, 0x81, 0x52, + 0x82, 0x60, 0x83, 0x6c, 0x84, 0x78, 0x85, 0x8c, + 0x86, 0x9e, 0x87, 0xbb, 0x88, 0xd2, 0x89, 0xe5, + 0x8a, 0x23, 0x8c, 0x8d, 0x90, 0x7c, 0x91, 0x7b + }, (u8[]){ + 0x9d, 0x02, 0x9e, 0x02, 0x9f, 0x74, 0xa0, 0x73, + 0xa1, 0x40, 0xa4, 0x50, 0xa5, 0x68, 0xa6, 0x70, + 0xa8, 0xc1, 0xa9, 0xef, 0xaa, 0x92, 0xab, 0x04, + 0xac, 0x80, 0xad, 0x80, 0xae, 0x80, 0xaf, 0x80, + 0xb2, 0xf2, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x00, + 0xb6, 0xaf + }, (u8[]){ + 0xbb, 0xae, 0xbc, 0x4f, 0xbd, 0x4e, 0xbe, 0x6a, + 0xbf, 0x68, 0xc0, 0xaa, 0xc1, 0xc0, 0xc2, 0x01, + 0xc3, 0x4e, 0xc6, 0x85, 0xc7, 0x81, 0xc9, 0xe0, + 0xca, 0xe8, 0xcb, 0xf0, 0xcc, 0xd8, 0xcd, 0x93 + }, (u8[]){ + 0xd0, 0x01, 0xd1, 0x08, 0xd2, 0xe0, 0xd3, 0x01, + 0xd4, 0x10, 0xd5, 0x80 + } }; static u8 *tbl_1280[] = { - "\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01" - , - "\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x01\x0b\x57\x0e\x61" - "\x0f\x42\x11\x00\x12\x00\x13\x00" "\x14\x3a\x16\x24\x17\x1b\x18\xbb" - "\x19\x01\x1a\x81\x1e\x04\x24\x3c" "\x25\x36\x26\x72\x27\x08\x28\x08" - "\x29\x15\x2a\x00\x2b\x00\x2c\x08" - , - "\x32\xa4\x33\x00\x34\x3d\x35\x00" "\x36\xf8\x38\x72\x39\x57\x3a\x00" - "\x3b\x0c\x3d\x99\x3e\x0c\x3f\xc2" "\x40\xc0\x41\x00\x42\xc0\x43\x0a" - "\x44\xf0\x45\x46\x46\x62\x47\x2a" "\x48\x3c\x4a\xec\x4b\xe8\x4c\xe8" - "\x4d\xe8\x4e\xe8" - , - "\x4f\x98\x50\x98\x51\x00\x52\x28" "\x53\x70\x54\x98\x58\x1a\x59\x85" - "\x5a\xa9\x5b\x64\x5c\x84\x5d\x53" "\x5e\x0e\x5f\xf0\x60\xf0\x61\xf0" - "\x62\x00\x63\x00\x64\x02\x65\x20" "\x66\x00\x69\x02\x6b\x5a\x6c\x04" - "\x6d\x55\x6e\x00\x6f\x9d" - , - "\x70\x08\x71\x78\x72\x00\x73\x01" "\x74\x3a\x75\x35\x76\x01\x77\x02" - "\x7a\x24\x7b\x04\x7c\x07\x7d\x10" "\x7e\x28\x7f\x36\x80\x44\x81\x52" - "\x82\x60\x83\x6c\x84\x78\x85\x8c" "\x86\x9e\x87\xbb\x88\xd2\x89\xe5" - "\x8a\x23\x8c\x0d\x90\x90\x91\x90" - , - "\x9d\x02\x9e\x02\x9f\x94\xa0\x94" "\xa1\x01\xa4\x50\xa5\x68\xa6\x70" - "\xa8\xc1\xa9\xef\xaa\x92\xab\x04" "\xac\x80\xad\x80\xae\x80\xaf\x80" - "\xb2\xf2\xb3\x20\xb4\x20\xb5\x00" "\xb6\xaf" - , - "\xbb\xae\xbc\x38\xbd\x39\xbe\x01" "\xbf\x01\xc0\xe2\xc1\xc0\xc2\x01" - "\xc3\x4e\xc6\x85\xc7\x81\xc9\xe0" "\xca\xe8\xcb\xf0\xcc\xd8\xcd\x93" - , - "\xd0\x21\xd1\x18\xd2\xe0\xd3\x01" "\xd4\x28\xd5\x00" + (u8[]){ + 0x00, 0x40, 0x07, 0x6a, 0x06, 0xf3, 0x0d, 0x6a, + 0x10, 0x10, 0xc1, 0x01 + }, + (u8[]){ + 0x12, 0x80, 0x00, 0x00, 0x01, 0x98, 0x02, 0x80, + 0x03, 0x12, 0x04, 0x01, 0x0b, 0x57, 0x0e, 0x61, + 0x0f, 0x42, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, + 0x14, 0x3a, 0x16, 0x24, 0x17, 0x1b, 0x18, 0xbb, + 0x19, 0x01, 0x1a, 0x81, 0x1e, 0x04, 0x24, 0x3c, + 0x25, 0x36, 0x26, 0x72, 0x27, 0x08, 0x28, 0x08, + 0x29, 0x15, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x08 + }, + (u8[]){ + 0x32, 0xa4, 0x33, 0x00, 0x34, 0x3d, 0x35, 0x00, + 0x36, 0xf8, 0x38, 0x72, 0x39, 0x57, 0x3a, 0x00, + 0x3b, 0x0c, 0x3d, 0x99, 0x3e, 0x0c, 0x3f, 0xc2, + 0x40, 0xc0, 0x41, 0x00, 0x42, 0xc0, 0x43, 0x0a, + 0x44, 0xf0, 0x45, 0x46, 0x46, 0x62, 0x47, 0x2a, + 0x48, 0x3c, 0x4a, 0xec, 0x4b, 0xe8, 0x4c, 0xe8, + 0x4d, 0xe8, 0x4e, 0xe8 + }, + (u8[]){ + 0x4f, 0x98, 0x50, 0x98, 0x51, 0x00, 0x52, 0x28, + 0x53, 0x70, 0x54, 0x98, 0x58, 0x1a, 0x59, 0x85, + 0x5a, 0xa9, 0x5b, 0x64, 0x5c, 0x84, 0x5d, 0x53, + 0x5e, 0x0e, 0x5f, 0xf0, 0x60, 0xf0, 0x61, 0xf0, + 0x62, 0x00, 0x63, 0x00, 0x64, 0x02, 0x65, 0x20, + 0x66, 0x00, 0x69, 0x02, 0x6b, 0x5a, 0x6c, 0x04, + 0x6d, 0x55, 0x6e, 0x00, 0x6f, 0x9d + }, + (u8[]){ + 0x70, 0x08, 0x71, 0x78, 0x72, 0x00, 0x73, 0x01, + 0x74, 0x3a, 0x75, 0x35, 0x76, 0x01, 0x77, 0x02, + 0x7a, 0x24, 0x7b, 0x04, 0x7c, 0x07, 0x7d, 0x10, + 0x7e, 0x28, 0x7f, 0x36, 0x80, 0x44, 0x81, 0x52, + 0x82, 0x60, 0x83, 0x6c, 0x84, 0x78, 0x85, 0x8c, + 0x86, 0x9e, 0x87, 0xbb, 0x88, 0xd2, 0x89, 0xe5, + 0x8a, 0x23, 0x8c, 0x0d, 0x90, 0x90, 0x91, 0x90 + }, + (u8[]){ + 0x9d, 0x02, 0x9e, 0x02, 0x9f, 0x94, 0xa0, 0x94, + 0xa1, 0x01, 0xa4, 0x50, 0xa5, 0x68, 0xa6, 0x70, + 0xa8, 0xc1, 0xa9, 0xef, 0xaa, 0x92, 0xab, 0x04, + 0xac, 0x80, 0xad, 0x80, 0xae, 0x80, 0xaf, 0x80, + 0xb2, 0xf2, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x00, + 0xb6, 0xaf + }, + (u8[]){ + 0xbb, 0xae, 0xbc, 0x38, 0xbd, 0x39, 0xbe, 0x01, + 0xbf, 0x01, 0xc0, 0xe2, 0xc1, 0xc0, 0xc2, 0x01, + 0xc3, 0x4e, 0xc6, 0x85, 0xc7, 0x81, 0xc9, 0xe0, + 0xca, 0xe8, 0xcb, 0xf0, 0xcc, 0xd8, 0xcd, 0x93 + }, + (u8[]){ + 0xd0, 0x21, 0xd1, 0x18, 0xd2, 0xe0, 0xd3, 0x01, + 0xd4, 0x28, 0xd5, 0x00 + } }; static u8 c04[] = {0x04}; -- cgit v1.2.3 From d64a7709a81c298761aadc9690c110ee3fcc675a Mon Sep 17 00:00:00 2001 From: Krzysztof Hałasa Date: Wed, 6 Oct 2021 06:30:19 +0100 Subject: media: TDA1997x: replace video detection routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TDA1997x (HDMI receiver) driver currently uses a specific video format detection scheme. The frame (or field in interlaced mode), line and HSync pulse durations are compared to those of known, standard video modes. If a match is found, the mode is assumed to be detected, otherwise -ERANGE is returned (then possibly ignored). This means that: - another mode with similar timings will be detected incorrectly (e.g. 2x faster clock and lines twice as long) - non-standard modes will not work. This patch replaces this scheme with a direct read of geometry registers. This way all modes recognized by the chip are supported. In interlaced modes, the code assumes the V sync signal has the same duration for both fields. While this may be not necessarily true, I can't see any way to get the "other" V sync width. This is most probably harmless. All tests have been performed on Gateworks' Ventana GW54xx board, with a TDA19971 chip. Signed-off-by: Krzysztof Hałasa Tested-by: Tim Harvey Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda1997x.c | 119 +++++++++++++++++++++----------------- drivers/media/i2c/tda1997x_regs.h | 3 + 2 files changed, 70 insertions(+), 52 deletions(-) diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 0b995424cb34..8fafce26d62f 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -1092,67 +1092,82 @@ tda1997x_detect_std(struct tda1997x_state *state, struct v4l2_dv_timings *timings) { struct v4l2_subdev *sd = &state->sd; - u32 vper; - u16 hper; - u16 hsper; - int i; /* * Read the FMT registers - * REG_V_PER: Period of a frame (or two fields) in MCLK(27MHz) cycles - * REG_H_PER: Period of a line in MCLK(27MHz) cycles - * REG_HS_WIDTH: Period of horiz sync pulse in MCLK(27MHz) cycles + * REG_V_PER: Period of a frame (or field) in MCLK (27MHz) cycles + * REG_H_PER: Period of a line in MCLK (27MHz) cycles + * REG_HS_WIDTH: Period of horiz sync pulse in MCLK (27MHz) cycles */ - vper = io_read24(sd, REG_V_PER) & MASK_VPER; - hper = io_read16(sd, REG_H_PER) & MASK_HPER; - hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH; - v4l2_dbg(1, debug, sd, "Signal Timings: %u/%u/%u\n", vper, hper, hsper); + u32 vper, vsync_pos; + u16 hper, hsync_pos, hsper, interlaced; + u16 htot, hact, hfront, hsync, hback; + u16 vtot, vact, vfront1, vfront2, vsync, vback1, vback2; if (!state->input_detect[0] && !state->input_detect[1]) return -ENOLINK; - for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) { - const struct v4l2_bt_timings *bt; - u32 lines, width, _hper, _hsper; - u32 vmin, vmax, hmin, hmax, hsmin, hsmax; - bool vmatch, hmatch, hsmatch; - - bt = &v4l2_dv_timings_presets[i].bt; - width = V4L2_DV_BT_FRAME_WIDTH(bt); - lines = V4L2_DV_BT_FRAME_HEIGHT(bt); - _hper = (u32)bt->pixelclock / width; - if (bt->interlaced) - lines /= 2; - /* vper +/- 0.7% */ - vmin = ((27000000 / 1000) * 993) / _hper * lines; - vmax = ((27000000 / 1000) * 1007) / _hper * lines; - /* hper +/- 1.0% */ - hmin = ((27000000 / 100) * 99) / _hper; - hmax = ((27000000 / 100) * 101) / _hper; - /* hsper +/- 2 (take care to avoid 32bit overflow) */ - _hsper = 27000 * bt->hsync / ((u32)bt->pixelclock/1000); - hsmin = _hsper - 2; - hsmax = _hsper + 2; - - /* vmatch matches the framerate */ - vmatch = ((vper <= vmax) && (vper >= vmin)) ? 1 : 0; - /* hmatch matches the width */ - hmatch = ((hper <= hmax) && (hper >= hmin)) ? 1 : 0; - /* hsmatch matches the hswidth */ - hsmatch = ((hsper <= hsmax) && (hsper >= hsmin)) ? 1 : 0; - if (hmatch && vmatch && hsmatch) { - v4l2_print_dv_timings(sd->name, "Detected format: ", - &v4l2_dv_timings_presets[i], - false); - if (timings) - *timings = v4l2_dv_timings_presets[i]; - return 0; - } - } + vper = io_read24(sd, REG_V_PER); + hper = io_read16(sd, REG_H_PER); + hsper = io_read16(sd, REG_HS_WIDTH); + vsync_pos = vper & MASK_VPER_SYNC_POS; + hsync_pos = hper & MASK_HPER_SYNC_POS; + interlaced = hsper & MASK_HSWIDTH_INTERLACED; + vper &= MASK_VPER; + hper &= MASK_HPER; + hsper &= MASK_HSWIDTH; + v4l2_dbg(1, debug, sd, "Signal Timings: %u/%u/%u\n", vper, hper, hsper); - v4l_err(state->client, "no resolution match for timings: %d/%d/%d\n", - vper, hper, hsper); - return -ERANGE; + htot = io_read16(sd, REG_FMT_H_TOT); + hact = io_read16(sd, REG_FMT_H_ACT); + hfront = io_read16(sd, REG_FMT_H_FRONT); + hsync = io_read16(sd, REG_FMT_H_SYNC); + hback = io_read16(sd, REG_FMT_H_BACK); + + vtot = io_read16(sd, REG_FMT_V_TOT); + vact = io_read16(sd, REG_FMT_V_ACT); + vfront1 = io_read(sd, REG_FMT_V_FRONT_F1); + vfront2 = io_read(sd, REG_FMT_V_FRONT_F2); + vsync = io_read(sd, REG_FMT_V_SYNC); + vback1 = io_read(sd, REG_FMT_V_BACK_F1); + vback2 = io_read(sd, REG_FMT_V_BACK_F2); + + v4l2_dbg(1, debug, sd, "Geometry: H %u %u %u %u %u Sync%c V %u %u %u %u %u %u %u Sync%c\n", + htot, hact, hfront, hsync, hback, hsync_pos ? '+' : '-', + vtot, vact, vfront1, vfront2, vsync, vback1, vback2, vsync_pos ? '+' : '-'); + + if (!timings) + return 0; + + timings->type = V4L2_DV_BT_656_1120; + timings->bt.width = hact; + timings->bt.hfrontporch = hfront; + timings->bt.hsync = hsync; + timings->bt.hbackporch = hback; + timings->bt.height = vact; + timings->bt.vfrontporch = vfront1; + timings->bt.vsync = vsync; + timings->bt.vbackporch = vback1; + timings->bt.interlaced = interlaced ? V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; + timings->bt.polarities = vsync_pos ? V4L2_DV_VSYNC_POS_POL : 0; + timings->bt.polarities |= hsync_pos ? V4L2_DV_HSYNC_POS_POL : 0; + + timings->bt.pixelclock = (u64)htot * vtot * 27000000; + if (interlaced) { + timings->bt.il_vfrontporch = vfront2; + timings->bt.il_vsync = timings->bt.vsync; + timings->bt.il_vbackporch = vback2; + do_div(timings->bt.pixelclock, vper * 2 /* full frame */); + } else { + timings->bt.il_vfrontporch = 0; + timings->bt.il_vsync = 0; + timings->bt.il_vbackporch = 0; + do_div(timings->bt.pixelclock, vper); + } + v4l2_find_dv_timings_cap(timings, &tda1997x_dv_timings_cap, + (u32)timings->bt.pixelclock / 500, NULL, NULL); + v4l2_print_dv_timings(sd->name, "Detected format: ", timings, false); + return 0; } /* some sort of errata workaround for chip revision 0 (N1) */ diff --git a/drivers/media/i2c/tda1997x_regs.h b/drivers/media/i2c/tda1997x_regs.h index d9b3daada07d..115371ba33f0 100644 --- a/drivers/media/i2c/tda1997x_regs.h +++ b/drivers/media/i2c/tda1997x_regs.h @@ -117,9 +117,12 @@ #define REG_CURPAGE_00H 0xFF #define MASK_VPER 0x3fffff +#define MASK_VPER_SYNC_POS 0x800000 #define MASK_VHREF 0x3fff #define MASK_HPER 0x0fff +#define MASK_HPER_SYNC_POS 0x8000 #define MASK_HSWIDTH 0x03ff +#define MASK_HSWIDTH_INTERLACED 0x8000 /* HPD Detection */ #define DETECT_UTIL BIT(7) /* utility of HDMI level */ -- cgit v1.2.3 From 901a52c4335996b3896da381a21182e2f9a19ed2 Mon Sep 17 00:00:00 2001 From: Krzysztof Hałasa Date: Wed, 6 Oct 2021 06:45:38 +0100 Subject: media: Add ADV7610 support for adv7604 driver - DT docs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADV7610 is another HDMI receiver chip, very similar to the ADV7611. Tested on TinyRex BaseBoard Lite. Signed-off-by: Krzysztof Hałasa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/adv7604.yaml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.yaml b/Documentation/devicetree/bindings/media/i2c/adv7604.yaml index de15cebe2955..c19d8391e2d5 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7604.yaml +++ b/Documentation/devicetree/bindings/media/i2c/adv7604.yaml @@ -4,23 +4,24 @@ $id: http://devicetree.org/schemas/media/i2c/adv7604.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Analog Devices ADV7604/11/12 video decoder with HDMI receiver +title: Analog Devices ADV7604/10/11/12 video decoder with HDMI receiver maintainers: - Hans Verkuil description: - The ADV7604 and ADV7611/12 are multiformat video decoders with an integrated - HDMI receiver. The ADV7604 has four multiplexed HDMI inputs and one analog - input, and the ADV7611 has one HDMI input and no analog input. The 7612 is - similar to the 7611 but has 2 HDMI inputs. + The ADV7604 and ADV7610/11/12 are multiformat video decoders with + an integrated HDMI receiver. The ADV7604 has four multiplexed HDMI inputs + and one analog input, and the ADV7610/11 have one HDMI input and no analog + input. The ADV7612 is similar to the ADV7610/11 but has 2 HDMI inputs. - These device tree bindings support the ADV7611/12 only at the moment. + These device tree bindings support the ADV7610/11/12 only at the moment. properties: compatible: items: - enum: + - adi,adv7610 - adi,adv7611 - adi,adv7612 -- cgit v1.2.3 From c2c88a07d679839ddf236db55b258aaedff819ad Mon Sep 17 00:00:00 2001 From: Krzysztof Hałasa Date: Wed, 6 Oct 2021 06:49:48 +0100 Subject: media: Add ADV7610 support for adv7604 driver. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADV7610 is another HDMI receiver chip, very similar to the ADV7611. Also: print chip names in upper case. Fix an error message claiming that no ADV761x has been found, while in reality a chip different than requested (though still supported) may have been found. Tested on TinyRex BaseBoard Lite. Signed-off-by: Krzysztof Hałasa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 122e1fdccd96..44768b59a6ff 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -41,7 +41,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-2)"); -MODULE_DESCRIPTION("Analog Devices ADV7604 video decoder driver"); +MODULE_DESCRIPTION("Analog Devices ADV7604/10/11/12 video decoder driver"); MODULE_AUTHOR("Hans Verkuil "); MODULE_AUTHOR("Mats Randgaard "); MODULE_LICENSE("GPL"); @@ -77,7 +77,7 @@ MODULE_LICENSE("GPL"); enum adv76xx_type { ADV7604, - ADV7611, + ADV7611, // including ADV7610 ADV7612, }; @@ -3176,6 +3176,7 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = { static const struct i2c_device_id adv76xx_i2c_id[] = { { "adv7604", (kernel_ulong_t)&adv76xx_chip_info[ADV7604] }, + { "adv7610", (kernel_ulong_t)&adv76xx_chip_info[ADV7611] }, { "adv7611", (kernel_ulong_t)&adv76xx_chip_info[ADV7611] }, { "adv7612", (kernel_ulong_t)&adv76xx_chip_info[ADV7612] }, { } @@ -3183,6 +3184,7 @@ static const struct i2c_device_id adv76xx_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, adv76xx_i2c_id); static const struct of_device_id adv76xx_of_id[] __maybe_unused = { + { .compatible = "adi,adv7610", .data = &adv76xx_chip_info[ADV7611] }, { .compatible = "adi,adv7611", .data = &adv76xx_chip_info[ADV7611] }, { .compatible = "adi,adv7612", .data = &adv76xx_chip_info[ADV7612] }, { } @@ -3500,8 +3502,8 @@ static int adv76xx_probe(struct i2c_client *client, return -ENODEV; } if (val != 0x68) { - v4l2_err(sd, "not an adv7604 on address 0x%x\n", - client->addr << 1); + v4l2_err(sd, "not an ADV7604 on address 0x%x\n", + client->addr << 1); return -ENODEV; } break; @@ -3525,8 +3527,9 @@ static int adv76xx_probe(struct i2c_client *client, val |= val2; if ((state->info->type == ADV7611 && val != 0x2051) || (state->info->type == ADV7612 && val != 0x2041)) { - v4l2_err(sd, "not an adv761x on address 0x%x\n", - client->addr << 1); + v4l2_err(sd, "not an %s on address 0x%x\n", + state->info->type == ADV7611 ? "ADV7610/11" : "ADV7612", + client->addr << 1); return -ENODEV; } break; -- cgit v1.2.3 From 48289036e8c7847d49a1c7086d07b8793d066e96 Mon Sep 17 00:00:00 2001 From: Krzysztof Hałasa Date: Wed, 6 Oct 2021 07:13:48 +0100 Subject: media: i.MX6: Support 16-bit BT.1120 video input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Confirmed to work with ADV7610 HDMI receiver. Signed-off-by: Krzysztof Hałasa Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/gpu/ipu-v3/ipu-csi.c | 31 ++++++++++++++++++++++++++----- drivers/staging/media/imx/imx-media-csi.c | 5 +++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c index 8ae301eef643..a9639d098893 100644 --- a/drivers/gpu/ipu-v3/ipu-csi.c +++ b/drivers/gpu/ipu-v3/ipu-csi.c @@ -259,10 +259,24 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code, cfg->data_width = IPU_CSI_DATA_WIDTH_8; break; case MEDIA_BUS_FMT_UYVY8_1X16: + if (mbus_type == V4L2_MBUS_BT656) { + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY; + cfg->data_width = IPU_CSI_DATA_WIDTH_8; + } else { + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; + cfg->data_width = IPU_CSI_DATA_WIDTH_16; + } + cfg->mipi_dt = MIPI_DT_YUV422; + break; case MEDIA_BUS_FMT_YUYV8_1X16: - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; + if (mbus_type == V4L2_MBUS_BT656) { + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV; + cfg->data_width = IPU_CSI_DATA_WIDTH_8; + } else { + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; + cfg->data_width = IPU_CSI_DATA_WIDTH_16; + } cfg->mipi_dt = MIPI_DT_YUV422; - cfg->data_width = IPU_CSI_DATA_WIDTH_16; break; case MEDIA_BUS_FMT_SBGGR8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: @@ -332,7 +346,7 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, const struct v4l2_mbus_config *mbus_cfg, const struct v4l2_mbus_framefmt *mbus_fmt) { - int ret; + int ret, is_bt1120; memset(csicfg, 0, sizeof(*csicfg)); @@ -353,11 +367,18 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, break; case V4L2_MBUS_BT656: csicfg->ext_vsync = 0; + /* UYVY10_1X20 etc. should be supported as well */ + is_bt1120 = mbus_fmt->code == MEDIA_BUS_FMT_UYVY8_1X16 || + mbus_fmt->code == MEDIA_BUS_FMT_YUYV8_1X16; if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) || mbus_fmt->field == V4L2_FIELD_ALTERNATE) - csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED; + csicfg->clk_mode = is_bt1120 ? + IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR : + IPU_CSI_CLK_MODE_CCIR656_INTERLACED; else - csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE; + csicfg->clk_mode = is_bt1120 ? + IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR : + IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE; break; case V4L2_MBUS_CSI2_DPHY: /* diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 3daa636b67db..1caa100be33d 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -139,6 +139,8 @@ static inline bool is_parallel_16bit_bus(struct v4l2_fwnode_endpoint *ep) * Check for conditions that require the IPU to handle the * data internally as generic data, aka passthrough mode: * - raw bayer media bus formats, or + * - BT.656 and BT.1120 (8/10-bit YUV422) data can always be processed + * on-the-fly * - the CSI is receiving from a 16-bit parallel bus, or * - the CSI is receiving from an 8-bit parallel bus and the incoming * media bus format is other than UYVY8_2X8/YUYV8_2X8. @@ -147,6 +149,9 @@ static inline bool requires_passthrough(struct v4l2_fwnode_endpoint *ep, struct v4l2_mbus_framefmt *infmt, const struct imx_media_pixfmt *incc) { + if (ep->bus_type == V4L2_MBUS_BT656) // including BT.1120 + return 0; + return incc->bayer || is_parallel_16bit_bus(ep) || (is_parallel_bus(ep) && infmt->code != MEDIA_BUS_FMT_UYVY8_2X8 && -- cgit v1.2.3 From 305e191ccf16647eb873255d69d8882fb7d50270 Mon Sep 17 00:00:00 2001 From: Jeff Chase Date: Wed, 6 Oct 2021 19:14:57 +0100 Subject: media: MAINTAINERS: update maintainer for ch7322 driver Jeff is leaving Google so Joe will take over. Signed-off-by: Jeff Chase Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index cb51ebb3fb42..df69dfe482e7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4431,7 +4431,7 @@ N: cros_ec N: cros-ec CHRONTEL CH7322 CEC DRIVER -M: Jeff Chase +M: Joe Tessler L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git -- cgit v1.2.3 From 4c2e5156d9fa63a3f41c2bf56b694ad42df825d7 Mon Sep 17 00:00:00 2001 From: Mirela Rabulea Date: Thu, 7 Oct 2021 17:30:38 +0100 Subject: media: imx-jpeg: Add pm-runtime support for imx-jpeg Save some power by disabling/enabling the jpeg clocks with every stream stop/start. Do not use DL_FLAG_RPM_ACTIVE in mxc_jpeg_attach_pm_domains, to ensure power domains are off after probe. Signed-off-by: Mirela Rabulea Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/imx-jpeg/mxc-jpeg.c | 73 ++++++++++++++++++++++++++++-- drivers/media/platform/imx-jpeg/mxc-jpeg.h | 2 + 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/imx-jpeg/mxc-jpeg.c index e45b0c74be55..4ca96cf9def7 100644 --- a/drivers/media/platform/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -1078,10 +1079,17 @@ static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) { struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q); struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, q->type); + int ret; dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx); q_data->sequence = 0; + ret = pm_runtime_resume_and_get(ctx->mxc_jpeg->dev); + if (ret < 0) { + dev_err(ctx->mxc_jpeg->dev, "Failed to power up jpeg\n"); + return ret; + } + return 0; } @@ -1099,9 +1107,10 @@ static void mxc_jpeg_stop_streaming(struct vb2_queue *q) else vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); if (!vbuf) - return; + break; v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); } + pm_runtime_put_sync(&ctx->mxc_jpeg->pdev->dev); } static int mxc_jpeg_valid_comp_id(struct device *dev, @@ -1961,8 +1970,7 @@ static int mxc_jpeg_attach_pm_domains(struct mxc_jpeg_dev *jpeg) jpeg->pd_link[i] = device_link_add(dev, jpeg->pd_dev[i], DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | - DL_FLAG_RPM_ACTIVE); + DL_FLAG_PM_RUNTIME); if (!jpeg->pd_link[i]) { ret = -EINVAL; goto fail; @@ -2025,6 +2033,19 @@ static int mxc_jpeg_probe(struct platform_device *pdev) jpeg->dev = dev; jpeg->mode = mode; + /* Get clocks */ + jpeg->clk_ipg = devm_clk_get(dev, "ipg"); + if (IS_ERR(jpeg->clk_ipg)) { + dev_err(dev, "failed to get clock: ipg\n"); + goto err_clk; + } + + jpeg->clk_per = devm_clk_get(dev, "per"); + if (IS_ERR(jpeg->clk_per)) { + dev_err(dev, "failed to get clock: per\n"); + goto err_clk; + } + ret = mxc_jpeg_attach_pm_domains(jpeg); if (ret < 0) { dev_err(dev, "failed to attach power domains %d\n", ret); @@ -2093,6 +2114,7 @@ static int mxc_jpeg_probe(struct platform_device *pdev) jpeg->dec_vdev->minor); platform_set_drvdata(pdev, jpeg); + pm_runtime_enable(dev); return 0; @@ -2109,9 +2131,52 @@ err_register: mxc_jpeg_detach_pm_domains(jpeg); err_irq: +err_clk: + return ret; +} + +#ifdef CONFIG_PM +static int mxc_jpeg_runtime_resume(struct device *dev) +{ + struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(jpeg->clk_ipg); + if (ret < 0) { + dev_err(dev, "failed to enable clock: ipg\n"); + goto err_ipg; + } + + ret = clk_prepare_enable(jpeg->clk_per); + if (ret < 0) { + dev_err(dev, "failed to enable clock: per\n"); + goto err_per; + } + + return 0; + +err_per: + clk_disable_unprepare(jpeg->clk_ipg); +err_ipg: return ret; } +static int mxc_jpeg_runtime_suspend(struct device *dev) +{ + struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); + + clk_disable_unprepare(jpeg->clk_ipg); + clk_disable_unprepare(jpeg->clk_per); + + return 0; +} +#endif + +static const struct dev_pm_ops mxc_jpeg_pm_ops = { + SET_RUNTIME_PM_OPS(mxc_jpeg_runtime_suspend, + mxc_jpeg_runtime_resume, NULL) +}; + static int mxc_jpeg_remove(struct platform_device *pdev) { unsigned int slot; @@ -2120,6 +2185,7 @@ static int mxc_jpeg_remove(struct platform_device *pdev) for (slot = 0; slot < MXC_MAX_SLOTS; slot++) mxc_jpeg_free_slot_data(jpeg, slot); + pm_runtime_disable(&pdev->dev); video_unregister_device(jpeg->dec_vdev); v4l2_m2m_release(jpeg->m2m_dev); v4l2_device_unregister(&jpeg->v4l2_dev); @@ -2136,6 +2202,7 @@ static struct platform_driver mxc_jpeg_driver = { .driver = { .name = "mxc-jpeg", .of_match_table = mxc_jpeg_match, + .pm = &mxc_jpeg_pm_ops, }, }; module_platform_driver(mxc_jpeg_driver); diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/imx-jpeg/mxc-jpeg.h index 4c210852e876..9fb2a5aaa941 100644 --- a/drivers/media/platform/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.h @@ -109,6 +109,8 @@ struct mxc_jpeg_dev { spinlock_t hw_lock; /* hardware access lock */ unsigned int mode; struct mutex lock; /* v4l2 ioctls serialization */ + struct clk *clk_ipg; + struct clk *clk_per; struct platform_device *pdev; struct device *dev; void __iomem *base_reg; -- cgit v1.2.3 From 298d8e8f7bcf023aceb60232d59b983255fec0df Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 8 Oct 2021 11:04:22 +0100 Subject: media: rkvdec: Do not override sizeimage for output format The rkvdec H.264 decoder currently overrides sizeimage for the output format. This causes issues when userspace requires and requests a larger buffer, but ends up with one of insufficient size. Instead, only provide a default size if none was requested. This fixes the video_decode_accelerator_tests from Chromium failing on the first frame due to insufficient buffer space. It also aligns the behavior of the rkvdec driver with the Hantro and Cedrus drivers. Fixes: cd33c830448b ("media: rkvdec: Add the rkvdec driver") Cc: Signed-off-by: Chen-Yu Tsai Reviewed-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkvdec/rkvdec-h264.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c index 76e97cbe2512..951e19231da2 100644 --- a/drivers/staging/media/rkvdec/rkvdec-h264.c +++ b/drivers/staging/media/rkvdec/rkvdec-h264.c @@ -1015,8 +1015,9 @@ static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp; fmt->num_planes = 1; - fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * - RKVDEC_H264_MAX_DEPTH_IN_BYTES; + if (!fmt->plane_fmt[0].sizeimage) + fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * + RKVDEC_H264_MAX_DEPTH_IN_BYTES; return 0; } -- cgit v1.2.3 From 0887e9e152efbd3601d6c907e90033d25067277d Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 8 Oct 2021 11:04:23 +0100 Subject: media: rkvdec: Support dynamic resolution changes The mem-to-mem stateless decoder API specifies support for dynamic resolution changes. In particular, the decoder should accept format changes on the OUTPUT queue even when buffers have been allocated, as long as it is not streaming. Relax restrictions for S_FMT as described in the previous paragraph, and as long as the codec format remains the same. This aligns it with the Hantro and Cedrus decoders. This change was mostly based on commit ae02d49493b5 ("media: hantro: Fix s_fmt for dynamic resolution changes"). Since rkvdec_s_fmt() is now just a wrapper around the output/capture variants without any additional shared functionality, drop the wrapper and call the respective functions directly. Fixes: cd33c830448b ("media: rkvdec: Add the rkvdec driver") Cc: Signed-off-by: Chen-Yu Tsai Reviewed-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkvdec/rkvdec.c | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index bf00fe6534a3..4fd4a2907da7 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -280,31 +280,20 @@ static int rkvdec_try_output_fmt(struct file *file, void *priv, return 0; } -static int rkvdec_s_fmt(struct file *file, void *priv, - struct v4l2_format *f, - int (*try_fmt)(struct file *, void *, - struct v4l2_format *)) +static int rkvdec_s_capture_fmt(struct file *file, void *priv, + struct v4l2_format *f) { struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); struct vb2_queue *vq; + int ret; - if (!try_fmt) - return -EINVAL; - - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + /* Change not allowed if queue is busy */ + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); if (vb2_is_busy(vq)) return -EBUSY; - return try_fmt(file, priv, f); -} - -static int rkvdec_s_capture_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); - int ret; - - ret = rkvdec_s_fmt(file, priv, f, rkvdec_try_capture_fmt); + ret = rkvdec_try_capture_fmt(file, priv, f); if (ret) return ret; @@ -319,9 +308,20 @@ static int rkvdec_s_output_fmt(struct file *file, void *priv, struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; const struct rkvdec_coded_fmt_desc *desc; struct v4l2_format *cap_fmt; - struct vb2_queue *peer_vq; + struct vb2_queue *peer_vq, *vq; int ret; + /* + * In order to support dynamic resolution change, the decoder admits + * a resolution change, as long as the pixelformat remains. Can't be + * done if streaming. + */ + vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (vb2_is_streaming(vq) || + (vb2_is_busy(vq) && + f->fmt.pix_mp.pixelformat != ctx->coded_fmt.fmt.pix_mp.pixelformat)) + return -EBUSY; + /* * Since format change on the OUTPUT queue will reset the CAPTURE * queue, we can't allow doing so when the CAPTURE queue has buffers @@ -331,7 +331,7 @@ static int rkvdec_s_output_fmt(struct file *file, void *priv, if (vb2_is_busy(peer_vq)) return -EBUSY; - ret = rkvdec_s_fmt(file, priv, f, rkvdec_try_output_fmt); + ret = rkvdec_try_output_fmt(file, priv, f); if (ret) return ret; -- cgit v1.2.3 From 5db127a534e1aa381c3ba60f51455863f37ea96b Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 10 Oct 2021 11:45:14 +0100 Subject: media: cedrus: Don't kernel map most buffers Except for VP8 probability coefficients buffer, all other buffers are never accessed by CPU. That allows us to mark them with DMA_ATTR_NO_KERNEL_MAPPING flag. This helps with decoding big (like 4k) videos on 32-bit ARM platforms where default vmalloc size is relatively small - 240 MiB. Since auxiliary buffer are not yet efficiently allocated, this can be easily exceeded. Even if allocation is optimized, 4k videos will still often exceed this limit. Signed-off-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 113 ++++++++++++---------- drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 30 +++--- drivers/staging/media/sunxi/cedrus/cedrus_video.c | 1 + 3 files changed, 82 insertions(+), 62 deletions(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c index de7442d4834d..b4173a8926d6 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -520,6 +520,11 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx) unsigned int mv_col_size; int ret; + /* + * NOTE: All buffers allocated here are only used by HW, so we + * can add DMA_ATTR_NO_KERNEL_MAPPING flag when allocating them. + */ + /* Formula for picture buffer size is taken from CedarX source. */ if (ctx->src_fmt.width > 2048) @@ -538,23 +543,23 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx) ctx->codec.h264.pic_info_buf_size = pic_info_size; ctx->codec.h264.pic_info_buf = - dma_alloc_coherent(dev->dev, ctx->codec.h264.pic_info_buf_size, - &ctx->codec.h264.pic_info_buf_dma, - GFP_KERNEL); + dma_alloc_attrs(dev->dev, ctx->codec.h264.pic_info_buf_size, + &ctx->codec.h264.pic_info_buf_dma, + GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING); if (!ctx->codec.h264.pic_info_buf) return -ENOMEM; /* * That buffer is supposed to be 16kiB in size, and be aligned - * on 16kiB as well. However, dma_alloc_coherent provides the - * guarantee that we'll have a CPU and DMA address aligned on - * the smallest page order that is greater to the requested - * size, so we don't have to overallocate. + * on 16kiB as well. However, dma_alloc_attrs provides the + * guarantee that we'll have a DMA address aligned on the + * smallest page order that is greater to the requested size, + * so we don't have to overallocate. */ ctx->codec.h264.neighbor_info_buf = - dma_alloc_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE, - &ctx->codec.h264.neighbor_info_buf_dma, - GFP_KERNEL); + dma_alloc_attrs(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE, + &ctx->codec.h264.neighbor_info_buf_dma, + GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING); if (!ctx->codec.h264.neighbor_info_buf) { ret = -ENOMEM; goto err_pic_buf; @@ -582,10 +587,11 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx) mv_col_size = field_size * 2 * CEDRUS_H264_FRAME_NUM; ctx->codec.h264.mv_col_buf_size = mv_col_size; - ctx->codec.h264.mv_col_buf = dma_alloc_coherent(dev->dev, - ctx->codec.h264.mv_col_buf_size, - &ctx->codec.h264.mv_col_buf_dma, - GFP_KERNEL); + ctx->codec.h264.mv_col_buf = + dma_alloc_attrs(dev->dev, + ctx->codec.h264.mv_col_buf_size, + &ctx->codec.h264.mv_col_buf_dma, + GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING); if (!ctx->codec.h264.mv_col_buf) { ret = -ENOMEM; goto err_neighbor_buf; @@ -600,10 +606,10 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx) ctx->codec.h264.deblk_buf_size = ALIGN(ctx->src_fmt.width, 32) * 12; ctx->codec.h264.deblk_buf = - dma_alloc_coherent(dev->dev, - ctx->codec.h264.deblk_buf_size, - &ctx->codec.h264.deblk_buf_dma, - GFP_KERNEL); + dma_alloc_attrs(dev->dev, + ctx->codec.h264.deblk_buf_size, + &ctx->codec.h264.deblk_buf_dma, + GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING); if (!ctx->codec.h264.deblk_buf) { ret = -ENOMEM; goto err_mv_col_buf; @@ -616,10 +622,10 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx) ctx->codec.h264.intra_pred_buf_size = ALIGN(ctx->src_fmt.width, 64) * 5 * 2; ctx->codec.h264.intra_pred_buf = - dma_alloc_coherent(dev->dev, - ctx->codec.h264.intra_pred_buf_size, - &ctx->codec.h264.intra_pred_buf_dma, - GFP_KERNEL); + dma_alloc_attrs(dev->dev, + ctx->codec.h264.intra_pred_buf_size, + &ctx->codec.h264.intra_pred_buf_dma, + GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING); if (!ctx->codec.h264.intra_pred_buf) { ret = -ENOMEM; goto err_deblk_buf; @@ -629,24 +635,28 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx) return 0; err_deblk_buf: - dma_free_coherent(dev->dev, ctx->codec.h264.deblk_buf_size, - ctx->codec.h264.deblk_buf, - ctx->codec.h264.deblk_buf_dma); + dma_free_attrs(dev->dev, ctx->codec.h264.deblk_buf_size, + ctx->codec.h264.deblk_buf, + ctx->codec.h264.deblk_buf_dma, + DMA_ATTR_NO_KERNEL_MAPPING); err_mv_col_buf: - dma_free_coherent(dev->dev, ctx->codec.h264.mv_col_buf_size, - ctx->codec.h264.mv_col_buf, - ctx->codec.h264.mv_col_buf_dma); + dma_free_attrs(dev->dev, ctx->codec.h264.mv_col_buf_size, + ctx->codec.h264.mv_col_buf, + ctx->codec.h264.mv_col_buf_dma, + DMA_ATTR_NO_KERNEL_MAPPING); err_neighbor_buf: - dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE, - ctx->codec.h264.neighbor_info_buf, - ctx->codec.h264.neighbor_info_buf_dma); + dma_free_attrs(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE, + ctx->codec.h264.neighbor_info_buf, + ctx->codec.h264.neighbor_info_buf_dma, + DMA_ATTR_NO_KERNEL_MAPPING); err_pic_buf: - dma_free_coherent(dev->dev, ctx->codec.h264.pic_info_buf_size, - ctx->codec.h264.pic_info_buf, - ctx->codec.h264.pic_info_buf_dma); + dma_free_attrs(dev->dev, ctx->codec.h264.pic_info_buf_size, + ctx->codec.h264.pic_info_buf, + ctx->codec.h264.pic_info_buf_dma, + DMA_ATTR_NO_KERNEL_MAPPING); return ret; } @@ -654,23 +664,28 @@ static void cedrus_h264_stop(struct cedrus_ctx *ctx) { struct cedrus_dev *dev = ctx->dev; - dma_free_coherent(dev->dev, ctx->codec.h264.mv_col_buf_size, - ctx->codec.h264.mv_col_buf, - ctx->codec.h264.mv_col_buf_dma); - dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE, - ctx->codec.h264.neighbor_info_buf, - ctx->codec.h264.neighbor_info_buf_dma); - dma_free_coherent(dev->dev, ctx->codec.h264.pic_info_buf_size, - ctx->codec.h264.pic_info_buf, - ctx->codec.h264.pic_info_buf_dma); + dma_free_attrs(dev->dev, ctx->codec.h264.mv_col_buf_size, + ctx->codec.h264.mv_col_buf, + ctx->codec.h264.mv_col_buf_dma, + DMA_ATTR_NO_KERNEL_MAPPING); + dma_free_attrs(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE, + ctx->codec.h264.neighbor_info_buf, + ctx->codec.h264.neighbor_info_buf_dma, + DMA_ATTR_NO_KERNEL_MAPPING); + dma_free_attrs(dev->dev, ctx->codec.h264.pic_info_buf_size, + ctx->codec.h264.pic_info_buf, + ctx->codec.h264.pic_info_buf_dma, + DMA_ATTR_NO_KERNEL_MAPPING); if (ctx->codec.h264.deblk_buf_size) - dma_free_coherent(dev->dev, ctx->codec.h264.deblk_buf_size, - ctx->codec.h264.deblk_buf, - ctx->codec.h264.deblk_buf_dma); + dma_free_attrs(dev->dev, ctx->codec.h264.deblk_buf_size, + ctx->codec.h264.deblk_buf, + ctx->codec.h264.deblk_buf_dma, + DMA_ATTR_NO_KERNEL_MAPPING); if (ctx->codec.h264.intra_pred_buf_size) - dma_free_coherent(dev->dev, ctx->codec.h264.intra_pred_buf_size, - ctx->codec.h264.intra_pred_buf, - ctx->codec.h264.intra_pred_buf_dma); + dma_free_attrs(dev->dev, ctx->codec.h264.intra_pred_buf_size, + ctx->codec.h264.intra_pred_buf, + ctx->codec.h264.intra_pred_buf_dma, + DMA_ATTR_NO_KERNEL_MAPPING); } static void cedrus_h264_trigger(struct cedrus_ctx *ctx) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index 3d9561d4aadb..8829a7bab07e 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -350,11 +350,12 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, ctx->codec.h265.mv_col_buf_size = num_buffers * ctx->codec.h265.mv_col_buf_unit_size; + /* Buffer is never accessed by CPU, so we can skip kernel mapping. */ ctx->codec.h265.mv_col_buf = - dma_alloc_coherent(dev->dev, - ctx->codec.h265.mv_col_buf_size, - &ctx->codec.h265.mv_col_buf_addr, - GFP_KERNEL); + dma_alloc_attrs(dev->dev, + ctx->codec.h265.mv_col_buf_size, + &ctx->codec.h265.mv_col_buf_addr, + GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING); if (!ctx->codec.h265.mv_col_buf) { ctx->codec.h265.mv_col_buf_size = 0; // TODO: Abort the process here. @@ -667,10 +668,11 @@ static int cedrus_h265_start(struct cedrus_ctx *ctx) /* The buffer size is calculated at setup time. */ ctx->codec.h265.mv_col_buf_size = 0; + /* Buffer is never accessed by CPU, so we can skip kernel mapping. */ ctx->codec.h265.neighbor_info_buf = - dma_alloc_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE, - &ctx->codec.h265.neighbor_info_buf_addr, - GFP_KERNEL); + dma_alloc_attrs(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE, + &ctx->codec.h265.neighbor_info_buf_addr, + GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING); if (!ctx->codec.h265.neighbor_info_buf) return -ENOMEM; @@ -682,16 +684,18 @@ static void cedrus_h265_stop(struct cedrus_ctx *ctx) struct cedrus_dev *dev = ctx->dev; if (ctx->codec.h265.mv_col_buf_size > 0) { - dma_free_coherent(dev->dev, ctx->codec.h265.mv_col_buf_size, - ctx->codec.h265.mv_col_buf, - ctx->codec.h265.mv_col_buf_addr); + dma_free_attrs(dev->dev, ctx->codec.h265.mv_col_buf_size, + ctx->codec.h265.mv_col_buf, + ctx->codec.h265.mv_col_buf_addr, + DMA_ATTR_NO_KERNEL_MAPPING); ctx->codec.h265.mv_col_buf_size = 0; } - dma_free_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE, - ctx->codec.h265.neighbor_info_buf, - ctx->codec.h265.neighbor_info_buf_addr); + dma_free_attrs(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE, + ctx->codec.h265.neighbor_info_buf, + ctx->codec.h265.neighbor_info_buf_addr, + DMA_ATTR_NO_KERNEL_MAPPING); } static void cedrus_h265_trigger(struct cedrus_ctx *ctx) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 66714609b577..33726175d980 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -568,6 +568,7 @@ int cedrus_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->dma_attrs = DMA_ATTR_NO_KERNEL_MAPPING; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct cedrus_buffer); src_vq->ops = &cedrus_qops; -- cgit v1.2.3 From 6cb67bea945bdf0ad40e633cd2d9fbeb0855675b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 10 Oct 2021 20:38:36 +0100 Subject: media: ivtv: fix build for UML MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevent the use of page table macros and types from 2 conflicting places. This fixes multiple build errors and warnings, e.g.: ../arch/x86/include/asm/pgtable_64_types.h:21:34: error: conflicting types for ‘pte_t’ typedef struct { pteval_t pte; } pte_t; ^~~~~ In file included from ../include/linux/mm_types_task.h:16:0, from ../include/linux/mm_types.h:5, from ../include/linux/buildid.h:5, from ../include/linux/module.h:14, from ../drivers/media/pci/ivtv/ivtv-driver.h:40, from ../drivers/media/pci/ivtv/ivtvfb.c:29: ../arch/um/include/asm/page.h:57:39: note: previous declaration of ‘pte_t’ was here typedef struct { unsigned long pte; } pte_t; ../arch/x86/include/asm/pgtable_types.h:284:43: error: expected ‘)’ before ‘prot’ static inline pgprot_t pgprot_nx(pgprot_t prot) ^ ../include/linux/pgtable.h:914:26: note: in definition of macro ‘pgprot_nx’ #define pgprot_nx(prot) (prot) ^~~~ In file included from ../arch/x86/include/asm/memtype.h:6:0, from ../drivers/media/pci/ivtv/ivtvfb.c:40: ../arch/x86/include/asm/pgtable_types.h:288:0: warning: "pgprot_nx" redefined #define pgprot_nx pgprot_nx ../arch/x86/include/asm/page_types.h:11:0: warning: "PAGE_SIZE" redefined #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) In file included from ../include/linux/mm_types_task.h:16:0, from ../include/linux/mm_types.h:5, from ../include/linux/buildid.h:5, from ../include/linux/module.h:14, from ../drivers/media/pci/ivtv/ivtv-driver.h:40, from ../drivers/media/pci/ivtv/ivtvfb.c:29: ../arch/um/include/asm/page.h:14:0: note: this is the location of the previous definition #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) Fixes: 68f5d3f3b654 ("um: add PCI over virtio emulation driver") Signed-off-by: Randy Dunlap Cc: Johannes Berg Cc: Andy Walls Cc: linux-um@lists.infradead.org Cc: Richard Weinberger Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtvfb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index c58ca8aa6d90..2c43ebf83966 100644 --- a/drivers/media/pci/ivtv/ivtvfb.c +++ b/drivers/media/pci/ivtv/ivtvfb.c @@ -36,7 +36,7 @@ #include #include -#ifdef CONFIG_X86_64 +#if defined(CONFIG_X86_64) && !defined(CONFIG_UML) #include #endif @@ -1157,7 +1157,7 @@ static int ivtvfb_init_card(struct ivtv *itv) { int rc; -#ifdef CONFIG_X86_64 +#if defined(CONFIG_X86_64) && !defined(CONFIG_UML) if (pat_enabled()) { if (ivtvfb_force_pat) { pr_info("PAT is enabled. Write-combined framebuffer caching will be disabled.\n"); -- cgit v1.2.3 From febfe985fc2ea052a363f6525ff624b8efd5273c Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 13 Oct 2021 09:14:10 +0100 Subject: media: ir_toy: assignment to be16 should be of correct type commit f0c15b360fb6 ("media: ir_toy: prevent device from hanging during transmit") removed a cpu_to_be16() cast, which causes a sparse warning. Fixes: f0c15b360fb6 ("media: ir_toy: prevent device from hanging during transmit") Reported-by: Hans Verkuil Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir_toy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c index 71aced52248f..7e98e7e3aace 100644 --- a/drivers/media/rc/ir_toy.c +++ b/drivers/media/rc/ir_toy.c @@ -318,7 +318,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count) buf[i] = cpu_to_be16(v); } - buf[count] = 0xffff; + buf[count] = cpu_to_be16(0xffff); irtoy->tx_buf = buf; irtoy->tx_len = size; -- cgit v1.2.3 From 95f4325de9e612918468f7e6bda633223bae793f Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 13 Oct 2021 13:27:57 +0100 Subject: media: sir_ir: remove broken driver This driver is a port of the lirc_sir driver to rc-core. However, for this driver I could not find any hardware to test, so it was done without testing. This is a mistake. There are clear bugs in the code. For example the two arguments to ktime_us_delta() are reversed, which means the result is garbage. The driver has been in the kernel for four years, and noone has ever reported an issue. So, remove this driver. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 8 - drivers/media/rc/Makefile | 1 - drivers/media/rc/sir_ir.c | 438 ---------------------------------------------- 3 files changed, 447 deletions(-) delete mode 100644 drivers/media/rc/sir_ir.c diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index fd5a7a058714..9506baf3c4c1 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -453,14 +453,6 @@ config IR_SERIAL_TRANSMITTER help Serial Port Transmitter support -config IR_SIR - tristate "Built-in SIR IrDA port" - help - Say Y if you want to use a IrDA SIR port Transceivers. - - To compile this driver as a module, choose M here: the module will - be called sir-ir. - config RC_XBOX_DVD tristate "Xbox DVD Movie Playback Kit" depends on USB diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 0db51fad27d6..378d62d21e06 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -47,7 +47,6 @@ obj-$(CONFIG_RC_ST) += st_rc.o obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o obj-$(CONFIG_IR_IMG) += img-ir/ obj-$(CONFIG_IR_SERIAL) += serial_ir.o -obj-$(CONFIG_IR_SIR) += sir_ir.o obj-$(CONFIG_IR_MTK) += mtk-cir.o obj-$(CONFIG_RC_XBOX_DVD) += xbox_remote.o obj-$(CONFIG_IR_TOY) += ir_toy.o diff --git a/drivers/media/rc/sir_ir.c b/drivers/media/rc/sir_ir.c deleted file mode 100644 index 6ec96dc34586..000000000000 --- a/drivers/media/rc/sir_ir.c +++ /dev/null @@ -1,438 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * IR SIR driver, (C) 2000 Milan Pikula - * - * sir_ir - Device driver for use with SIR (serial infra red) - * mode of IrDA on many notebooks. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include - -#include - -/* SECTION: Definitions */ -#define PULSE '[' - -/* 9bit * 1s/115200bit in milli seconds = 78.125ms*/ -#define TIME_CONST (9000000ul / 115200ul) - -/* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */ -#define SIR_TIMEOUT (HZ * 5 / 100) - -/* onboard sir ports are typically com3 */ -static int io = 0x3e8; -static int irq = 4; -static int threshold = 3; - -static DEFINE_SPINLOCK(timer_lock); -static struct timer_list timerlist; -/* time of last signal change detected */ -static ktime_t last; -/* time of last UART data ready interrupt */ -static ktime_t last_intr_time; -static int last_value; -static struct rc_dev *rcdev; - -static struct platform_device *sir_ir_dev; - -static DEFINE_SPINLOCK(hardware_lock); - -/* SECTION: Prototypes */ - -/* Communication with user-space */ -static void add_read_queue(int flag, unsigned long val); -/* Hardware */ -static irqreturn_t sir_interrupt(int irq, void *dev_id); -static void send_space(unsigned long len); -static void send_pulse(unsigned long len); -static int init_hardware(void); -static void drop_hardware(void); -/* Initialisation */ - -static inline unsigned int sinp(int offset) -{ - return inb(io + offset); -} - -static inline void soutp(int offset, int value) -{ - outb(value, io + offset); -} - -/* SECTION: Communication with user-space */ -static int sir_tx_ir(struct rc_dev *dev, unsigned int *tx_buf, - unsigned int count) -{ - unsigned long flags; - int i; - - local_irq_save(flags); - for (i = 0; i < count;) { - if (tx_buf[i]) - send_pulse(tx_buf[i]); - i++; - if (i >= count) - break; - if (tx_buf[i]) - send_space(tx_buf[i]); - i++; - } - local_irq_restore(flags); - - return count; -} - -static void add_read_queue(int flag, unsigned long val) -{ - struct ir_raw_event ev = {}; - - pr_debug("add flag %d with val %lu\n", flag, val); - - /* - * statistically, pulses are ~TIME_CONST/2 too long. we could - * maybe make this more exact, but this is good enough - */ - if (flag) { - /* pulse */ - if (val > TIME_CONST / 2) - val -= TIME_CONST / 2; - else /* should not ever happen */ - val = 1; - ev.pulse = true; - } else { - val += TIME_CONST / 2; - } - ev.duration = val; - - ir_raw_event_store_with_filter(rcdev, &ev); -} - -/* SECTION: Hardware */ -static void sir_timeout(struct timer_list *unused) -{ - /* - * if last received signal was a pulse, but receiving stopped - * within the 9 bit frame, we need to finish this pulse and - * simulate a signal change to from pulse to space. Otherwise - * upper layers will receive two sequences next time. - */ - - unsigned long flags; - unsigned long pulse_end; - - /* avoid interference with interrupt */ - spin_lock_irqsave(&timer_lock, flags); - if (last_value) { - /* clear unread bits in UART and restart */ - outb(UART_FCR_CLEAR_RCVR, io + UART_FCR); - /* determine 'virtual' pulse end: */ - pulse_end = min_t(unsigned long, - ktime_us_delta(last, last_intr_time), - IR_MAX_DURATION); - dev_dbg(&sir_ir_dev->dev, "timeout add %d for %lu usec\n", - last_value, pulse_end); - add_read_queue(last_value, pulse_end); - last_value = 0; - last = last_intr_time; - } - spin_unlock_irqrestore(&timer_lock, flags); - ir_raw_event_handle(rcdev); -} - -static irqreturn_t sir_interrupt(int irq, void *dev_id) -{ - unsigned char data; - ktime_t curr_time; - unsigned long delt; - unsigned long deltintr; - unsigned long flags; - int counter = 0; - int iir, lsr; - - while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) { - if (++counter > 256) { - dev_err(&sir_ir_dev->dev, "Trapped in interrupt"); - break; - } - - switch (iir & UART_IIR_ID) { /* FIXME toto treba preriedit */ - case UART_IIR_MSI: - (void)inb(io + UART_MSR); - break; - case UART_IIR_RLSI: - case UART_IIR_THRI: - (void)inb(io + UART_LSR); - break; - case UART_IIR_RDI: - /* avoid interference with timer */ - spin_lock_irqsave(&timer_lock, flags); - do { - del_timer(&timerlist); - data = inb(io + UART_RX); - curr_time = ktime_get(); - delt = min_t(unsigned long, - ktime_us_delta(last, curr_time), - IR_MAX_DURATION); - deltintr = min_t(unsigned long, - ktime_us_delta(last_intr_time, - curr_time), - IR_MAX_DURATION); - dev_dbg(&sir_ir_dev->dev, "t %lu, d %d\n", - deltintr, (int)data); - /* - * if nothing came in last X cycles, - * it was gap - */ - if (deltintr > TIME_CONST * threshold) { - if (last_value) { - dev_dbg(&sir_ir_dev->dev, "GAP\n"); - /* simulate signal change */ - add_read_queue(last_value, - delt - - deltintr); - last_value = 0; - last = last_intr_time; - delt = deltintr; - } - } - data = 1; - if (data ^ last_value) { - /* - * deltintr > 2*TIME_CONST, remember? - * the other case is timeout - */ - add_read_queue(last_value, - delt - TIME_CONST); - last_value = data; - last = curr_time; - last = ktime_sub_us(last, - TIME_CONST); - } - last_intr_time = curr_time; - if (data) { - /* - * start timer for end of - * sequence detection - */ - timerlist.expires = jiffies + - SIR_TIMEOUT; - add_timer(&timerlist); - } - - lsr = inb(io + UART_LSR); - } while (lsr & UART_LSR_DR); /* data ready */ - spin_unlock_irqrestore(&timer_lock, flags); - break; - default: - break; - } - } - ir_raw_event_handle(rcdev); - return IRQ_RETVAL(IRQ_HANDLED); -} - -static void send_space(unsigned long len) -{ - usleep_range(len, len + 25); -} - -static void send_pulse(unsigned long len) -{ - long bytes_out = len / TIME_CONST; - - if (bytes_out == 0) - bytes_out++; - - while (bytes_out--) { - outb(PULSE, io + UART_TX); - /* FIXME treba seriozne cakanie z char/serial.c */ - while (!(inb(io + UART_LSR) & UART_LSR_THRE)) - ; - } -} - -static int init_hardware(void) -{ - u8 scratch, scratch2, scratch3; - unsigned long flags; - - spin_lock_irqsave(&hardware_lock, flags); - - /* - * This is a simple port existence test, borrowed from the autoconfig - * function in drivers/tty/serial/8250/8250_port.c - */ - scratch = sinp(UART_IER); - soutp(UART_IER, 0); -#ifdef __i386__ - outb(0xff, 0x080); -#endif - scratch2 = sinp(UART_IER) & 0x0f; - soutp(UART_IER, 0x0f); -#ifdef __i386__ - outb(0x00, 0x080); -#endif - scratch3 = sinp(UART_IER) & 0x0f; - soutp(UART_IER, scratch); - if (scratch2 != 0 || scratch3 != 0x0f) { - /* we fail, there's nothing here */ - spin_unlock_irqrestore(&hardware_lock, flags); - pr_err("port existence test failed, cannot continue\n"); - return -ENODEV; - } - - /* reset UART */ - outb(0, io + UART_MCR); - outb(0, io + UART_IER); - /* init UART */ - /* set DLAB, speed = 115200 */ - outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR); - outb(1, io + UART_DLL); outb(0, io + UART_DLM); - /* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */ - outb(UART_LCR_WLEN7, io + UART_LCR); - /* FIFO operation */ - outb(UART_FCR_ENABLE_FIFO, io + UART_FCR); - /* interrupts */ - /* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */ - outb(UART_IER_RDI, io + UART_IER); - /* turn on UART */ - outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, io + UART_MCR); - spin_unlock_irqrestore(&hardware_lock, flags); - - return 0; -} - -static void drop_hardware(void) -{ - unsigned long flags; - - spin_lock_irqsave(&hardware_lock, flags); - - /* turn off interrupts */ - outb(0, io + UART_IER); - - spin_unlock_irqrestore(&hardware_lock, flags); -} - -/* SECTION: Initialisation */ -static int sir_ir_probe(struct platform_device *dev) -{ - int retval; - - rcdev = devm_rc_allocate_device(&sir_ir_dev->dev, RC_DRIVER_IR_RAW); - if (!rcdev) - return -ENOMEM; - - rcdev->device_name = "SIR IrDA port"; - rcdev->input_phys = KBUILD_MODNAME "/input0"; - rcdev->input_id.bustype = BUS_HOST; - rcdev->input_id.vendor = 0x0001; - rcdev->input_id.product = 0x0001; - rcdev->input_id.version = 0x0100; - rcdev->tx_ir = sir_tx_ir; - rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; - rcdev->driver_name = KBUILD_MODNAME; - rcdev->map_name = RC_MAP_RC6_MCE; - rcdev->timeout = IR_DEFAULT_TIMEOUT; - rcdev->dev.parent = &sir_ir_dev->dev; - - timer_setup(&timerlist, sir_timeout, 0); - - /* get I/O port access and IRQ line */ - if (!devm_request_region(&sir_ir_dev->dev, io, 8, KBUILD_MODNAME)) { - pr_err("i/o port 0x%.4x already in use.\n", io); - return -EBUSY; - } - retval = devm_request_irq(&sir_ir_dev->dev, irq, sir_interrupt, 0, - KBUILD_MODNAME, NULL); - if (retval < 0) { - pr_err("IRQ %d already in use.\n", irq); - return retval; - } - - retval = init_hardware(); - if (retval) { - del_timer_sync(&timerlist); - return retval; - } - - pr_info("I/O port 0x%.4x, IRQ %d.\n", io, irq); - - retval = devm_rc_register_device(&sir_ir_dev->dev, rcdev); - if (retval < 0) - return retval; - - return 0; -} - -static int sir_ir_remove(struct platform_device *dev) -{ - drop_hardware(); - del_timer_sync(&timerlist); - return 0; -} - -static struct platform_driver sir_ir_driver = { - .probe = sir_ir_probe, - .remove = sir_ir_remove, - .driver = { - .name = "sir_ir", - }, -}; - -static int __init sir_ir_init(void) -{ - int retval; - - retval = platform_driver_register(&sir_ir_driver); - if (retval) - return retval; - - sir_ir_dev = platform_device_alloc("sir_ir", 0); - if (!sir_ir_dev) { - retval = -ENOMEM; - goto pdev_alloc_fail; - } - - retval = platform_device_add(sir_ir_dev); - if (retval) - goto pdev_add_fail; - - return 0; - -pdev_add_fail: - platform_device_put(sir_ir_dev); -pdev_alloc_fail: - platform_driver_unregister(&sir_ir_driver); - return retval; -} - -static void __exit sir_ir_exit(void) -{ - platform_device_unregister(sir_ir_dev); - platform_driver_unregister(&sir_ir_driver); -} - -module_init(sir_ir_init); -module_exit(sir_ir_exit); - -MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports"); -MODULE_AUTHOR("Milan Pikula"); -MODULE_LICENSE("GPL"); - -module_param_hw(io, int, ioport, 0444); -MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); - -module_param_hw(irq, int, irq, 0444); -MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); - -module_param(threshold, int, 0444); -MODULE_PARM_DESC(threshold, "space detection threshold (3)"); -- cgit v1.2.3 From fdc881783099c6343921ff017450831c8766d12a Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 17 Oct 2021 13:01:15 +0100 Subject: media: ite-cir: IR receiver stop working after receive overflow On an Intel NUC6iSYK, no IR is reported after a receive overflow. When a receiver overflow occurs, this condition is only cleared by reading the fifo. Make sure we read anything in the fifo. Fixes: 28c7afb07ccf ("media: ite-cir: check for receive overflow") Suggested-by: Bryan Pass Tested-by: Bryan Pass Cc: stable@vger.kernel.org> Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ite-cir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 5bc23e8c6d91..4f77d4ebacdc 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -242,7 +242,7 @@ static irqreturn_t ite_cir_isr(int irq, void *data) } /* check for the receive interrupt */ - if (iflags & ITE_IRQ_RX_FIFO) { + if (iflags & (ITE_IRQ_RX_FIFO | ITE_IRQ_RX_FIFO_OVERRUN)) { /* read the FIFO bytes */ rx_bytes = dev->params->get_rx_bytes(dev, rx_buf, ITE_RX_FIFO_LEN); -- cgit v1.2.3 From 1ecda6393db4be44aba27a243e648dc98c9b92e3 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 8 Sep 2021 14:03:10 +0100 Subject: media: allegro: ignore interrupt if mailbox is not initialized The mailbox is initialized after the interrupt handler is installed. As the firmware is loaded and started even later, it should not happen that the interrupt occurs without the mailbox being initialized. As the Linux Driver Verification project (linuxtesting.org) keeps reporting this as an error, add a check to ignore interrupts before the mailbox is initialized to fix this potential null pointer dereference. Reported-by: Yuri Savinykh Reported-by: Nadezda Lutovinova Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/allegro-dvt/allegro-core.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 887b492e4ad1..14a119b43bca 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -2185,6 +2185,15 @@ static irqreturn_t allegro_irq_thread(int irq, void *data) { struct allegro_dev *dev = data; + /* + * The firmware is initialized after the mailbox is setup. We further + * check the AL5_ITC_CPU_IRQ_STA register, if the firmware actually + * triggered the interrupt. Although this should not happen, make sure + * that we ignore interrupts, if the mailbox is not initialized. + */ + if (!dev->mbox_status) + return IRQ_NONE; + allegro_mbox_notify(dev->mbox_status); return IRQ_HANDLED; -- cgit v1.2.3 From dacc21d638c427a53448d91bd976ee6762822911 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 8 Sep 2021 14:03:11 +0100 Subject: media: allegro: fix module removal if initialization failed If the module probe finished, but the firmware initialization failed, removing the module must not revert the firmware initialization. Add a field to track the status of the firmware initialization and only roll it back, if the firmware was successfully initialized. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/allegro-dvt/allegro-core.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 14a119b43bca..89d6de6082f6 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -142,6 +142,7 @@ struct allegro_dev { struct allegro_buffer suballocator; struct completion init_complete; + bool initialized; /* The mailbox interface */ struct allegro_mbox *mbox_command; @@ -3632,6 +3633,8 @@ static void allegro_fw_callback(const struct firmware *fw, void *context) "allegro codec registered as /dev/video%d\n", dev->video_dev.num); + dev->initialized = true; + release_firmware(fw_codec); release_firmware(fw); @@ -3678,6 +3681,8 @@ static int allegro_probe(struct platform_device *pdev) mutex_init(&dev->lock); + dev->initialized = false; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); if (!res) { dev_err(&pdev->dev, @@ -3748,11 +3753,13 @@ static int allegro_remove(struct platform_device *pdev) { struct allegro_dev *dev = platform_get_drvdata(pdev); - video_unregister_device(&dev->video_dev); - if (dev->m2m_dev) - v4l2_m2m_release(dev->m2m_dev); - allegro_mcu_hw_deinit(dev); - allegro_free_fw_codec(dev); + if (dev->initialized) { + video_unregister_device(&dev->video_dev); + if (dev->m2m_dev) + v4l2_m2m_release(dev->m2m_dev); + allegro_mcu_hw_deinit(dev); + allegro_free_fw_codec(dev); + } v4l2_device_unregister(&dev->v4l2_dev); -- cgit v1.2.3 From b6707e770d832da586a4b42d4d45b3a91d5f98c2 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 8 Sep 2021 14:03:12 +0100 Subject: media: allegro: lookup VCU settings The VCU provides information about its configuration in a dedicated register space. These settings include, for example, the expected clock rates and the configuration of the encoder buffer. In the device tree, the settings are described by the "xlnx,vcu-settings" compatible. The settings are needed to correctly configure the clocks and the encoder buffer. Lookup the VCU settings in the device tree and make it accessible to the driver via a regmap. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/allegro-dvt/allegro-core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 89d6de6082f6..2663d9da0522 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -136,6 +138,7 @@ struct allegro_dev { struct regmap *regmap; struct regmap *sram; + struct regmap *settings; const struct fw_info *fw_info; struct allegro_buffer firmware; @@ -3721,6 +3724,10 @@ static int allegro_probe(struct platform_device *pdev) return PTR_ERR(dev->sram); } + dev->settings = syscon_regmap_lookup_by_compatible("xlnx,vcu-settings"); + if (IS_ERR(dev->settings)) + dev_warn(&pdev->dev, "failed to open settings\n"); + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; -- cgit v1.2.3 From 83cc5fd9c622d3c322bb450d5c237c4c3ceaefa0 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 8 Sep 2021 14:03:13 +0100 Subject: media: allegro: add pm_runtime support The allegro driver must ensure that the mcu and core clocks are enabled and set to the expected clock rate before trying to load the firmware and to reset the MCU. Up until now, the driver assumed that the clocks are always enabled in the PL (programming logic), because the xlnx_vcu driver did not export the clocks to other drivers. This has changed and by explicitly enabling the clocks in the driver, this assumption can be dropped. It might even be possible to disable the clocks for the encoder if the encoder is not used. However, the behavior is not documented and it might be necessary to reinitialize the encoder after deactivating the clocks. Play it safe by sticking to the current behavior. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/allegro-dvt/allegro-core.c | 85 ++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 2663d9da0522..3deece8176eb 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -140,6 +142,9 @@ struct allegro_dev { struct regmap *sram; struct regmap *settings; + struct clk *clk_core; + struct clk *clk_mcu; + const struct fw_info *fw_info; struct allegro_buffer firmware; struct allegro_buffer suballocator; @@ -3604,11 +3609,16 @@ static void allegro_fw_callback(const struct firmware *fw, void *context) v4l2_info(&dev->v4l2_dev, "using mcu firmware version '%s'\n", dev->fw_info->version); + pm_runtime_enable(&dev->plat_dev->dev); + err = pm_runtime_resume_and_get(&dev->plat_dev->dev); + if (err) + goto err_release_firmware_codec; + /* Ensure that the mcu is sleeping at the reset vector */ err = allegro_mcu_reset(dev); if (err) { v4l2_err(&dev->v4l2_dev, "failed to reset mcu\n"); - goto err_release_firmware_codec; + goto err_suspend; } allegro_copy_firmware(dev, fw->data, fw->size); @@ -3650,6 +3660,9 @@ err_mcu_hw_deinit: allegro_mcu_hw_deinit(dev); err_free_fw_codec: allegro_free_fw_codec(dev); +err_suspend: + pm_runtime_put(&dev->plat_dev->dev); + pm_runtime_disable(&dev->plat_dev->dev); err_release_firmware_codec: release_firmware(fw_codec); err_release_firmware: @@ -3728,6 +3741,14 @@ static int allegro_probe(struct platform_device *pdev) if (IS_ERR(dev->settings)) dev_warn(&pdev->dev, "failed to open settings\n"); + dev->clk_core = devm_clk_get(&pdev->dev, "core_clk"); + if (IS_ERR(dev->clk_core)) + return PTR_ERR(dev->clk_core); + + dev->clk_mcu = devm_clk_get(&pdev->dev, "mcu_clk"); + if (IS_ERR(dev->clk_mcu)) + return PTR_ERR(dev->clk_mcu); + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -3768,11 +3789,67 @@ static int allegro_remove(struct platform_device *pdev) allegro_free_fw_codec(dev); } + pm_runtime_put(&dev->plat_dev->dev); + pm_runtime_disable(&dev->plat_dev->dev); + v4l2_device_unregister(&dev->v4l2_dev); return 0; } +static int allegro_runtime_resume(struct device *device) +{ + struct allegro_dev *dev = dev_get_drvdata(device); + struct regmap *settings = dev->settings; + unsigned int clk_mcu; + unsigned int clk_core; + int err; + + if (!settings) + return -EINVAL; + +#define MHZ_TO_HZ(freq) ((freq) * 1000 * 1000) + + err = regmap_read(settings, VCU_CORE_CLK, &clk_core); + if (err < 0) + return err; + err = clk_set_rate(dev->clk_core, MHZ_TO_HZ(clk_core)); + if (err < 0) + return err; + err = clk_prepare_enable(dev->clk_core); + if (err) + return err; + + err = regmap_read(settings, VCU_MCU_CLK, &clk_mcu); + if (err < 0) + goto disable_clk_core; + err = clk_set_rate(dev->clk_mcu, MHZ_TO_HZ(clk_mcu)); + if (err < 0) + goto disable_clk_core; + err = clk_prepare_enable(dev->clk_mcu); + if (err) + goto disable_clk_core; + +#undef MHZ_TO_HZ + + return 0; + +disable_clk_core: + clk_disable_unprepare(dev->clk_core); + + return err; +} + +static int allegro_runtime_suspend(struct device *device) +{ + struct allegro_dev *dev = dev_get_drvdata(device); + + clk_disable_unprepare(dev->clk_mcu); + clk_disable_unprepare(dev->clk_core); + + return 0; +} + static const struct of_device_id allegro_dt_ids[] = { { .compatible = "allegro,al5e-1.1" }, { /* sentinel */ } @@ -3780,12 +3857,18 @@ static const struct of_device_id allegro_dt_ids[] = { MODULE_DEVICE_TABLE(of, allegro_dt_ids); +static const struct dev_pm_ops allegro_pm_ops = { + .runtime_resume = allegro_runtime_resume, + .runtime_suspend = allegro_runtime_suspend, +}; + static struct platform_driver allegro_driver = { .probe = allegro_probe, .remove = allegro_remove, .driver = { .name = "allegro", .of_match_table = of_match_ptr(allegro_dt_ids), + .pm = &allegro_pm_ops, }, }; -- cgit v1.2.3 From 98f1cbf65bf275cce2b9985a8d89cd4fc287a9cc Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 8 Sep 2021 14:03:14 +0100 Subject: media: allegro: add encoder buffer support The encoder buffer serves as a cache for reference frames during the encoding process. The encoder buffer significantly reduces the bandwidth requirement for read accesses on the AXI ports of the VCU, but slightly reduces the quality of the encoded video. The encoder buffer must be configured as a whole during the firmware initialization and later explicitly enabled for every channel that shall use the encoder buffer. Prior to firmware version 2019.2, it was necessary to explicitly set the size of the encoder buffer for every channel. Since 2019.2 it is sufficient to enable the encoder buffer and leave the rest to the firmware. Therefore, only support the encoder buffer for firmware 2019.2 and later. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/allegro-dvt/allegro-core.c | 83 +++++++++++++++++++++-- drivers/media/platform/allegro-dvt/allegro-mail.c | 19 +++--- drivers/media/platform/allegro-dvt/allegro-mail.h | 10 +-- 3 files changed, 90 insertions(+), 22 deletions(-) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 3deece8176eb..cb42b6e3d85a 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -129,6 +129,13 @@ struct allegro_mbox { struct mutex lock; }; +struct allegro_encoder_buffer { + unsigned int size; + unsigned int color_depth; + unsigned int num_cores; + unsigned int clk_rate; +}; + struct allegro_dev { struct v4l2_device v4l2_dev; struct video_device video_dev; @@ -148,6 +155,8 @@ struct allegro_dev { const struct fw_info *fw_info; struct allegro_buffer firmware; struct allegro_buffer suballocator; + bool has_encoder_buffer; + struct allegro_encoder_buffer encoder_buffer; struct completion init_complete; bool initialized; @@ -930,6 +939,52 @@ out: kfree(msg); } +static int allegro_encoder_buffer_init(struct allegro_dev *dev, + struct allegro_encoder_buffer *buffer) +{ + int err; + struct regmap *settings = dev->settings; + unsigned int supports_10_bit; + unsigned int memory_depth; + unsigned int num_cores; + unsigned int color_depth; + unsigned long clk_rate; + + /* We don't support the encoder buffer pre Firmware version 2019.2 */ + if (dev->fw_info->mailbox_version < MCU_MSG_VERSION_2019_2) + return -ENODEV; + + if (!settings) + return -EINVAL; + + err = regmap_read(settings, VCU_ENC_COLOR_DEPTH, &supports_10_bit); + if (err < 0) + return err; + err = regmap_read(settings, VCU_MEMORY_DEPTH, &memory_depth); + if (err < 0) + return err; + err = regmap_read(settings, VCU_NUM_CORE, &num_cores); + if (err < 0) + return err; + + clk_rate = clk_get_rate(dev->clk_core); + if (clk_rate == 0) + return -EINVAL; + + color_depth = supports_10_bit ? 10 : 8; + /* The firmware expects the encoder buffer size in bits. */ + buffer->size = color_depth * 32 * memory_depth; + buffer->color_depth = color_depth; + buffer->num_cores = num_cores; + buffer->clk_rate = clk_rate; + + v4l2_dbg(1, debug, &dev->v4l2_dev, + "using %d bits encoder buffer with %d-bit color depth\n", + buffer->size, color_depth); + + return 0; +} + static void allegro_mcu_send_init(struct allegro_dev *dev, dma_addr_t suballoc_dma, size_t suballoc_size) { @@ -943,10 +998,17 @@ static void allegro_mcu_send_init(struct allegro_dev *dev, msg.suballoc_dma = to_mcu_addr(dev, suballoc_dma); msg.suballoc_size = to_mcu_size(dev, suballoc_size); - /* disable L2 cache */ - msg.l2_cache[0] = -1; - msg.l2_cache[1] = -1; - msg.l2_cache[2] = -1; + if (dev->has_encoder_buffer) { + msg.encoder_buffer_size = dev->encoder_buffer.size; + msg.encoder_buffer_color_depth = dev->encoder_buffer.color_depth; + msg.num_cores = dev->encoder_buffer.num_cores; + msg.clk_rate = dev->encoder_buffer.clk_rate; + } else { + msg.encoder_buffer_size = -1; + msg.encoder_buffer_color_depth = -1; + msg.num_cores = -1; + msg.clk_rate = -1; + } allegro_mbox_send(dev->mbox_command, &msg); } @@ -1193,9 +1255,8 @@ static int fill_create_channel_param(struct allegro_channel *channel, param->max_transfo_depth_intra = channel->max_transfo_depth_intra; param->max_transfo_depth_inter = channel->max_transfo_depth_inter; - param->prefetch_auto = 0; - param->prefetch_mem_offset = 0; - param->prefetch_mem_size = 0; + param->encoder_buffer_enabled = channel->dev->has_encoder_buffer; + param->encoder_buffer_offset = 0; param->rate_control_mode = channel->frame_rc_enable ? v4l2_bitrate_mode_to_mcu_mode(bitrate_mode) : 0; @@ -1320,6 +1381,7 @@ static int allegro_mcu_send_encode_frame(struct allegro_dev *dev, u64 src_handle) { struct mcu_msg_encode_frame msg; + bool use_encoder_buffer = channel->dev->has_encoder_buffer; memset(&msg, 0, sizeof(msg)); @@ -1328,6 +1390,8 @@ static int allegro_mcu_send_encode_frame(struct allegro_dev *dev, msg.channel_id = channel->mcu_channel_id; msg.encoding_options = AL_OPT_FORCE_LOAD; + if (use_encoder_buffer) + msg.encoding_options |= AL_OPT_USE_L2; msg.pps_qp = 26; /* qp are relative to 26 */ msg.user_param = 0; /* copied to mcu_msg_encode_frame_response */ /* src_handle is copied to mcu_msg_encode_frame_response */ @@ -3522,6 +3586,11 @@ static int allegro_mcu_hw_init(struct allegro_dev *dev, return -EIO; } + err = allegro_encoder_buffer_init(dev, &dev->encoder_buffer); + dev->has_encoder_buffer = (err == 0); + if (!dev->has_encoder_buffer) + v4l2_info(&dev->v4l2_dev, "encoder buffer not available\n"); + allegro_mcu_enable_interrupts(dev); /* The mcu sends INIT after reset. */ diff --git a/drivers/media/platform/allegro-dvt/allegro-mail.c b/drivers/media/platform/allegro-dvt/allegro-mail.c index 7e08c5050f2e..d81fae3ed3e4 100644 --- a/drivers/media/platform/allegro-dvt/allegro-mail.c +++ b/drivers/media/platform/allegro-dvt/allegro-mail.c @@ -49,11 +49,11 @@ allegro_enc_init(u32 *dst, struct mcu_msg_init_request *msg) dst[i++] = msg->reserved0; dst[i++] = msg->suballoc_dma; dst[i++] = msg->suballoc_size; - dst[i++] = msg->l2_cache[0]; - dst[i++] = msg->l2_cache[1]; - dst[i++] = msg->l2_cache[2]; + dst[i++] = msg->encoder_buffer_size; + dst[i++] = msg->encoder_buffer_color_depth; + dst[i++] = msg->num_cores; if (version >= MCU_MSG_VERSION_2019_2) { - dst[i++] = -1; + dst[i++] = msg->clk_rate; dst[i++] = 0; } @@ -146,13 +146,10 @@ allegro_encode_config_blob(u32 *dst, struct create_channel_param *param) FIELD_PREP(GENMASK(7, 0), param->tc_offset); dst[i++] = param->unknown11; dst[i++] = param->unknown12; - if (version >= MCU_MSG_VERSION_2019_2) - dst[i++] = param->num_slices; - else - dst[i++] = FIELD_PREP(GENMASK(31, 16), param->prefetch_auto) | - FIELD_PREP(GENMASK(15, 0), param->num_slices); - dst[i++] = param->prefetch_mem_offset; - dst[i++] = param->prefetch_mem_size; + dst[i++] = param->num_slices; + dst[i++] = param->encoder_buffer_offset; + dst[i++] = param->encoder_buffer_enabled; + dst[i++] = FIELD_PREP(GENMASK(31, 16), param->clip_vrt_range) | FIELD_PREP(GENMASK(15, 0), param->clip_hrz_range); dst[i++] = FIELD_PREP(GENMASK(31, 16), param->me_range[1]) | diff --git a/drivers/media/platform/allegro-dvt/allegro-mail.h b/drivers/media/platform/allegro-dvt/allegro-mail.h index 2c7bc509eac3..a5686058d754 100644 --- a/drivers/media/platform/allegro-dvt/allegro-mail.h +++ b/drivers/media/platform/allegro-dvt/allegro-mail.h @@ -37,7 +37,10 @@ struct mcu_msg_init_request { u32 reserved0; /* maybe a unused channel id */ u32 suballoc_dma; u32 suballoc_size; - s32 l2_cache[3]; + s32 encoder_buffer_size; + s32 encoder_buffer_color_depth; + s32 num_cores; + s32 clk_rate; }; struct mcu_msg_init_response { @@ -79,9 +82,8 @@ struct create_channel_param { u32 unknown11; u32 unknown12; u16 num_slices; - u16 prefetch_auto; - u32 prefetch_mem_offset; - u32 prefetch_mem_size; + u32 encoder_buffer_offset; + u32 encoder_buffer_enabled; u16 clip_hrz_range; u16 clip_vrt_range; u16 me_range[4]; -- cgit v1.2.3 From 7aea2c0b48a568e6732c1d30516febe36bf555f1 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 8 Sep 2021 14:03:15 +0100 Subject: media: allegro: add control to disable encoder buffer The encoder buffer can have a negative impact on the quality of the encoded video. Add a control to allow user space to disable the encoder buffer per channel if the VCU supports the encoder buffer but the quality is not sufficient. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/allegro-dvt/allegro-core.c | 32 +++++++++++++++++++++-- include/uapi/linux/v4l2-controls.h | 5 ++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index cb42b6e3d85a..7ec85299d03e 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -105,6 +105,12 @@ #define BETA_OFFSET_DIV_2 -1 #define TC_OFFSET_DIV_2 -1 +/* + * This control allows applications to explicitly disable the encoder buffer. + * This value is Allegro specific. + */ +#define V4L2_CID_USER_ALLEGRO_ENCODER_BUFFER (V4L2_CID_USER_ALLEGRO_BASE + 0) + static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-2)"); @@ -275,6 +281,8 @@ struct allegro_channel { struct v4l2_ctrl *mpeg_video_cpb_size; struct v4l2_ctrl *mpeg_video_gop_size; + struct v4l2_ctrl *encoder_buffer; + /* user_id is used to identify the channel during CREATE_CHANNEL */ /* not sure, what to set here and if this is actually required */ int user_id; @@ -1255,7 +1263,7 @@ static int fill_create_channel_param(struct allegro_channel *channel, param->max_transfo_depth_intra = channel->max_transfo_depth_intra; param->max_transfo_depth_inter = channel->max_transfo_depth_inter; - param->encoder_buffer_enabled = channel->dev->has_encoder_buffer; + param->encoder_buffer_enabled = v4l2_ctrl_g_ctrl(channel->encoder_buffer); param->encoder_buffer_offset = 0; param->rate_control_mode = channel->frame_rc_enable ? @@ -1381,7 +1389,7 @@ static int allegro_mcu_send_encode_frame(struct allegro_dev *dev, u64 src_handle) { struct mcu_msg_encode_frame msg; - bool use_encoder_buffer = channel->dev->has_encoder_buffer; + bool use_encoder_buffer = v4l2_ctrl_g_ctrl(channel->encoder_buffer); memset(&msg, 0, sizeof(msg)); @@ -2466,6 +2474,8 @@ static void allegro_destroy_channel(struct allegro_channel *channel) v4l2_ctrl_grab(channel->mpeg_video_cpb_size, false); v4l2_ctrl_grab(channel->mpeg_video_gop_size, false); + v4l2_ctrl_grab(channel->encoder_buffer, false); + if (channel->user_id != -1) { clear_bit(channel->user_id, &dev->channel_user_ids); channel->user_id = -1; @@ -2532,6 +2542,8 @@ static int allegro_create_channel(struct allegro_channel *channel) v4l2_ctrl_grab(channel->mpeg_video_cpb_size, true); v4l2_ctrl_grab(channel->mpeg_video_gop_size, true); + v4l2_ctrl_grab(channel->encoder_buffer, true); + reinit_completion(&channel->completion); allegro_mcu_send_create_channel(dev, channel); timeout = wait_for_completion_timeout(&channel->completion, @@ -2915,6 +2927,10 @@ static int allegro_try_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: allegro_clamp_bitrate(channel, ctrl); break; + case V4L2_CID_USER_ALLEGRO_ENCODER_BUFFER: + if (!channel->dev->has_encoder_buffer) + ctrl->val = 0; + break; } return 0; @@ -2955,6 +2971,16 @@ static const struct v4l2_ctrl_ops allegro_ctrl_ops = { .s_ctrl = allegro_s_ctrl, }; +static const struct v4l2_ctrl_config allegro_encoder_buffer_ctrl_config = { + .id = V4L2_CID_USER_ALLEGRO_ENCODER_BUFFER, + .name = "Encoder Buffer Enable", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + static int allegro_open(struct file *file) { struct video_device *vdev = video_devdata(file); @@ -3106,6 +3132,8 @@ static int allegro_open(struct file *file) V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, ALLEGRO_GOP_SIZE_MAX, 1, ALLEGRO_GOP_SIZE_DEFAULT); + channel->encoder_buffer = v4l2_ctrl_new_custom(handler, + &allegro_encoder_buffer_ctrl_config, NULL); v4l2_ctrl_new_std(handler, &allegro_ctrl_ops, V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 133e20444939..5fea5feb0412 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -211,6 +211,11 @@ enum v4l2_colorfx { * We reserve 128 controls for this driver. */ #define V4L2_CID_USER_CCS_BASE (V4L2_CID_USER_BASE + 0x10f0) +/* + * The base for Allegro driver controls. + * We reserve 16 controls for this driver. + */ +#define V4L2_CID_USER_ALLEGRO_BASE (V4L2_CID_USER_BASE + 0x1170) /* MPEG-class control IDs */ /* The MPEG controls are applicable to all codec controls -- cgit v1.2.3 From 436ee4b515bb9a63f68f9d1917c7df75010c251d Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 8 Sep 2021 14:03:49 +0100 Subject: media: allegro: fix row and column in response message The fields for the number of rows and columns in the encode frame response message are switched. This causes broken PPS, if the encoder uses tiles for encoding and the number of rows and columns differ. Write the fields of the response message into the correct fields of the the internal data structure when parsing the response message. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/allegro-dvt/allegro-mail.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/allegro-dvt/allegro-mail.c b/drivers/media/platform/allegro-dvt/allegro-mail.c index d81fae3ed3e4..16effad10746 100644 --- a/drivers/media/platform/allegro-dvt/allegro-mail.c +++ b/drivers/media/platform/allegro-dvt/allegro-mail.c @@ -426,8 +426,8 @@ allegro_dec_encode_frame(struct mcu_msg_encode_frame_response *msg, u32 *src) msg->frame_tag_size = src[i++]; msg->stuffing = src[i++]; msg->filler = src[i++]; - msg->num_column = FIELD_GET(GENMASK(31, 16), src[i]); - msg->num_row = FIELD_GET(GENMASK(15, 0), src[i++]); + msg->num_row = FIELD_GET(GENMASK(31, 16), src[i]); + msg->num_column = FIELD_GET(GENMASK(15, 0), src[i++]); msg->num_ref_idx_l1 = FIELD_GET(GENMASK(31, 24), src[i]); msg->num_ref_idx_l0 = FIELD_GET(GENMASK(23, 16), src[i]); msg->qp = FIELD_GET(GENMASK(15, 0), src[i++]); -- cgit v1.2.3 From c0a3753c5a608399a3e0de8a1f405d1197143c6b Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 8 Sep 2021 14:03:50 +0100 Subject: media: allegro: remove external QP table The VCU allows to specify the QP per frame and coding unit. A buffer that specifies the QP is passed via the ep2 field in the ENCODE_FRAME message. The driver currently does not support the external QP table. Simplify the driver by not setting the ep2 fields at all. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/allegro-dvt/allegro-core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 7ec85299d03e..52924ce142cc 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -1407,8 +1407,6 @@ static int allegro_mcu_send_encode_frame(struct allegro_dev *dev, msg.src_y = to_codec_addr(dev, src_y); msg.src_uv = to_codec_addr(dev, src_uv); msg.stride = channel->stride; - msg.ep2 = 0x0; - msg.ep2_v = to_mcu_addr(dev, msg.ep2); allegro_mbox_send(dev->mbox_command, &msg); -- cgit v1.2.3 From 89091e12464ace837bb72c5d20173c069481afd2 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 8 Sep 2021 14:03:51 +0100 Subject: media: allegro: correctly scale the bit rate in SPS The bit rate in the SPS can be scaled by an exponent, which allows to reduce the number of bits in the SPS in case of high bit rates. The driver did not scale the bitrate, but used a scaling exponent of 0. Fix this by properly calculating the scaling factor and writing the bit rate as value and scaling factor into the SPS. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/allegro-dvt/allegro-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 52924ce142cc..777cbc526ae3 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -1639,8 +1639,9 @@ static ssize_t allegro_h264_write_sps(struct allegro_channel *channel, sps->vui.nal_hrd_parameters_present_flag = 0; sps->vui.vcl_hrd_parameters_present_flag = 1; sps->vui.vcl_hrd_parameters.cpb_cnt_minus1 = 0; - sps->vui.vcl_hrd_parameters.bit_rate_scale = 0; /* See Rec. ITU-T H.264 (04/2017) p. 410 E-53 */ + sps->vui.vcl_hrd_parameters.bit_rate_scale = + ffs(channel->bitrate_peak) - 6; sps->vui.vcl_hrd_parameters.bit_rate_value_minus1[0] = channel->bitrate_peak / (1 << (6 + sps->vui.vcl_hrd_parameters.bit_rate_scale)) - 1; /* See Rec. ITU-T H.264 (04/2017) p. 410 E-54 */ -- cgit v1.2.3 From e5c28f21916df73c5d794fa82d79ca3cce7ea1f3 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 8 Sep 2021 14:03:52 +0100 Subject: media: allegro: extract nal value lookup functions to header The lookup of the h.264 or hevc values for the respective V4L2 controls is done by the driver that uses the sps/pps generator and not in the generator. Therefore, it is more intuitive to define these functions directly in the header and not in the module. Extract the functions to the headers as static inline functions. Also simplify the function name and add kernel-doc for the hevc functions. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/allegro-dvt/allegro-core.c | 16 ++-- drivers/media/platform/allegro-dvt/nal-h264.c | 74 ---------------- drivers/media/platform/allegro-dvt/nal-h264.h | 78 ++++++++++++++++- drivers/media/platform/allegro-dvt/nal-hevc.c | 70 --------------- drivers/media/platform/allegro-dvt/nal-hevc.h | 100 +++++++++++++++++++++- 5 files changed, 180 insertions(+), 158 deletions(-) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 777cbc526ae3..d157c1b2585b 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -1588,14 +1588,14 @@ static ssize_t allegro_h264_write_sps(struct allegro_channel *channel, profile = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_profile); level = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_level); - sps->profile_idc = nal_h264_profile_from_v4l2(profile); + sps->profile_idc = nal_h264_profile(profile); sps->constraint_set0_flag = 0; sps->constraint_set1_flag = 1; sps->constraint_set2_flag = 0; sps->constraint_set3_flag = 0; sps->constraint_set4_flag = 0; sps->constraint_set5_flag = 0; - sps->level_idc = nal_h264_level_from_v4l2(level); + sps->level_idc = nal_h264_level(level); sps->seq_parameter_set_id = 0; sps->log2_max_frame_num_minus4 = LOG2_MAX_FRAME_NUM - 4; sps->pic_order_cnt_type = 0; @@ -1734,12 +1734,12 @@ static ssize_t allegro_hevc_write_vps(struct allegro_channel *channel, vps->temporal_id_nesting_flag = 1; ptl = &vps->profile_tier_level; - ptl->general_profile_idc = nal_hevc_profile_from_v4l2(profile); + ptl->general_profile_idc = nal_hevc_profile(profile); ptl->general_profile_compatibility_flag[ptl->general_profile_idc] = 1; - ptl->general_tier_flag = nal_hevc_tier_from_v4l2(tier); + ptl->general_tier_flag = nal_hevc_tier(tier); ptl->general_progressive_source_flag = 1; ptl->general_frame_only_constraint_flag = 1; - ptl->general_level_idc = nal_hevc_level_from_v4l2(level); + ptl->general_level_idc = nal_hevc_level(level); vps->sub_layer_ordering_info_present_flag = 0; vps->max_dec_pic_buffering_minus1[0] = num_ref_frames; @@ -1771,12 +1771,12 @@ static ssize_t allegro_hevc_write_sps(struct allegro_channel *channel, sps->temporal_id_nesting_flag = 1; ptl = &sps->profile_tier_level; - ptl->general_profile_idc = nal_hevc_profile_from_v4l2(profile); + ptl->general_profile_idc = nal_hevc_profile(profile); ptl->general_profile_compatibility_flag[ptl->general_profile_idc] = 1; - ptl->general_tier_flag = nal_hevc_tier_from_v4l2(tier); + ptl->general_tier_flag = nal_hevc_tier(tier); ptl->general_progressive_source_flag = 1; ptl->general_frame_only_constraint_flag = 1; - ptl->general_level_idc = nal_hevc_level_from_v4l2(level); + ptl->general_level_idc = nal_hevc_level(level); sps->seq_parameter_set_id = 0; sps->chroma_format_idc = 1; /* Only 4:2:0 sampling supported */ diff --git a/drivers/media/platform/allegro-dvt/nal-h264.c b/drivers/media/platform/allegro-dvt/nal-h264.c index 0ab2fcbee1b9..32663766340f 100644 --- a/drivers/media/platform/allegro-dvt/nal-h264.c +++ b/drivers/media/platform/allegro-dvt/nal-h264.c @@ -34,80 +34,6 @@ enum nal_unit_type { FILLER_DATA = 12, }; -/** - * nal_h264_profile_from_v4l2() - Get profile_idc for v4l2 h264 profile - * @profile: the profile as &enum v4l2_mpeg_video_h264_profile - * - * Convert the &enum v4l2_mpeg_video_h264_profile to profile_idc as specified - * in Rec. ITU-T H.264 (04/2017) A.2. - * - * Return: the profile_idc for the passed level - */ -int nal_h264_profile_from_v4l2(enum v4l2_mpeg_video_h264_profile profile) -{ - switch (profile) { - case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: - return 66; - case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: - return 77; - case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: - return 88; - case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: - return 100; - default: - return -EINVAL; - } -} - -/** - * nal_h264_level_from_v4l2() - Get level_idc for v4l2 h264 level - * @level: the level as &enum v4l2_mpeg_video_h264_level - * - * Convert the &enum v4l2_mpeg_video_h264_level to level_idc as specified in - * Rec. ITU-T H.264 (04/2017) A.3.2. - * - * Return: the level_idc for the passed level - */ -int nal_h264_level_from_v4l2(enum v4l2_mpeg_video_h264_level level) -{ - switch (level) { - case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: - return 10; - case V4L2_MPEG_VIDEO_H264_LEVEL_1B: - return 9; - case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: - return 11; - case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: - return 12; - case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: - return 13; - case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: - return 20; - case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: - return 21; - case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: - return 22; - case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: - return 30; - case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: - return 31; - case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: - return 32; - case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: - return 40; - case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: - return 41; - case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: - return 42; - case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: - return 50; - case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: - return 51; - default: - return -EINVAL; - } -} - static void nal_h264_write_start_code_prefix(struct rbsp *rbsp) { u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8); diff --git a/drivers/media/platform/allegro-dvt/nal-h264.h b/drivers/media/platform/allegro-dvt/nal-h264.h index a19634fe8c0b..a7ad437687e7 100644 --- a/drivers/media/platform/allegro-dvt/nal-h264.h +++ b/drivers/media/platform/allegro-dvt/nal-h264.h @@ -8,8 +8,11 @@ #ifndef __NAL_H264_H__ #define __NAL_H264_H__ +#include #include #include +#include +#include /* * struct nal_h264_hrd_parameters - HRD parameters @@ -187,8 +190,79 @@ struct nal_h264_pps { }; }; -int nal_h264_profile_from_v4l2(enum v4l2_mpeg_video_h264_profile profile); -int nal_h264_level_from_v4l2(enum v4l2_mpeg_video_h264_level level); +/** + * nal_h264_profile() - Get profile_idc for v4l2 h264 profile + * @profile: the profile as &enum v4l2_mpeg_video_h264_profile + * + * Convert the &enum v4l2_mpeg_video_h264_profile to profile_idc as specified + * in Rec. ITU-T H.264 (04/2017) A.2. + * + * Return: the profile_idc for the passed level + */ +static inline int nal_h264_profile(enum v4l2_mpeg_video_h264_profile profile) +{ + switch (profile) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + return 66; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + return 77; + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: + return 88; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + return 100; + default: + return -EINVAL; + } +} + +/** + * nal_h264_level() - Get level_idc for v4l2 h264 level + * @level: the level as &enum v4l2_mpeg_video_h264_level + * + * Convert the &enum v4l2_mpeg_video_h264_level to level_idc as specified in + * Rec. ITU-T H.264 (04/2017) A.3.2. + * + * Return: the level_idc for the passed level + */ +static inline int nal_h264_level(enum v4l2_mpeg_video_h264_level level) +{ + switch (level) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + return 10; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + return 9; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + return 11; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + return 12; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + return 13; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + return 20; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + return 21; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + return 22; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + return 30; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + return 31; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + return 32; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + return 40; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + return 41; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + return 42; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + return 50; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + return 51; + default: + return -EINVAL; + } +} ssize_t nal_h264_write_sps(const struct device *dev, void *dest, size_t n, struct nal_h264_sps *sps); diff --git a/drivers/media/platform/allegro-dvt/nal-hevc.c b/drivers/media/platform/allegro-dvt/nal-hevc.c index 15a352e45831..0999a2bdc812 100644 --- a/drivers/media/platform/allegro-dvt/nal-hevc.c +++ b/drivers/media/platform/allegro-dvt/nal-hevc.c @@ -35,76 +35,6 @@ enum nal_unit_type { FD_NUT = 38, }; -int nal_hevc_profile_from_v4l2(enum v4l2_mpeg_video_hevc_profile profile) -{ - switch (profile) { - case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: - return 1; - case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10: - return 2; - case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: - return 3; - default: - return -EINVAL; - } -} -EXPORT_SYMBOL_GPL(nal_hevc_profile_from_v4l2); - -int nal_hevc_tier_from_v4l2(enum v4l2_mpeg_video_hevc_tier tier) -{ - switch (tier) { - case V4L2_MPEG_VIDEO_HEVC_TIER_MAIN: - return 0; - case V4L2_MPEG_VIDEO_HEVC_TIER_HIGH: - return 1; - default: - return -EINVAL; - } -} -EXPORT_SYMBOL_GPL(nal_hevc_tier_from_v4l2); - -int nal_hevc_level_from_v4l2(enum v4l2_mpeg_video_hevc_level level) -{ - /* - * T-Rec-H.265 p. 280: general_level_idc and sub_layer_level_idc[ i ] - * shall be set equal to a value of 30 times the level number - * specified in Table A.6. - */ - int factor = 30 / 10; - - switch (level) { - case V4L2_MPEG_VIDEO_HEVC_LEVEL_1: - return factor * 10; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_2: - return factor * 20; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1: - return factor * 21; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_3: - return factor * 30; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1: - return factor * 31; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_4: - return factor * 40; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1: - return factor * 41; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_5: - return factor * 50; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1: - return factor * 51; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2: - return factor * 52; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_6: - return factor * 60; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1: - return factor * 61; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2: - return factor * 62; - default: - return -EINVAL; - } -} -EXPORT_SYMBOL_GPL(nal_hevc_level_from_v4l2); - static void nal_hevc_write_start_code_prefix(struct rbsp *rbsp) { u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8); diff --git a/drivers/media/platform/allegro-dvt/nal-hevc.h b/drivers/media/platform/allegro-dvt/nal-hevc.h index c09bbe5446aa..fb899d162bd9 100644 --- a/drivers/media/platform/allegro-dvt/nal-hevc.h +++ b/drivers/media/platform/allegro-dvt/nal-hevc.h @@ -8,9 +8,11 @@ #ifndef __NAL_HEVC_H__ #define __NAL_HEVC_H__ +#include #include #include -#include +#include +#include struct nal_hevc_profile_tier_level { unsigned int general_profile_space; @@ -318,9 +320,99 @@ struct nal_hevc_pps { }; }; -int nal_hevc_profile_from_v4l2(enum v4l2_mpeg_video_hevc_profile profile); -int nal_hevc_tier_from_v4l2(enum v4l2_mpeg_video_hevc_tier tier); -int nal_hevc_level_from_v4l2(enum v4l2_mpeg_video_hevc_level level); +/** + * nal_hevc_profile() - Get profile_idc for v4l2 hevc profile + * @profile: the profile as &enum v4l2_mpeg_video_hevc_profile + * + * Convert the &enum v4l2_mpeg_video_hevc_profile to profile_idc as specified + * in Rec. ITU-T H.265 (02/2018) A.3. + * + * Return: the profile_idc for the passed level + */ +static inline int nal_hevc_profile(enum v4l2_mpeg_video_hevc_profile profile) +{ + switch (profile) { + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: + return 1; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10: + return 2; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: + return 3; + default: + return -EINVAL; + } +} + +/** + * nal_hevc_tier() - Get tier_flag for v4l2 hevc tier + * @tier: the tier as &enum v4l2_mpeg_video_hevc_tier + * + * Convert the &enum v4l2_mpeg_video_hevc_tier to tier_flag as specified + * in Rec. ITU-T H.265 (02/2018) A.4.1. + * + * Return: the tier_flag for the passed tier + */ +static inline int nal_hevc_tier(enum v4l2_mpeg_video_hevc_tier tier) +{ + switch (tier) { + case V4L2_MPEG_VIDEO_HEVC_TIER_MAIN: + return 0; + case V4L2_MPEG_VIDEO_HEVC_TIER_HIGH: + return 1; + default: + return -EINVAL; + } +} + +/** + * nal_hevc_level() - Get level_idc for v4l2 hevc level + * @level: the level as &enum v4l2_mpeg_video_hevc_level + * + * Convert the &enum v4l2_mpeg_video_hevc_level to level_idc as specified in + * Rec. ITU-T H.265 (02/2018) A.4.1. + * + * Return: the level_idc for the passed level + */ +static inline int nal_hevc_level(enum v4l2_mpeg_video_hevc_level level) +{ + /* + * T-Rec-H.265 p. 280: general_level_idc and sub_layer_level_idc[ i ] + * shall be set equal to a value of 30 times the level number + * specified in Table A.6. + */ + int factor = 30 / 10; + + switch (level) { + case V4L2_MPEG_VIDEO_HEVC_LEVEL_1: + return factor * 10; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2: + return factor * 20; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1: + return factor * 21; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3: + return factor * 30; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1: + return factor * 31; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4: + return factor * 40; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1: + return factor * 41; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5: + return factor * 50; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1: + return factor * 51; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2: + return factor * 52; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_6: + return factor * 60; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1: + return factor * 61; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2: + return factor * 62; + default: + return -EINVAL; + } +} int nal_range_from_v4l2(enum v4l2_quantization quantization); int nal_color_primaries_from_v4l2(enum v4l2_colorspace colorspace); -- cgit v1.2.3 From 0317c05fa15b64fe10b832eeab2354cf1b8ec831 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 8 Sep 2021 14:03:53 +0100 Subject: media: allegro: write correct colorspace into SPS Currently, the driver always writes PAL as video format into the SPS of the encoded stream. Set the video format to the default value 5 (unspecified) and use the color description that is already configured on the channel as color space. This fixes the color space definition in the coded data to reflect the configured color space of the video data that is encoded. Add lookup functions to convert the color primaries, transfer function and matrix coefficients from the V4L2 control values to the values specified in the h.264 standard. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/allegro-dvt/allegro-core.c | 14 ++- drivers/media/platform/allegro-dvt/nal-h264.h | 122 ++++++++++++++++++++++ 2 files changed, 131 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index d157c1b2585b..752c5562069b 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -1620,13 +1620,17 @@ static ssize_t allegro_h264_write_sps(struct allegro_channel *channel, sps->vui_parameters_present_flag = 1; sps->vui.aspect_ratio_info_present_flag = 0; sps->vui.overscan_info_present_flag = 0; + sps->vui.video_signal_type_present_flag = 1; - sps->vui.video_format = 1; - sps->vui.video_full_range_flag = 0; + sps->vui.video_format = 5; /* unspecified */ + sps->vui.video_full_range_flag = nal_h264_full_range(channel->quantization); sps->vui.colour_description_present_flag = 1; - sps->vui.colour_primaries = 5; - sps->vui.transfer_characteristics = 5; - sps->vui.matrix_coefficients = 5; + sps->vui.colour_primaries = nal_h264_color_primaries(channel->colorspace); + sps->vui.transfer_characteristics = + nal_h264_transfer_characteristics(channel->colorspace, channel->xfer_func); + sps->vui.matrix_coefficients = + nal_h264_matrix_coeffs(channel->colorspace, channel->ycbcr_enc); + sps->vui.chroma_loc_info_present_flag = 1; sps->vui.chroma_sample_loc_type_top_field = 0; sps->vui.chroma_sample_loc_type_bottom_field = 0; diff --git a/drivers/media/platform/allegro-dvt/nal-h264.h b/drivers/media/platform/allegro-dvt/nal-h264.h index a7ad437687e7..34db07cda652 100644 --- a/drivers/media/platform/allegro-dvt/nal-h264.h +++ b/drivers/media/platform/allegro-dvt/nal-h264.h @@ -264,6 +264,128 @@ static inline int nal_h264_level(enum v4l2_mpeg_video_h264_level level) } } +/** + * nal_h264_full_range() - Get video_full_range_flag for v4l2 quantization + * @quantization: the quantization type as &enum v4l2_quantization + * + * Convert the &enum v4l2_quantization to video_full_range_flag as specified in + * Rec. ITU-T H.264 (04/2017) E.2.1. + * + * Return: the video_full_range_flag value for the passed quantization + */ +static inline int nal_h264_full_range(enum v4l2_quantization quantization) +{ + switch (quantization) { + case V4L2_QUANTIZATION_FULL_RANGE: + return 1; + case V4L2_QUANTIZATION_LIM_RANGE: + return 0; + default: + break; + } + + return 0; +} + +/** + * nal_h264_color_primaries() - Get color_primaries for v4l2 colorspace + * @colorspace: the color space as &enum v4l2_colorspace + * + * Convert the &enum v4l2_colorspace to color_primaries as specified in + * Rec. ITU-T H.264 (04/2017) E.2.1. + * + * Return: the color_primaries value for the passed colorspace + */ +static inline int nal_h264_color_primaries(enum v4l2_colorspace colorspace) +{ + switch (colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + return 6; + case V4L2_COLORSPACE_SMPTE240M: + return 7; + case V4L2_COLORSPACE_REC709: + return 1; + case V4L2_COLORSPACE_470_SYSTEM_M: + return 4; + case V4L2_COLORSPACE_JPEG: + case V4L2_COLORSPACE_SRGB: + case V4L2_COLORSPACE_470_SYSTEM_BG: + return 5; + case V4L2_COLORSPACE_BT2020: + return 9; + case V4L2_COLORSPACE_DEFAULT: + case V4L2_COLORSPACE_OPRGB: + case V4L2_COLORSPACE_RAW: + case V4L2_COLORSPACE_DCI_P3: + default: + return 2; + } +} + +/** + * nal_h264_transfer_characteristics() - Get transfer_characteristics for v4l2 xfer_func + * @colorspace: the color space as &enum v4l2_colorspace + * @xfer_func: the transfer function as &enum v4l2_xfer_func + * + * Convert the &enum v4l2_xfer_func to transfer_characteristics as specified in + * Rec. ITU-T H.264 (04/2017) E.2.1. + * + * Return: the transfer_characteristics value for the passed transfer function + */ +static inline int nal_h264_transfer_characteristics(enum v4l2_colorspace colorspace, + enum v4l2_xfer_func xfer_func) +{ + if (xfer_func == V4L2_XFER_FUNC_DEFAULT) + xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(colorspace); + + switch (xfer_func) { + case V4L2_XFER_FUNC_709: + return 6; + case V4L2_XFER_FUNC_SMPTE2084: + return 16; + case V4L2_XFER_FUNC_SRGB: + case V4L2_XFER_FUNC_OPRGB: + case V4L2_XFER_FUNC_NONE: + case V4L2_XFER_FUNC_DCI_P3: + case V4L2_XFER_FUNC_SMPTE240M: + default: + return 2; + } +} + +/** + * nal_h264_matrix_coeffs() - Get matrix_coefficients for v4l2 v4l2_ycbcr_encoding + * @colorspace: the color space as &enum v4l2_colorspace + * @ycbcr_encoding: the ycbcr encoding as &enum v4l2_ycbcr_encoding + * + * Convert the &enum v4l2_ycbcr_encoding to matrix_coefficients as specified in + * Rec. ITU-T H.264 (04/2017) E.2.1. + * + * Return: the matrix_coefficients value for the passed encoding + */ +static inline int nal_h264_matrix_coeffs(enum v4l2_colorspace colorspace, + enum v4l2_ycbcr_encoding ycbcr_encoding) +{ + if (ycbcr_encoding == V4L2_YCBCR_ENC_DEFAULT) + ycbcr_encoding = V4L2_MAP_YCBCR_ENC_DEFAULT(colorspace); + + switch (ycbcr_encoding) { + case V4L2_YCBCR_ENC_601: + case V4L2_YCBCR_ENC_XV601: + return 5; + case V4L2_YCBCR_ENC_709: + case V4L2_YCBCR_ENC_XV709: + return 1; + case V4L2_YCBCR_ENC_BT2020: + return 9; + case V4L2_YCBCR_ENC_BT2020_CONST_LUM: + return 10; + case V4L2_YCBCR_ENC_SMPTE240M: + default: + return 2; + } +} + ssize_t nal_h264_write_sps(const struct device *dev, void *dest, size_t n, struct nal_h264_sps *sps); ssize_t nal_h264_read_sps(const struct device *dev, -- cgit v1.2.3 From 42fd280628bd0a78f72b49916e8ed2dfabb63a27 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 8 Sep 2021 14:03:54 +0100 Subject: media: allegro: nal-hevc: implement generator for vui The NAL unit generator for HEVC does not support the generation of vui parameters. Implement it to allow drivers to set the vui parameters in the coded video stream. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/allegro-dvt/nal-hevc.c | 132 +++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/allegro-dvt/nal-hevc.c b/drivers/media/platform/allegro-dvt/nal-hevc.c index 0999a2bdc812..9cdf2756e0a3 100644 --- a/drivers/media/platform/allegro-dvt/nal-hevc.c +++ b/drivers/media/platform/allegro-dvt/nal-hevc.c @@ -207,6 +207,136 @@ static void nal_hevc_rbsp_vps(struct rbsp *rbsp, struct nal_hevc_vps *vps) rbsp_unsupported(rbsp); } +static void nal_hevc_rbsp_sub_layer_hrd_parameters(struct rbsp *rbsp, + struct nal_hevc_sub_layer_hrd_parameters *hrd) +{ + unsigned int i; + unsigned int cpb_cnt = 1; + + for (i = 0; i < cpb_cnt; i++) { + rbsp_uev(rbsp, &hrd->bit_rate_value_minus1[i]); + rbsp_uev(rbsp, &hrd->cpb_size_value_minus1[i]); + rbsp_bit(rbsp, &hrd->cbr_flag[i]); + } +} + +static void nal_hevc_rbsp_hrd_parameters(struct rbsp *rbsp, + struct nal_hevc_hrd_parameters *hrd) +{ + unsigned int i; + unsigned int max_num_sub_layers_minus_1 = 0; + + rbsp_bit(rbsp, &hrd->nal_hrd_parameters_present_flag); + rbsp_bit(rbsp, &hrd->vcl_hrd_parameters_present_flag); + if (hrd->nal_hrd_parameters_present_flag || hrd->vcl_hrd_parameters_present_flag) { + rbsp_bit(rbsp, &hrd->sub_pic_hrd_params_present_flag); + if (hrd->sub_pic_hrd_params_present_flag) { + rbsp_bits(rbsp, 8, &hrd->tick_divisor_minus2); + rbsp_bits(rbsp, 5, &hrd->du_cpb_removal_delay_increment_length_minus1); + rbsp_bit(rbsp, &hrd->sub_pic_cpb_params_in_pic_timing_sei_flag); + rbsp_bits(rbsp, 5, &hrd->dpb_output_delay_du_length_minus1); + } + rbsp_bits(rbsp, 4, &hrd->bit_rate_scale); + rbsp_bits(rbsp, 4, &hrd->cpb_size_scale); + if (hrd->sub_pic_hrd_params_present_flag) + rbsp_bits(rbsp, 4, &hrd->cpb_size_du_scale); + rbsp_bits(rbsp, 5, &hrd->initial_cpb_removal_delay_length_minus1); + rbsp_bits(rbsp, 5, &hrd->au_cpb_removal_delay_length_minus1); + rbsp_bits(rbsp, 5, &hrd->dpb_output_delay_length_minus1); + } + for (i = 0; i <= max_num_sub_layers_minus_1; i++) { + rbsp_bit(rbsp, &hrd->fixed_pic_rate_general_flag[i]); + if (!hrd->fixed_pic_rate_general_flag[i]) + rbsp_bit(rbsp, &hrd->fixed_pic_rate_within_cvs_flag[i]); + if (hrd->fixed_pic_rate_within_cvs_flag[i]) + rbsp_uev(rbsp, &hrd->elemental_duration_in_tc_minus1[i]); + else + rbsp_bit(rbsp, &hrd->low_delay_hrd_flag[i]); + if (!hrd->low_delay_hrd_flag[i]) + rbsp_uev(rbsp, &hrd->cpb_cnt_minus1[i]); + if (hrd->nal_hrd_parameters_present_flag) + nal_hevc_rbsp_sub_layer_hrd_parameters(rbsp, &hrd->vcl_hrd[i]); + if (hrd->vcl_hrd_parameters_present_flag) + nal_hevc_rbsp_sub_layer_hrd_parameters(rbsp, &hrd->vcl_hrd[i]); + } +} + +static void nal_hevc_rbsp_vui_parameters(struct rbsp *rbsp, + struct nal_hevc_vui_parameters *vui) +{ + if (!vui) { + rbsp->error = -EINVAL; + return; + } + + rbsp_bit(rbsp, &vui->aspect_ratio_info_present_flag); + if (vui->aspect_ratio_info_present_flag) { + rbsp_bits(rbsp, 8, &vui->aspect_ratio_idc); + if (vui->aspect_ratio_idc == 255) { + rbsp_bits(rbsp, 16, &vui->sar_width); + rbsp_bits(rbsp, 16, &vui->sar_height); + } + } + + rbsp_bit(rbsp, &vui->overscan_info_present_flag); + if (vui->overscan_info_present_flag) + rbsp_bit(rbsp, &vui->overscan_appropriate_flag); + + rbsp_bit(rbsp, &vui->video_signal_type_present_flag); + if (vui->video_signal_type_present_flag) { + rbsp_bits(rbsp, 3, &vui->video_format); + rbsp_bit(rbsp, &vui->video_full_range_flag); + + rbsp_bit(rbsp, &vui->colour_description_present_flag); + if (vui->colour_description_present_flag) { + rbsp_bits(rbsp, 8, &vui->colour_primaries); + rbsp_bits(rbsp, 8, &vui->transfer_characteristics); + rbsp_bits(rbsp, 8, &vui->matrix_coeffs); + } + } + + rbsp_bit(rbsp, &vui->chroma_loc_info_present_flag); + if (vui->chroma_loc_info_present_flag) { + rbsp_uev(rbsp, &vui->chroma_sample_loc_type_top_field); + rbsp_uev(rbsp, &vui->chroma_sample_loc_type_bottom_field); + } + + rbsp_bit(rbsp, &vui->neutral_chroma_indication_flag); + rbsp_bit(rbsp, &vui->field_seq_flag); + rbsp_bit(rbsp, &vui->frame_field_info_present_flag); + rbsp_bit(rbsp, &vui->default_display_window_flag); + if (vui->default_display_window_flag) { + rbsp_uev(rbsp, &vui->def_disp_win_left_offset); + rbsp_uev(rbsp, &vui->def_disp_win_right_offset); + rbsp_uev(rbsp, &vui->def_disp_win_top_offset); + rbsp_uev(rbsp, &vui->def_disp_win_bottom_offset); + } + + rbsp_bit(rbsp, &vui->vui_timing_info_present_flag); + if (vui->vui_timing_info_present_flag) { + rbsp_bits(rbsp, 32, &vui->vui_num_units_in_tick); + rbsp_bits(rbsp, 32, &vui->vui_time_scale); + rbsp_bit(rbsp, &vui->vui_poc_proportional_to_timing_flag); + if (vui->vui_poc_proportional_to_timing_flag) + rbsp_uev(rbsp, &vui->vui_num_ticks_poc_diff_one_minus1); + rbsp_bit(rbsp, &vui->vui_hrd_parameters_present_flag); + if (vui->vui_hrd_parameters_present_flag) + nal_hevc_rbsp_hrd_parameters(rbsp, &vui->nal_hrd_parameters); + } + + rbsp_bit(rbsp, &vui->bitstream_restriction_flag); + if (vui->bitstream_restriction_flag) { + rbsp_bit(rbsp, &vui->tiles_fixed_structure_flag); + rbsp_bit(rbsp, &vui->motion_vectors_over_pic_boundaries_flag); + rbsp_bit(rbsp, &vui->restricted_ref_pic_lists_flag); + rbsp_uev(rbsp, &vui->min_spatial_segmentation_idc); + rbsp_uev(rbsp, &vui->max_bytes_per_pic_denom); + rbsp_uev(rbsp, &vui->max_bits_per_min_cu_denom); + rbsp_uev(rbsp, &vui->log2_max_mv_length_horizontal); + rbsp_uev(rbsp, &vui->log2_max_mv_length_vertical); + } +} + static void nal_hevc_rbsp_sps(struct rbsp *rbsp, struct nal_hevc_sps *sps) { unsigned int i; @@ -275,7 +405,7 @@ static void nal_hevc_rbsp_sps(struct rbsp *rbsp, struct nal_hevc_sps *sps) rbsp_bit(rbsp, &sps->strong_intra_smoothing_enabled_flag); rbsp_bit(rbsp, &sps->vui_parameters_present_flag); if (sps->vui_parameters_present_flag) - rbsp_unsupported(rbsp); + nal_hevc_rbsp_vui_parameters(rbsp, &sps->vui); rbsp_bit(rbsp, &sps->extension_present_flag); if (sps->extension_present_flag) { -- cgit v1.2.3 From b35d3fea2a39c040ae1787d9544b24e5343b0645 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 8 Sep 2021 14:03:55 +0100 Subject: media: allegro: write vui parameters for HEVC The vui parameters are optional. However, the vui data allows to specify the color space of the encoded video. Write the vui parameters to make sure that decoders are able to pick up the correct color space. Also implement the necessary lookup functions to convert the values from the V4L2 controls to the values specified in the hevc standard. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/allegro-dvt/allegro-core.c | 47 ++++++++++++ drivers/media/platform/allegro-dvt/nal-hevc.h | 89 +++++++++++++++++++++-- 2 files changed, 130 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 752c5562069b..c8156da33043 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -1762,7 +1762,10 @@ static ssize_t allegro_hevc_write_sps(struct allegro_channel *channel, struct allegro_dev *dev = channel->dev; struct nal_hevc_sps *sps; struct nal_hevc_profile_tier_level *ptl; + struct nal_hevc_vui_parameters *vui; + struct nal_hevc_hrd_parameters *hrd; ssize_t size; + unsigned int cpb_size; unsigned int num_ref_frames = channel->num_ref_idx_l0; s32 profile = v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_profile); s32 level = v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_level); @@ -1815,6 +1818,50 @@ static ssize_t allegro_hevc_write_sps(struct allegro_channel *channel, sps->sps_temporal_mvp_enabled_flag = channel->temporal_mvp_enable; sps->strong_intra_smoothing_enabled_flag = channel->max_cu_size > 4; + sps->vui_parameters_present_flag = 1; + vui = &sps->vui; + + vui->video_signal_type_present_flag = 1; + vui->video_format = 5; /* unspecified */ + vui->video_full_range_flag = nal_hevc_full_range(channel->quantization); + vui->colour_description_present_flag = 1; + vui->colour_primaries = nal_hevc_color_primaries(channel->colorspace); + vui->transfer_characteristics = nal_hevc_transfer_characteristics(channel->colorspace, + channel->xfer_func); + vui->matrix_coeffs = nal_hevc_matrix_coeffs(channel->colorspace, channel->ycbcr_enc); + + vui->chroma_loc_info_present_flag = 1; + vui->chroma_sample_loc_type_top_field = 0; + vui->chroma_sample_loc_type_bottom_field = 0; + + vui->vui_timing_info_present_flag = 1; + vui->vui_num_units_in_tick = channel->framerate.denominator; + vui->vui_time_scale = channel->framerate.numerator; + + vui->bitstream_restriction_flag = 1; + vui->motion_vectors_over_pic_boundaries_flag = 1; + vui->restricted_ref_pic_lists_flag = 1; + vui->log2_max_mv_length_horizontal = 15; + vui->log2_max_mv_length_vertical = 15; + + vui->vui_hrd_parameters_present_flag = 1; + hrd = &vui->nal_hrd_parameters; + hrd->vcl_hrd_parameters_present_flag = 1; + + hrd->initial_cpb_removal_delay_length_minus1 = 31; + hrd->au_cpb_removal_delay_length_minus1 = 30; + hrd->dpb_output_delay_length_minus1 = 30; + + hrd->bit_rate_scale = ffs(channel->bitrate_peak) - 6; + hrd->vcl_hrd[0].bit_rate_value_minus1[0] = + (channel->bitrate_peak >> (6 + hrd->bit_rate_scale)) - 1; + + cpb_size = v4l2_ctrl_g_ctrl(channel->mpeg_video_cpb_size) * 1000; + hrd->cpb_size_scale = ffs(cpb_size) - 4; + hrd->vcl_hrd[0].cpb_size_value_minus1[0] = (cpb_size >> (4 + hrd->cpb_size_scale)) - 1; + + hrd->vcl_hrd[0].cbr_flag[0] = !v4l2_ctrl_g_ctrl(channel->mpeg_video_frame_rc_enable); + size = nal_hevc_write_sps(&dev->plat_dev->dev, dest, n, sps); kfree(sps); diff --git a/drivers/media/platform/allegro-dvt/nal-hevc.h b/drivers/media/platform/allegro-dvt/nal-hevc.h index fb899d162bd9..eb46f12aae80 100644 --- a/drivers/media/platform/allegro-dvt/nal-hevc.h +++ b/drivers/media/platform/allegro-dvt/nal-hevc.h @@ -414,12 +414,89 @@ static inline int nal_hevc_level(enum v4l2_mpeg_video_hevc_level level) } } -int nal_range_from_v4l2(enum v4l2_quantization quantization); -int nal_color_primaries_from_v4l2(enum v4l2_colorspace colorspace); -int nal_transfer_characteristics_from_v4l2(enum v4l2_colorspace colorspace, - enum v4l2_xfer_func xfer_func); -int nal_matrix_coeffs_from_v4l2(enum v4l2_colorspace colorspace, - enum v4l2_ycbcr_encoding ycbcr_encoding); +static inline int nal_hevc_full_range(enum v4l2_quantization quantization) +{ + switch (quantization) { + case V4L2_QUANTIZATION_FULL_RANGE: + return 1; + case V4L2_QUANTIZATION_LIM_RANGE: + return 0; + default: + break; + } + + return 0; +} + +static inline int nal_hevc_color_primaries(enum v4l2_colorspace colorspace) +{ + switch (colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + return 6; + case V4L2_COLORSPACE_SMPTE240M: + return 7; + case V4L2_COLORSPACE_REC709: + return 1; + case V4L2_COLORSPACE_470_SYSTEM_M: + return 4; + case V4L2_COLORSPACE_JPEG: + case V4L2_COLORSPACE_SRGB: + case V4L2_COLORSPACE_470_SYSTEM_BG: + return 5; + case V4L2_COLORSPACE_BT2020: + return 9; + case V4L2_COLORSPACE_DEFAULT: + case V4L2_COLORSPACE_OPRGB: + case V4L2_COLORSPACE_RAW: + case V4L2_COLORSPACE_DCI_P3: + default: + return 2; + } +} + +static inline int nal_hevc_transfer_characteristics(enum v4l2_colorspace colorspace, + enum v4l2_xfer_func xfer_func) +{ + if (xfer_func == V4L2_XFER_FUNC_DEFAULT) + xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(colorspace); + + switch (xfer_func) { + case V4L2_XFER_FUNC_709: + return 6; + case V4L2_XFER_FUNC_SMPTE2084: + return 16; + case V4L2_XFER_FUNC_SRGB: + case V4L2_XFER_FUNC_OPRGB: + case V4L2_XFER_FUNC_NONE: + case V4L2_XFER_FUNC_DCI_P3: + case V4L2_XFER_FUNC_SMPTE240M: + default: + return 2; + } +} + +static inline int nal_hevc_matrix_coeffs(enum v4l2_colorspace colorspace, + enum v4l2_ycbcr_encoding ycbcr_encoding) +{ + if (ycbcr_encoding == V4L2_YCBCR_ENC_DEFAULT) + ycbcr_encoding = V4L2_MAP_YCBCR_ENC_DEFAULT(colorspace); + + switch (ycbcr_encoding) { + case V4L2_YCBCR_ENC_601: + case V4L2_YCBCR_ENC_XV601: + return 5; + case V4L2_YCBCR_ENC_709: + case V4L2_YCBCR_ENC_XV709: + return 1; + case V4L2_YCBCR_ENC_BT2020: + return 9; + case V4L2_YCBCR_ENC_BT2020_CONST_LUM: + return 10; + case V4L2_YCBCR_ENC_SMPTE240M: + default: + return 2; + } +} ssize_t nal_hevc_write_vps(const struct device *dev, void *dest, size_t n, struct nal_hevc_vps *vps); -- cgit v1.2.3 From 3f3e877ce8efabe44ddc8e13885f99cdc770e198 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Wed, 31 Mar 2021 12:05:42 +0100 Subject: media: venus: venc: Use pmruntime autosuspend Migrate encoder to pm-runtime autosuspend. Signed-off-by: Stanimir Varbanov Tested-by: Vikash Garodia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc.c | 103 ++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index bc1c42dd53c0..472f2cff4573 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -538,6 +538,64 @@ static const struct v4l2_ioctl_ops venc_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; +static int venc_pm_get(struct venus_inst *inst) +{ + struct venus_core *core = inst->core; + struct device *dev = core->dev_enc; + int ret; + + mutex_lock(&core->pm_lock); + ret = pm_runtime_resume_and_get(dev); + mutex_unlock(&core->pm_lock); + + return ret < 0 ? ret : 0; +} + +static int venc_pm_put(struct venus_inst *inst, bool autosuspend) +{ + struct venus_core *core = inst->core; + struct device *dev = core->dev_enc; + int ret; + + mutex_lock(&core->pm_lock); + + if (autosuspend) + ret = pm_runtime_put_autosuspend(dev); + else + ret = pm_runtime_put_sync(dev); + + mutex_unlock(&core->pm_lock); + + return ret < 0 ? ret : 0; +} + +static int venc_pm_get_put(struct venus_inst *inst) +{ + struct venus_core *core = inst->core; + struct device *dev = core->dev_enc; + int ret = 0; + + mutex_lock(&core->pm_lock); + + if (pm_runtime_suspended(dev)) { + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + goto error; + + ret = pm_runtime_put_autosuspend(dev); + } + +error: + mutex_unlock(&core->pm_lock); + + return ret < 0 ? ret : 0; +} + +static void venc_pm_touch(struct venus_inst *inst) +{ + pm_runtime_mark_last_busy(inst->core->dev_enc); +} + static int venc_set_properties(struct venus_inst *inst) { struct venc_controls *ctr = &inst->controls.enc; @@ -931,10 +989,18 @@ static int venc_queue_setup(struct vb2_queue *q, return 0; } + ret = venc_pm_get(inst); + if (ret) + return ret; + mutex_lock(&inst->lock); ret = venc_init_session(inst); mutex_unlock(&inst->lock); + if (ret) + goto put_power; + + ret = venc_pm_put(inst, false); if (ret) return ret; @@ -970,6 +1036,9 @@ static int venc_queue_setup(struct vb2_queue *q, break; } + return ret; +put_power: + venc_pm_put(inst, false); return ret; } @@ -986,6 +1055,8 @@ static void venc_release_session(struct venus_inst *inst) { int ret; + venc_pm_get(inst); + mutex_lock(&inst->lock); ret = hfi_session_deinit(inst); @@ -997,6 +1068,8 @@ static void venc_release_session(struct venus_inst *inst) venus_pm_load_scale(inst); INIT_LIST_HEAD(&inst->registeredbufs); venus_pm_release_core(inst); + + venc_pm_put(inst, false); } static void venc_buf_cleanup(struct vb2_buffer *vb) @@ -1066,7 +1139,15 @@ static int venc_start_streaming(struct vb2_queue *q, unsigned int count) inst->sequence_cap = 0; inst->sequence_out = 0; + ret = venc_pm_get(inst); + if (ret) + goto error; + ret = venus_pm_acquire_core(inst); + if (ret) + goto put_power; + + ret = venc_pm_put(inst, true); if (ret) goto error; @@ -1091,6 +1172,8 @@ static int venc_start_streaming(struct vb2_queue *q, unsigned int count) return 0; +put_power: + venc_pm_put(inst, false); error: venus_helper_buffers_done(inst, q->type, VB2_BUF_STATE_QUEUED); if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) @@ -1105,6 +1188,8 @@ static void venc_vb2_buf_queue(struct vb2_buffer *vb) { struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); + venc_pm_get_put(inst); + mutex_lock(&inst->lock); venus_helper_vb2_buf_queue(vb); mutex_unlock(&inst->lock); @@ -1128,6 +1213,8 @@ static void venc_buf_done(struct venus_inst *inst, unsigned int buf_type, struct vb2_buffer *vb; unsigned int type; + venc_pm_touch(inst); + if (buf_type == HFI_BUFFER_INPUT) type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; else @@ -1157,6 +1244,8 @@ static void venc_event_notify(struct venus_inst *inst, u32 event, { struct device *dev = inst->core->dev_enc; + venc_pm_touch(inst); + if (event == EVT_SESSION_ERROR) { inst->session_error = true; dev_err(dev, "enc: event session error %x\n", inst->error); @@ -1245,13 +1334,9 @@ static int venc_open(struct file *file) venus_helper_init_instance(inst); - ret = pm_runtime_resume_and_get(core->dev_enc); - if (ret < 0) - goto err_free; - ret = venc_ctrl_init(inst); if (ret) - goto err_put_sync; + goto err_free; ret = hfi_session_create(inst, &venc_hfi_ops); if (ret) @@ -1290,8 +1375,6 @@ err_session_destroy: hfi_session_destroy(inst); err_ctrl_deinit: venc_ctrl_deinit(inst); -err_put_sync: - pm_runtime_put_sync(core->dev_enc); err_free: kfree(inst); return ret; @@ -1301,6 +1384,8 @@ static int venc_close(struct file *file) { struct venus_inst *inst = to_inst(file); + venc_pm_get(inst); + v4l2_m2m_ctx_release(inst->m2m_ctx); v4l2_m2m_release(inst->m2m_dev); venc_ctrl_deinit(inst); @@ -1309,7 +1394,7 @@ static int venc_close(struct file *file) v4l2_fh_del(&inst->fh); v4l2_fh_exit(&inst->fh); - pm_runtime_put_sync(inst->core->dev_enc); + venc_pm_put(inst, false); kfree(inst); return 0; @@ -1366,6 +1451,8 @@ static int venc_probe(struct platform_device *pdev) core->dev_enc = dev; video_set_drvdata(vdev, core); + pm_runtime_set_autosuspend_delay(dev, 2000); + pm_runtime_use_autosuspend(dev); pm_runtime_enable(dev); return 0; -- cgit v1.2.3 From b46ff4eb34ce250df30dc239bab5fedc64c317ed Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Fri, 23 Apr 2021 08:24:54 +0100 Subject: media: venus: Make sys_error flag an atomic bitops Make the sys_error flag an atomic bitops in order to avoid locking in sys_error readers. Signed-off-by: Stanimir Varbanov Tested-by: Vikash Garodia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.c | 4 ++-- drivers/media/platform/qcom/venus/core.h | 3 ++- drivers/media/platform/qcom/venus/helpers.c | 2 +- drivers/media/platform/qcom/venus/hfi.c | 2 +- drivers/media/platform/qcom/venus/vdec.c | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index de7b32caa8b8..0f31cc5668c1 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -65,7 +65,7 @@ static void venus_event_notify(struct venus_core *core, u32 event) } mutex_lock(&core->lock); - core->sys_error = true; + set_bit(0, &core->sys_error); list_for_each_entry(inst, &core->instances, list) inst->ops->event_notify(inst, EVT_SESSION_ERROR, NULL); mutex_unlock(&core->lock); @@ -161,7 +161,7 @@ static void venus_sys_error_handler(struct work_struct *work) dev_warn(core->dev, "system error has occurred (recovered)\n"); mutex_lock(&core->lock); - core->sys_error = false; + clear_bit(0, &core->sys_error); mutex_unlock(&core->lock); } diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index a3f077f64be0..46d87a1226ff 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -7,6 +7,7 @@ #ifndef __VENUS_CORE_H_ #define __VENUS_CORE_H_ +#include #include #include #include @@ -182,7 +183,7 @@ struct venus_core { unsigned int state; struct completion done; unsigned int error; - bool sys_error; + unsigned long sys_error; const struct hfi_core_ops *core_ops; const struct venus_pm_ops *pm_ops; struct mutex pm_lock; diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 7f2f5b91caaa..8cebb8e29aed 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -1486,7 +1486,7 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q) ret |= venus_helper_intbufs_free(inst); ret |= hfi_session_deinit(inst); - if (inst->session_error || core->sys_error) + if (inst->session_error || test_bit(0, &core->sys_error)) ret = -EIO; if (ret) diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index 0f2482367e06..179b1f8b2650 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -214,7 +214,7 @@ int hfi_session_init(struct venus_inst *inst, u32 pixfmt) * session_init() can't pass successfully */ mutex_lock(&core->lock); - if (!core->ops || core->sys_error) { + if (!core->ops || test_bit(0, &inst->core->sys_error)) { mutex_unlock(&core->lock); return -EIO; } diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 41c5a353fcae..11990a95d346 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -1231,7 +1231,7 @@ static void vdec_session_release(struct venus_inst *inst) ret = hfi_session_deinit(inst); abort = (ret && ret != -EINVAL) ? 1 : 0; - if (inst->session_error || core->sys_error) + if (inst->session_error || test_bit(0, &core->sys_error)) abort = 1; if (abort) -- cgit v1.2.3 From 3efc5204dd99b13a3ca5f94f9eb6d9d36f261368 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Fri, 23 Apr 2021 08:29:31 +0100 Subject: media: venus: hfi: Check for sys error on session hfi functions Check sys error flag for all hfi_session_xxx functions and exit with EIO in case of an error. Signed-off-by: Stanimir Varbanov Tested-by: Vikash Garodia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/hfi.c | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index 179b1f8b2650..4e2151fb47f0 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -187,6 +187,11 @@ int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops) mutex_lock(&core->lock); + if (test_bit(0, &inst->core->sys_error)) { + ret = -EIO; + goto unlock; + } + max = atomic_add_unless(&core->insts_count, 1, core->max_sessions_supported); if (!max) { @@ -196,6 +201,7 @@ int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops) ret = 0; } +unlock: mutex_unlock(&core->lock); return ret; @@ -263,6 +269,9 @@ int hfi_session_deinit(struct venus_inst *inst) if (inst->state < INST_INIT) return -EINVAL; + if (test_bit(0, &inst->core->sys_error)) + goto done; + reinit_completion(&inst->done); ret = ops->session_end(inst); @@ -273,6 +282,7 @@ int hfi_session_deinit(struct venus_inst *inst) if (ret) return ret; +done: inst->state = INST_UNINIT; return 0; @@ -284,6 +294,9 @@ int hfi_session_start(struct venus_inst *inst) const struct hfi_ops *ops = inst->core->ops; int ret; + if (test_bit(0, &inst->core->sys_error)) + return -EIO; + if (inst->state != INST_LOAD_RESOURCES) return -EINVAL; @@ -308,6 +321,9 @@ int hfi_session_stop(struct venus_inst *inst) const struct hfi_ops *ops = inst->core->ops; int ret; + if (test_bit(0, &inst->core->sys_error)) + return -EIO; + if (inst->state != INST_START) return -EINVAL; @@ -331,6 +347,9 @@ int hfi_session_continue(struct venus_inst *inst) { struct venus_core *core = inst->core; + if (test_bit(0, &inst->core->sys_error)) + return -EIO; + if (core->res->hfi_version == HFI_VERSION_1XX) return 0; @@ -343,6 +362,9 @@ int hfi_session_abort(struct venus_inst *inst) const struct hfi_ops *ops = inst->core->ops; int ret; + if (test_bit(0, &inst->core->sys_error)) + return -EIO; + reinit_completion(&inst->done); ret = ops->session_abort(inst); @@ -362,6 +384,9 @@ int hfi_session_load_res(struct venus_inst *inst) const struct hfi_ops *ops = inst->core->ops; int ret; + if (test_bit(0, &inst->core->sys_error)) + return -EIO; + if (inst->state != INST_INIT) return -EINVAL; @@ -385,6 +410,9 @@ int hfi_session_unload_res(struct venus_inst *inst) const struct hfi_ops *ops = inst->core->ops; int ret; + if (test_bit(0, &inst->core->sys_error)) + return -EIO; + if (inst->state != INST_STOP) return -EINVAL; @@ -409,6 +437,9 @@ int hfi_session_flush(struct venus_inst *inst, u32 type, bool block) const struct hfi_ops *ops = inst->core->ops; int ret; + if (test_bit(0, &inst->core->sys_error)) + return -EIO; + reinit_completion(&inst->done); ret = ops->session_flush(inst, type); @@ -429,6 +460,9 @@ int hfi_session_set_buffers(struct venus_inst *inst, struct hfi_buffer_desc *bd) { const struct hfi_ops *ops = inst->core->ops; + if (test_bit(0, &inst->core->sys_error)) + return -EIO; + return ops->session_set_buffers(inst, bd); } @@ -438,6 +472,9 @@ int hfi_session_unset_buffers(struct venus_inst *inst, const struct hfi_ops *ops = inst->core->ops; int ret; + if (test_bit(0, &inst->core->sys_error)) + return -EIO; + reinit_completion(&inst->done); ret = ops->session_unset_buffers(inst, bd); @@ -460,6 +497,9 @@ int hfi_session_get_property(struct venus_inst *inst, u32 ptype, const struct hfi_ops *ops = inst->core->ops; int ret; + if (test_bit(0, &inst->core->sys_error)) + return -EIO; + if (inst->state < INST_INIT || inst->state >= INST_STOP) return -EINVAL; @@ -483,6 +523,9 @@ int hfi_session_set_property(struct venus_inst *inst, u32 ptype, void *pdata) { const struct hfi_ops *ops = inst->core->ops; + if (test_bit(0, &inst->core->sys_error)) + return -EIO; + if (inst->state < INST_INIT || inst->state >= INST_STOP) return -EINVAL; @@ -494,6 +537,9 @@ int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd) { const struct hfi_ops *ops = inst->core->ops; + if (test_bit(0, &inst->core->sys_error)) + return -EIO; + if (fd->buffer_type == HFI_BUFFER_INPUT) return ops->session_etb(inst, fd); else if (fd->buffer_type == HFI_BUFFER_OUTPUT || -- cgit v1.2.3 From aa6dcf171ab71910960f53ffcae3c8fa48928a85 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Fri, 23 Apr 2021 10:08:05 +0100 Subject: media: venus: helpers: Add helper to mark fatal vb2 error Add a helper to mark source and destination vb2 queues fatal unrecoverable error. Signed-off-by: Stanimir Varbanov Tested-by: Vikash Garodia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/helpers.c | 12 ++++++++++++ drivers/media/platform/qcom/venus/helpers.h | 1 + 2 files changed, 13 insertions(+) diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 8cebb8e29aed..dacd244d5aca 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -1514,6 +1514,18 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q) } EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming); +void venus_helper_vb2_queue_error(struct venus_inst *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; + struct vb2_queue *q; + + q = v4l2_m2m_get_src_vq(m2m_ctx); + vb2_queue_error(q); + q = v4l2_m2m_get_dst_vq(m2m_ctx); + vb2_queue_error(q); +} +EXPORT_SYMBOL_GPL(venus_helper_vb2_queue_error); + int venus_helper_process_initial_cap_bufs(struct venus_inst *inst) { struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h index e6269b4be3af..6a250c3d3cfe 100644 --- a/drivers/media/platform/qcom/venus/helpers.h +++ b/drivers/media/platform/qcom/venus/helpers.h @@ -21,6 +21,7 @@ int venus_helper_vb2_buf_prepare(struct vb2_buffer *vb); void venus_helper_vb2_buf_queue(struct vb2_buffer *vb); void venus_helper_vb2_stop_streaming(struct vb2_queue *q); int venus_helper_vb2_start_streaming(struct venus_inst *inst); +void venus_helper_vb2_queue_error(struct venus_inst *inst); void venus_helper_m2m_device_run(void *priv); void venus_helper_m2m_job_abort(void *priv); int venus_helper_get_bufreq(struct venus_inst *inst, u32 type, -- cgit v1.2.3 From 3227a8f7cf331ed5be4b6c26339366b8d2d83b09 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Fri, 23 Apr 2021 10:41:25 +0100 Subject: media: venus: Handle fatal errors during encoding and decoding According to stateful decoder docs a fatal failure of decoding (and encoding) could be recover it by closing the corresponding file handle and open new one or reinitialize decoding (and encoding) by stop streaming on both queues. In order to satisfy this requirement we add a mechanism ins sys_error_handler and corresponding decoder and encoder drivers to wait for sys_error_done waitqueue in reqbuf. Signed-off-by: Stanimir Varbanov Tested-by: Vikash Garodia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.c | 9 ++++++--- drivers/media/platform/qcom/venus/core.h | 3 +++ drivers/media/platform/qcom/venus/helpers.c | 2 ++ drivers/media/platform/qcom/venus/vdec.c | 16 ++++++++++++++++ drivers/media/platform/qcom/venus/venc.c | 13 +++++++++++++ 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 0f31cc5668c1..3916af160ea9 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -95,9 +95,8 @@ static void venus_sys_error_handler(struct work_struct *work) failed = true; } - hfi_core_deinit(core, true); - - mutex_lock(&core->lock); + core->ops->core_deinit(core); + core->state = CORE_UNINIT; for (i = 0; i < max_attempts; i++) { if (!pm_runtime_active(core->dev_dec) && !pm_runtime_active(core->dev_enc)) @@ -105,6 +104,8 @@ static void venus_sys_error_handler(struct work_struct *work) msleep(10); } + mutex_lock(&core->lock); + venus_shutdown(core); venus_coredump(core); @@ -162,6 +163,7 @@ static void venus_sys_error_handler(struct work_struct *work) mutex_lock(&core->lock); clear_bit(0, &core->sys_error); + wake_up_all(&core->sys_err_done); mutex_unlock(&core->lock); } @@ -316,6 +318,7 @@ static int venus_probe(struct platform_device *pdev) INIT_LIST_HEAD(&core->instances); mutex_init(&core->lock); INIT_DELAYED_WORK(&core->work, venus_sys_error_handler); + init_waitqueue_head(&core->sys_err_done); ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, hfi_isr_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 46d87a1226ff..262e021fd19e 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -184,6 +184,7 @@ struct venus_core { struct completion done; unsigned int error; unsigned long sys_error; + wait_queue_head_t sys_err_done; const struct hfi_core_ops *core_ops; const struct venus_pm_ops *pm_ops; struct mutex pm_lock; @@ -336,6 +337,7 @@ enum venus_inst_modes { * @registeredbufs: a list of registered capture bufferes * @delayed_process: a list of delayed buffers * @delayed_process_work: a work_struct for process delayed buffers + * @nonblock: nonblocking flag * @ctrl_handler: v4l control handler * @controls: a union of decoder and encoder control parameters * @fh: a holder of v4l file handle structure @@ -399,6 +401,7 @@ struct venus_inst { struct list_head registeredbufs; struct list_head delayed_process; struct work_struct delayed_process_work; + bool nonblock; struct v4l2_ctrl_handler ctrl_handler; union { diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index dacd244d5aca..caf47ca6a950 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -1510,6 +1510,8 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q) venus_pm_release_core(inst); + inst->session_error = 0; + mutex_unlock(&inst->lock); } EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming); diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 11990a95d346..36e783eeafe9 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -846,6 +846,7 @@ static int vdec_queue_setup(struct vb2_queue *q, unsigned int sizes[], struct device *alloc_devs[]) { struct venus_inst *inst = vb2_get_drv_priv(q); + struct venus_core *core = inst->core; unsigned int in_num, out_num; int ret = 0; @@ -871,6 +872,16 @@ static int vdec_queue_setup(struct vb2_queue *q, return 0; } + if (test_bit(0, &core->sys_error)) { + if (inst->nonblock) + return -EAGAIN; + + ret = wait_event_interruptible(core->sys_err_done, + !test_bit(0, &core->sys_error)); + if (ret) + return ret; + } + ret = vdec_pm_get(inst); if (ret) return ret; @@ -1198,6 +1209,8 @@ static void vdec_stop_streaming(struct vb2_queue *q) venus_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR); + inst->session_error = 0; + if (ret) goto unlock; @@ -1473,6 +1486,7 @@ static void vdec_event_notify(struct venus_inst *inst, u32 event, switch (event) { case EVT_SESSION_ERROR: inst->session_error = true; + venus_helper_vb2_queue_error(inst); dev_err(dev, "dec: event session error %x\n", inst->error); break; case EVT_SYS_EVENT_CHANGE: @@ -1594,6 +1608,8 @@ static int vdec_open(struct file *file) inst->bit_depth = VIDC_BITDEPTH_8; inst->pic_struct = HFI_INTERLACE_FRAME_PROGRESSIVE; init_waitqueue_head(&inst->reconf_wait); + inst->nonblock = file->f_flags & O_NONBLOCK; + venus_helper_init_instance(inst); ret = vdec_ctrl_init(inst); diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 472f2cff4573..84bafc3118cc 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -966,6 +966,7 @@ static int venc_queue_setup(struct vb2_queue *q, unsigned int sizes[], struct device *alloc_devs[]) { struct venus_inst *inst = vb2_get_drv_priv(q); + struct venus_core *core = inst->core; unsigned int num, min = 4; int ret; @@ -989,6 +990,16 @@ static int venc_queue_setup(struct vb2_queue *q, return 0; } + if (test_bit(0, &core->sys_error)) { + if (inst->nonblock) + return -EAGAIN; + + ret = wait_event_interruptible(core->sys_err_done, + !test_bit(0, &core->sys_error)); + if (ret) + return ret; + } + ret = venc_pm_get(inst); if (ret) return ret; @@ -1248,6 +1259,7 @@ static void venc_event_notify(struct venus_inst *inst, u32 event, if (event == EVT_SESSION_ERROR) { inst->session_error = true; + venus_helper_vb2_queue_error(inst); dev_err(dev, "enc: event session error %x\n", inst->error); } } @@ -1331,6 +1343,7 @@ static int venc_open(struct file *file) inst->session_type = VIDC_SESSION_TYPE_ENC; inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT; inst->core_acquired = false; + inst->nonblock = file->f_flags & O_NONBLOCK; venus_helper_init_instance(inst); -- cgit v1.2.3 From 40d87aafee29fb01ce1e1868502fb2059a6a7f34 Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Wed, 20 Oct 2021 07:44:08 +0100 Subject: media: venus: vdec: decoded picture buffer handling during reconfig sequence In existing implementation, driver is freeing and un-mapping all the decoded picture buffers(DPB) as part of dynamic resolution change(DRC) handling. As a result, when firmware try to access the DPB buffer, from previous sequence, SMMU context fault is seen due to the buffer being already unmapped. With this change, driver defines ownership of each DPB buffer. If a buffer is owned by firmware, driver would skip from un-mapping the same. Signed-off-by: Mansur Alisha Shaik Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.h | 1 + drivers/media/platform/qcom/venus/helpers.c | 51 ++++++++++++++++++++++++++++- drivers/media/platform/qcom/venus/helpers.h | 3 ++ drivers/media/platform/qcom/venus/vdec.c | 7 +++- 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 262e021fd19e..7c3bac01cd49 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -458,6 +458,7 @@ struct venus_inst { bool next_buf_last; bool drain_active; enum venus_inst_modes flags; + struct ida dpb_ids; }; #define IS_V1(core) ((core)->res->hfi_version == HFI_VERSION_1XX) diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index caf47ca6a950..84c3a511ec31 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -3,6 +3,7 @@ * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * Copyright (C) 2017 Linaro Ltd. */ +#include #include #include #include @@ -21,6 +22,11 @@ #define NUM_MBS_720P (((ALIGN(1280, 16)) >> 4) * ((ALIGN(736, 16)) >> 4)) #define NUM_MBS_4K (((ALIGN(4096, 16)) >> 4) * ((ALIGN(2304, 16)) >> 4)) +enum dpb_buf_owner { + DRIVER, + FIRMWARE, +}; + struct intbuf { struct list_head list; u32 type; @@ -28,6 +34,8 @@ struct intbuf { void *va; dma_addr_t da; unsigned long attrs; + enum dpb_buf_owner owned_by; + u32 dpb_out_tag; }; bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt) @@ -95,9 +103,16 @@ int venus_helper_queue_dpb_bufs(struct venus_inst *inst) fdata.device_addr = buf->da; fdata.buffer_type = buf->type; + if (buf->owned_by == FIRMWARE) + continue; + + fdata.clnt_data = buf->dpb_out_tag; + ret = hfi_session_process_buf(inst, &fdata); if (ret) goto fail; + + buf->owned_by = FIRMWARE; } fail: @@ -110,13 +125,19 @@ int venus_helper_free_dpb_bufs(struct venus_inst *inst) struct intbuf *buf, *n; list_for_each_entry_safe(buf, n, &inst->dpbbufs, list) { + if (buf->owned_by == FIRMWARE) + continue; + + ida_free(&inst->dpb_ids, buf->dpb_out_tag); + list_del_init(&buf->list); dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da, buf->attrs); kfree(buf); } - INIT_LIST_HEAD(&inst->dpbbufs); + if (list_empty(&inst->dpbbufs)) + INIT_LIST_HEAD(&inst->dpbbufs); return 0; } @@ -134,6 +155,7 @@ int venus_helper_alloc_dpb_bufs(struct venus_inst *inst) unsigned int i; u32 count; int ret; + int id; /* no need to allocate dpb buffers */ if (!inst->dpb_fmt) @@ -171,6 +193,15 @@ int venus_helper_alloc_dpb_bufs(struct venus_inst *inst) ret = -ENOMEM; goto fail; } + buf->owned_by = DRIVER; + + id = ida_alloc_min(&inst->dpb_ids, VB2_MAX_FRAME, GFP_KERNEL); + if (id < 0) { + ret = id; + goto fail; + } + + buf->dpb_out_tag = id; list_add_tail(&buf->list, &inst->dpbbufs); } @@ -1371,6 +1402,24 @@ venus_helper_find_buf(struct venus_inst *inst, unsigned int type, u32 idx) } EXPORT_SYMBOL_GPL(venus_helper_find_buf); +void venus_helper_change_dpb_owner(struct venus_inst *inst, + struct vb2_v4l2_buffer *vbuf, unsigned int type, + unsigned int buf_type, u32 tag) +{ + struct intbuf *dpb_buf; + + if (!V4L2_TYPE_IS_CAPTURE(type) || + buf_type != inst->dpb_buftype) + return; + + list_for_each_entry(dpb_buf, &inst->dpbbufs, list) + if (dpb_buf->dpb_out_tag == tag) { + dpb_buf->owned_by = DRIVER; + break; + } +} +EXPORT_SYMBOL_GPL(venus_helper_change_dpb_owner); + int venus_helper_vb2_buf_init(struct vb2_buffer *vb) { struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h index 6a250c3d3cfe..32619c3e8c97 100644 --- a/drivers/media/platform/qcom/venus/helpers.h +++ b/drivers/media/platform/qcom/venus/helpers.h @@ -14,6 +14,9 @@ struct venus_core; bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt); struct vb2_v4l2_buffer *venus_helper_find_buf(struct venus_inst *inst, unsigned int type, u32 idx); +void venus_helper_change_dpb_owner(struct venus_inst *inst, + struct vb2_v4l2_buffer *vbuf, unsigned int type, + unsigned int buf_type, u32 idx); void venus_helper_buffers_done(struct venus_inst *inst, unsigned int type, enum vb2_buffer_state state); int venus_helper_vb2_buf_init(struct vb2_buffer *vb); diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 36e783eeafe9..91da3f509724 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -1339,8 +1339,10 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type, type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; vbuf = venus_helper_find_buf(inst, type, tag); - if (!vbuf) + if (!vbuf) { + venus_helper_change_dpb_owner(inst, vbuf, type, buf_type, tag); return; + } vbuf->flags = flags; vbuf->field = V4L2_FIELD_NONE; @@ -1622,6 +1624,8 @@ static int vdec_open(struct file *file) vdec_inst_init(inst); + ida_init(&inst->dpb_ids); + /* * create m2m device for every instance, the m2m context scheduling * is made by firmware side so we do not need to care about. @@ -1667,6 +1671,7 @@ static int vdec_close(struct file *file) v4l2_m2m_ctx_release(inst->m2m_ctx); v4l2_m2m_release(inst->m2m_dev); vdec_ctrl_deinit(inst); + ida_destroy(&inst->dpb_ids); hfi_session_destroy(inst); mutex_destroy(&inst->lock); v4l2_fh_del(&inst->fh); -- cgit v1.2.3 From 96fbc6c547583595b977762b762f30e619622929 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Fri, 8 Oct 2021 11:21:17 +0100 Subject: media: dt-bindings: media: venus: Add sdm660 dt schema Add a schema description for the Venus video decoder/encoder IP in SDM660. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/qcom,sdm660-venus.yaml | 186 +++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/qcom,sdm660-venus.yaml diff --git a/Documentation/devicetree/bindings/media/qcom,sdm660-venus.yaml b/Documentation/devicetree/bindings/media/qcom,sdm660-venus.yaml new file mode 100644 index 000000000000..33da7d3cfd38 --- /dev/null +++ b/Documentation/devicetree/bindings/media/qcom,sdm660-venus.yaml @@ -0,0 +1,186 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/media/qcom,sdm660-venus.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Qualcomm Venus video encode and decode accelerators + +maintainers: + - Stanimir Varbanov + - AngeloGioacchino Del Regno + +description: | + The Venus IP is a video encode and decode accelerator present + on Qualcomm platforms + +properties: + compatible: + const: qcom,sdm660-venus + + reg: + maxItems: 1 + + clocks: + maxItems: 4 + + clock-names: + items: + - const: core + - const: iface + - const: bus + - const: bus_throttle + + interconnects: + maxItems: 2 + + interconnect-names: + items: + - const: cpu-cfg + - const: video-mem + + interrupts: + maxItems: 1 + + iommus: + maxItems: 20 + + memory-region: + maxItems: 1 + + power-domains: + maxItems: 1 + + video-decoder: + type: object + + properties: + compatible: + const: venus-decoder + + clocks: + maxItems: 1 + + clock-names: + items: + - const: vcodec0_core + + power-domains: + maxItems: 1 + + required: + - compatible + - clocks + - clock-names + - power-domains + + additionalProperties: false + + video-encoder: + type: object + + properties: + compatible: + const: venus-encoder + + clocks: + maxItems: 1 + + clock-names: + items: + - const: vcodec0_core + + power-domains: + maxItems: 1 + + required: + - compatible + - clocks + - clock-names + - power-domains + + additionalProperties: false + + video-firmware: + type: object + + description: | + Firmware subnode is needed when the platform does not + have TrustZone. + + properties: + iommus: + maxItems: 1 + + required: + - iommus + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - iommus + - memory-region + - power-domains + - video-decoder + - video-encoder + +additionalProperties: false + +examples: + - | + #include + #include + + video-codec@cc00000 { + compatible = "qcom,sdm660-venus"; + reg = <0x0cc00000 0xff000>; + clocks = <&mmcc VIDEO_CORE_CLK>, + <&mmcc VIDEO_AHB_CLK>, + <&mmcc VIDEO_AXI_CLK>, + <&mmcc THROTTLE_VIDEO_AXI_CLK>; + clock-names = "core", "iface", "bus", "bus_throttle"; + interconnects = <&gnoc 0 &mnoc 13>, + <&mnoc 4 &bimc 5>; + interconnect-names = "cpu-cfg", "video-mem"; + interrupts = ; + iommus = <&mmss_smmu 0x400>, + <&mmss_smmu 0x401>, + <&mmss_smmu 0x40a>, + <&mmss_smmu 0x407>, + <&mmss_smmu 0x40e>, + <&mmss_smmu 0x40f>, + <&mmss_smmu 0x408>, + <&mmss_smmu 0x409>, + <&mmss_smmu 0x40b>, + <&mmss_smmu 0x40c>, + <&mmss_smmu 0x40d>, + <&mmss_smmu 0x410>, + <&mmss_smmu 0x421>, + <&mmss_smmu 0x428>, + <&mmss_smmu 0x429>, + <&mmss_smmu 0x42b>, + <&mmss_smmu 0x42c>, + <&mmss_smmu 0x42d>, + <&mmss_smmu 0x411>, + <&mmss_smmu 0x431>; + memory-region = <&venus_region>; + power-domains = <&mmcc VENUS_GDSC>; + + video-decoder { + compatible = "venus-decoder"; + clocks = <&mmcc VIDEO_SUBCORE0_CLK>; + clock-names = "vcodec0_core"; + power-domains = <&mmcc VENUS_CORE0_GDSC>; + }; + + video-encoder { + compatible = "venus-encoder"; + clocks = <&mmcc VIDEO_SUBCORE0_CLK>; + clock-names = "vcodec0_core"; + power-domains = <&mmcc VENUS_CORE0_GDSC>; + }; + }; -- cgit v1.2.3 From 57c3b9f55ba875a6f6295fa59f0bdc0a01c544f8 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Fri, 8 Oct 2021 11:21:18 +0100 Subject: media: venus: core: Add sdm660 DT compatible and resource struct Add the SDM660 DT compatible and its resource structure in order to support the Venus IP in SDM630, SDM636, SDM660 and SDA variants. This SoC features Venus 4.4 (HFI3XX) with only one subcore, used for both encoding and decoding, and switched on with one main and one subcore dedicated GDSC. Signed-off-by: AngeloGioacchino Del Regno Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.c | 64 ++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 3916af160ea9..f5fa81896012 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -568,6 +568,69 @@ static const struct venus_resources msm8996_res = { .fwname = "qcom/venus-4.2/venus.mdt", }; +static const struct freq_tbl sdm660_freq_table[] = { + { 979200, 518400000 }, + { 489600, 441600000 }, + { 432000, 404000000 }, + { 244800, 320000000 }, + { 216000, 269330000 }, + { 108000, 133330000 }, +}; + +static const struct reg_val sdm660_reg_preset[] = { + { 0x80010, 0x001f001f }, + { 0x80018, 0x00000156 }, + { 0x8001c, 0x00000156 }, +}; + +static const struct bw_tbl sdm660_bw_table_enc[] = { + { 979200, 1044000, 0, 2446336, 0 }, /* 4k UHD @ 30 */ + { 864000, 887000, 0, 2108416, 0 }, /* 720p @ 240 */ + { 489600, 666000, 0, 1207296, 0 }, /* 1080p @ 60 */ + { 432000, 578000, 0, 1058816, 0 }, /* 720p @ 120 */ + { 244800, 346000, 0, 616448, 0 }, /* 1080p @ 30 */ + { 216000, 293000, 0, 534528, 0 }, /* 720p @ 60 */ + { 108000, 151000, 0, 271360, 0 }, /* 720p @ 30 */ +}; + +static const struct bw_tbl sdm660_bw_table_dec[] = { + { 979200, 2365000, 0, 1892000, 0 }, /* 4k UHD @ 30 */ + { 864000, 1978000, 0, 1554000, 0 }, /* 720p @ 240 */ + { 489600, 1133000, 0, 895000, 0 }, /* 1080p @ 60 */ + { 432000, 994000, 0, 781000, 0 }, /* 720p @ 120 */ + { 244800, 580000, 0, 460000, 0 }, /* 1080p @ 30 */ + { 216000, 501000, 0, 301000, 0 }, /* 720p @ 60 */ + { 108000, 255000, 0, 202000, 0 }, /* 720p @ 30 */ +}; + +static const struct venus_resources sdm660_res = { + .freq_tbl = sdm660_freq_table, + .freq_tbl_size = ARRAY_SIZE(sdm660_freq_table), + .reg_tbl = sdm660_reg_preset, + .reg_tbl_size = ARRAY_SIZE(sdm660_reg_preset), + .bw_tbl_enc = sdm660_bw_table_enc, + .bw_tbl_enc_size = ARRAY_SIZE(sdm660_bw_table_enc), + .bw_tbl_dec = sdm660_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sdm660_bw_table_dec), + .clks = {"core", "iface", "bus", "bus_throttle" }, + .clks_num = 4, + .vcodec0_clks = { "vcodec0_core" }, + .vcodec1_clks = { "vcodec0_core" }, + .vcodec_clks_num = 1, + .vcodec_num = 1, + .max_load = 1036800, + .hfi_version = HFI_VERSION_3XX, + .vmem_id = VIDC_RESOURCE_NONE, + .vmem_size = 0, + .vmem_addr = 0, + .cp_start = 0, + .cp_size = 0x79000000, + .cp_nonpixel_start = 0x1000000, + .cp_nonpixel_size = 0x28000000, + .dma_mask = 0xd9000000 - 1, + .fwname = "qcom/venus-4.4/venus.mdt", +}; + static const struct freq_tbl sdm845_freq_table[] = { { 3110400, 533000000 }, /* 4096x2160@90 */ { 2073600, 444000000 }, /* 4096x2160@60 */ @@ -793,6 +856,7 @@ static const struct venus_resources sc7280_res = { static const struct of_device_id venus_dt_match[] = { { .compatible = "qcom,msm8916-venus", .data = &msm8916_res, }, { .compatible = "qcom,msm8996-venus", .data = &msm8996_res, }, + { .compatible = "qcom,sdm660-venus", .data = &sdm660_res, }, { .compatible = "qcom,sdm845-venus", .data = &sdm845_res, }, { .compatible = "qcom,sdm845-venus-v2", .data = &sdm845_res_v2, }, { .compatible = "qcom,sc7180-venus", .data = &sc7180_res, }, -- cgit v1.2.3