Received: by 2002:a05:6a10:6744:0:0:0:0 with SMTP id w4csp3313947pxu; Mon, 19 Oct 2020 09:06:01 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyWc8/br63V7nZAb6lQtUyUmjTERQ6zBGim9QyDvCbmzuDiJbWiZSLqTV3WaIXrf+0F1Ctb X-Received: by 2002:a19:8d3:: with SMTP id 202mr123172lfi.600.1603123561623; Mon, 19 Oct 2020 09:06:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1603123561; cv=none; d=google.com; s=arc-20160816; b=mmwhn+e9aVnWxgdY+XGpFxSYEevAs8UOhlwKhNRW1yp05wdCRhwIEStwnv18m1mpK3 jgjF0qey+v7Dw5rmtvUT+C1d1/Oza9vlapAvMkWj9zl6HxlL4Az92tgWB3P3Xsr9OHeQ UebocWB0LNlhpQeHrUxC1upyW+4I4eWNfp9I2/Hz2T3p4xDuRvdT1wHjLziQBr9VvQCW tDYZ8+k4wCagcdPwH6282jRDAXQ15/DFmbxLjLw/FnXjBUeUuexAHNeQo0NWAJUYpzud wmktNVoUfaUjpEpp54PNY5Lm9rnF3J0Q9i37/eMG5Wjlgow5nxRgfSWxw/hsln9BypiI BJYw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:content-language :in-reply-to:mime-version:user-agent:date:message-id:references:cc :to:from:subject; bh=lxehheR0dqNZyxCLHn31LLP3LNwOw4PmS3cvBPMCF58=; b=I31yYDIKXu3bar15t78LwKfxOXH4uiM82aTWcSn7sUAIy6bwQj9BD7es/wKn/dXtsj 1F969mBJnSBNYKqmiR9C4/bCasOLpQk9ZEjeEV49RvpxZeRZDH4vIG3LwCpxGaVyAiKp 7gOxJjPQjE79rYxHCq6wxU1QO5PIFq7HSy33XsIkTLK25cQ1cvH3b0PrRA70jDcHHpz9 4jJoBHz8atSbmCvoUZIihAW79B13YrzfcvjPmuKbCaPsgDC44npbnglDsX61GZBsNW0V NTgfmoDoG+SLBEpcjwlhL+hki6gKxTGWQkyEejVGFkmLdp8tkyq/KvzCy7J/dy7gdhJx 3xSA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id du16si219312ejc.643.2020.10.19.09.05.37; Mon, 19 Oct 2020 09:06:01 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730540AbgJSQCe (ORCPT + 99 others); Mon, 19 Oct 2020 12:02:34 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:57284 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730335AbgJSQCe (ORCPT ); Mon, 19 Oct 2020 12:02:34 -0400 Received: from [IPv6:2804:14c:483:7f66::1000] (unknown [IPv6:2804:14c:483:7f66::1000]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: koike) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 4778A1F44F48; Mon, 19 Oct 2020 17:02:28 +0100 (BST) Subject: Re: [PATCH] media: staging: rkisp1: cap: refactor enable/disable stream to allow multistreaming From: Helen Koike To: Dafna Hirschfeld , linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, hverkuil@xs4all.nl, kernel@collabora.com, sakari.ailus@linux.intel.com, linux-rockchip@lists.infradead.org, mchehab@kernel.org, tfiga@chromium.org, linux-kernel@vger.kernel.org References: <20201015195746.264722-1-helen.koike@collabora.com> <8b31c5a3-9b01-9536-384a-b06d9a0a2e1a@collabora.com> Message-ID: <32295a2e-c3b0-fffc-5e23-8dbdbb83f757@collabora.com> Date: Mon, 19 Oct 2020 13:02:23 -0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.3.2 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hello, On 10/16/20 3:11 PM, Helen Koike wrote: > > > On 10/16/20 11:28 AM, Dafna Hirschfeld wrote: >> Hi, >> >> Am 15.10.20 um 21:57 schrieb Helen Koike: >>> Allow streaming from self picture path and main picture path at the same >>> time. >>> >>> Take care for s_stream() callbacks to not be called twice. >>> When starting a stream, s_stream(true) shouldn't be called for the isp >>> and the sensor if the other stream is already enabled (since it was >>> already called). >>> When stopping a stream, s_stream(false) shouldn't be called for isp and >>> the sensor if the other stream is still enabled. >>> >>> Remove the callback function scheme for navigating through the topology, >>> simplifying the code, improving readability, while calling >>> media_pipeline_{start,stop}() in the right order. >>> >>> Remove multistreaming item from the TODO list. >>> >>> Signed-off-by: Helen Koike >>> >>> --- >>> Hello, >>> >>> Since we didn't reach an agreement on the helpers in the core[1], I'm >>> sending this patch to fix this limitation only for rkisp1. >>> >>> [1] https://patchwork.linuxtv.org/project/linux-media/cover/20200415013044.1778572-1-helen.koike@collabora.com/ >>> >>> If we decide to add the helpers in the future, we can clean up drivers >>> even more, but I don't want to block this feature. >>> >>> Overview of the patch: >>> ====================== >>> >>> * Rename rkisp1_stream_{start,stop}() to >>>    rkisp1_cap_stream_{enable,disable}() to clarify the difference between >>>    other stream enable/disable functions >>> >>> * Implement rkisp1_pipeline_stream_{enable,disable}() to replace >>>    rkisp1_pipeline_{enable,disable}_cb() and rkisp1_pipeline_sink_walk(), >>>    which were removed. >>> >>> * Call rkisp1_cap_stream_{enable,disable}() from >>>    rkisp1_pipeline_stream_{enable,disable}() for better >>>    unwind handling and function name semantics. >>> >>> * Call media_pipeline_{start,stop}() in the right order. >>> >>> * Remove item from TODO list (I also reviewed the use of the >>>    is_streaming var in the code and lgtm). >>> >>> This patch was tested on rockpi4 board with: >>> ============================================ >>> >>> "media-ctl" "-d" "platform:rkisp1" "-r" >>> "media-ctl" "-d" "platform:rkisp1" "-l" "'imx219 4-0010':0 -> 'rkisp1_isp':0 [1]" >>> "media-ctl" "-d" "platform:rkisp1" "-l" "'rkisp1_isp':2 -> 'rkisp1_resizer_selfpath':0 [1]" >>> "media-ctl" "-d" "platform:rkisp1" "-l" "'rkisp1_isp':2 -> 'rkisp1_resizer_mainpath':0 [1]" >>> >>> "media-ctl" "-d" "platform:rkisp1" "--set-v4l2" '"imx219 4-0010":0 [fmt:SRGGB10_1X10/1640x1232]' >>> >>> "media-ctl" "-d" "platform:rkisp1" "--set-v4l2" '"rkisp1_isp":0 [fmt:SRGGB10_1X10/1640x1232 crop: (0,0)/1600x1200]' >>> "media-ctl" "-d" "platform:rkisp1" "--set-v4l2" '"rkisp1_isp":2 [fmt:YUYV8_2X8/1600x1200 crop: (0,0)/1500x1100]' >>> >>> "media-ctl" "-d" "platform:rkisp1" "--set-v4l2" '"rkisp1_resizer_selfpath":0 [fmt:YUYV8_2X8/1500x1100 crop: (300,400)/1400x1000]' >>> "media-ctl" "-d" "platform:rkisp1" "--set-v4l2" '"rkisp1_resizer_selfpath":1 [fmt:YUYV8_2X8/900x800]' >>> >>> "v4l2-ctl" "-z" "platform:rkisp1" "-d" "rkisp1_selfpath" "-v" "width=900,height=800," >>> "v4l2-ctl" "-z" "platform:rkisp1" "-d" "rkisp1_selfpath" "-v" "pixelformat=422P" >>> >>> "media-ctl" "-d" "platform:rkisp1" "--set-v4l2" '"rkisp1_resizer_mainpath":0 [fmt:YUYV8_2X8/1500x1100 crop: (300,400)/1400x1000]' >>> "media-ctl" "-d" "platform:rkisp1" "--set-v4l2" '"rkisp1_resizer_mainpath":1 [fmt:YUYV8_2X8/900x800]' >>> >>> "v4l2-ctl" "-z" "platform:rkisp1" "-d" "rkisp1_mainpath" "-v" "width=900,height=800," >>> "v4l2-ctl" "-z" "platform:rkisp1" "-d" "rkisp1_mainpath" "-v" "pixelformat=422P" >>> >>> sleep 1 >>> >>> time v4l2-ctl "-z" "platform:rkisp1" "-d" "rkisp1_mainpath" "--stream-mmap" "--stream-count" "100" & >>> time v4l2-ctl "-z" "platform:rkisp1" "-d" "rkisp1_selfpath" "--stream-mmap" "--stream-count" "100" & >>> >>> wait >>> echo "Completed" >>> >>> Thanks >>> Helen >>> --- >>>   drivers/staging/media/rkisp1/TODO             |   3 - >>>   drivers/staging/media/rkisp1/rkisp1-capture.c | 227 +++++++++--------- >>>   2 files changed, 113 insertions(+), 117 deletions(-) >>> >>> diff --git a/drivers/staging/media/rkisp1/TODO b/drivers/staging/media/rkisp1/TODO >>> index e7c8398fc2cef..a2dd0ad951c25 100644 >>> --- a/drivers/staging/media/rkisp1/TODO >>> +++ b/drivers/staging/media/rkisp1/TODO >>> @@ -1,9 +1,6 @@ >>>   * Fix pad format size for statistics and parameters entities. >>>   * Fix checkpatch errors. >>>   * Add uapi docs. Remember to add documentation of how quantization is handled. >>> -* streaming paths (mainpath and selfpath) check if the other path is streaming >>> -in several places of the code, review this, specially that it doesn't seem it >>> -supports streaming from both paths at the same time. >>>     NOTES: >>>   * All v4l2-compliance test must pass. >>> diff --git a/drivers/staging/media/rkisp1/rkisp1-capture.c b/drivers/staging/media/rkisp1/rkisp1-capture.c >>> index b6f497ce3e95c..254936873c6c1 100644 >>> --- a/drivers/staging/media/rkisp1/rkisp1-capture.c >>> +++ b/drivers/staging/media/rkisp1/rkisp1-capture.c >>> @@ -830,71 +830,43 @@ static void rkisp1_return_all_buffers(struct rkisp1_capture *cap, >>>   } >>>     /* >>> - * rkisp1_pipeline_sink_walk - Walk through the pipeline and call cb >>> - * @from: entity at which to start pipeline walk >>> - * @until: entity at which to stop pipeline walk >>> - * >>> - * Walk the entities chain starting at the pipeline video node and stop >>> - * all subdevices in the chain. >>> - * >>> - * If the until argument isn't NULL, stop the pipeline walk when reaching the >>> - * until entity. This is used to disable a partially started pipeline due to a >>> - * subdev start error. >>> + * Most of registers inside rockchip ISP1 have shadow register since >>> + * they must be not be changed during processing a frame. >>> + * Usually, each sub-module updates its shadow register after >>> + * processing the last pixel of a frame. >>>    */ >>> -static int rkisp1_pipeline_sink_walk(struct media_entity *from, >>> -                     struct media_entity *until, >>> -                     int (*cb)(struct media_entity *from, >>> -                           struct media_entity *curr)) >>> +static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap) >>>   { >>> -    struct media_entity *entity = from; >>> -    struct media_pad *pad; >>> -    unsigned int i; >>> -    int ret; >>> - >>> -    while (1) { >>> -        pad = NULL; >>> -        /* Find remote source pad */ >>> -        for (i = 0; i < entity->num_pads; i++) { >>> -            struct media_pad *spad = &entity->pads[i]; >>> - >>> -            if (!(spad->flags & MEDIA_PAD_FL_SINK)) >>> -                continue; >>> -            pad = media_entity_remote_pad(spad); >>> -            if (pad && is_media_entity_v4l2_subdev(pad->entity)) >>> -                break; >>> -        } >>> -        if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) >>> -            break; >>> +    struct rkisp1_device *rkisp1 = cap->rkisp1; >>> +    struct rkisp1_capture *other = &rkisp1->capture_devs[cap->id ^ 1]; >>>   -        entity = pad->entity; >>> -        if (entity == until) >>> -            break; >>> +    cap->ops->set_data_path(cap); >>> +    cap->ops->config(cap); >>>   -        ret = cb(from, entity); >>> -        if (ret) >>> -            return ret; >>> +    /* Setup a buffer for the next frame */ >>> +    spin_lock_irq(&cap->buf.lock); >>> +    rkisp1_set_next_buf(cap); >>> +    cap->ops->enable(cap); >>> +    /* It's safe to config ACTIVE and SHADOW regs for the >>> +     * first stream. While when the second is starting, do NOT >>> +     * force update because it also update the first one. >>> +     * >>> +     * The latter case would drop one more buf(that is 2) since >>> +     * there's not buf in shadow when the second FE received. This's >>> +     * also required because the second FE maybe corrupt especially >>> +     * when run at 120fps. >>> +     */ >>> +    if (!other->is_streaming) { >>> +        /* force cfg update */ >>> +        rkisp1_write(rkisp1, >>> +                 RKISP1_CIF_MI_INIT_SOFT_UPD, RKISP1_CIF_MI_INIT); >>> +        rkisp1_set_next_buf(cap); >>>       } >>> - >>> -    return 0; >>> -} >>> - >>> -static int rkisp1_pipeline_disable_cb(struct media_entity *from, >>> -                      struct media_entity *curr) >>> -{ >>> -    struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(curr); >>> - >>> -    return v4l2_subdev_call(sd, video, s_stream, false); >>> -} >>> - >>> -static int rkisp1_pipeline_enable_cb(struct media_entity *from, >>> -                     struct media_entity *curr) >>> -{ >>> -    struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(curr); >>> - >>> -    return v4l2_subdev_call(sd, video, s_stream, true); >>> +    spin_unlock_irq(&cap->buf.lock); >>> +    cap->is_streaming = true; >>>   } >>>   -static void rkisp1_stream_stop(struct rkisp1_capture *cap) >>> +static void rkisp1_cap_stream_disable(struct rkisp1_capture *cap) >>>   { >>>       int ret; >>>   @@ -911,6 +883,81 @@ static void rkisp1_stream_stop(struct rkisp1_capture *cap) >>>       } >>>   } >>>   +/* >>> + * rkisp1_pipeline_stream_disable - disable nodes in the pipeline >>> + * >>> + * Call s_stream(false) in the reverse order from >>> + * rkisp1_pipeline_stream_enable() and disable the DMA engine. >>> + * Should be called before media_pipeline_stop() >>> + */ >>> +static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) >>> +    __must_hold(&cap->rkisp1->stream_lock) >>> +{ >>> +    struct rkisp1_device *rkisp1 = cap->rkisp1; >>> + >>> +    rkisp1_cap_stream_disable(cap); >>> + >>> +    /* >>> +     * If the other capture is streaming, isp and sensor nodes shouldn't >>> +     * be disabled, skip them. >>> +     */ >>> +    if (rkisp1->pipe.streaming_count < 2) { >>> +        v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream, >>> +                 false); >>> +        v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); >>> +    } >>> + >>> +    v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, >>> +             false); >> >> I wonder if the order of the disable matters. If it should be from the sensor up to the >> capture then we should call 'rkisp1_cap_stream_disable' at the end of this >> function. The only issue I saw was if I enable the sensor before the ISP. Even if the order in disabling the capture doesn't matter much, it is nice to keep the logic, thanks for this comment. >> >>> +} >>> + >>> +/* >>> + * rkisp1_pipeline_stream_enable - enable nodes in the pipeline >>> + * >>> + * Enable the DMA Engine and call s_stream(true) through the pipeline. >>> + * Should be called after media_pipeline_start() >>> + */ >>> +static int rkisp1_pipeline_stream_enable(struct rkisp1_capture *cap) >>> +    __must_hold(&cap->rkisp1->stream_lock) >>> +{ >>> +    struct rkisp1_device *rkisp1 = cap->rkisp1; >>> +    int ret; >>> + >>> +    rkisp1_cap_stream_enable(cap); >>> + >>> +    ret = v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, >>> +                   s_stream, true); >>> +    if (ret) >>> +        return ret; >> >> In case of error here, shouldn't we call 'rkisp1_cap_stream_disable'? > > Yes, thanks for catching it :) > >> >>> + >>> +    /* >>> +     * If the other capture is streaming, isp and sensor nodes are already >>> +     * enabled, skip them. >>> +     */ >>> +    if (rkisp1->pipe.streaming_count > 1) >>> +        return 0; >>> + >>> +    ret = v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, true); >>> +    if (ret) >>> +        goto err_disable_rsz; >>> + >>> +    ret = v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream, >>> +                   true); >>> +    if (ret) >>> +        goto err_disable_isp; >>> + >>> +    return 0; >>> + >>> +err_disable_isp: >>> +    v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); >>> +err_disable_rsz: >>> +    v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, >>> +             false); >>> +    rkisp1_cap_stream_disable(cap); >>> + >>> +    return ret; >>> +} >>> + >>>   static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue) >>>   { >>>       struct rkisp1_capture *cap = queue->drv_priv; >>> @@ -920,13 +967,8 @@ static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue) >>>         mutex_lock(&cap->rkisp1->stream_lock); >>>   -    rkisp1_stream_stop(cap); >>> +    rkisp1_pipeline_stream_disable(cap); >>>       media_pipeline_stop(&node->vdev.entity); >>> -    ret = rkisp1_pipeline_sink_walk(&node->vdev.entity, NULL, >>> -                    rkisp1_pipeline_disable_cb); >>> -    if (ret) >>> -        dev_err(rkisp1->dev, >>> -            "pipeline stream-off failed error:%d\n", ret); >>>         rkisp1_return_all_buffers(cap, VB2_BUF_STATE_ERROR); >>>   @@ -940,43 +982,6 @@ static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue) >>>       mutex_unlock(&cap->rkisp1->stream_lock); >>>   } >>>   -/* >>> - * Most of registers inside rockchip ISP1 have shadow register since >>> - * they must be not be changed during processing a frame. >>> - * Usually, each sub-module updates its shadow register after >>> - * processing the last pixel of a frame. >>> - */ >>> -static void rkisp1_stream_start(struct rkisp1_capture *cap) >>> -{ >>> -    struct rkisp1_device *rkisp1 = cap->rkisp1; >>> -    struct rkisp1_capture *other = &rkisp1->capture_devs[cap->id ^ 1]; >>> - >>> -    cap->ops->set_data_path(cap); >>> -    cap->ops->config(cap); >>> - >>> -    /* Setup a buffer for the next frame */ >>> -    spin_lock_irq(&cap->buf.lock); >>> -    rkisp1_set_next_buf(cap); >>> -    cap->ops->enable(cap); >>> -    /* It's safe to config ACTIVE and SHADOW regs for the >>> -     * first stream. While when the second is starting, do NOT >>> -     * force update because it also update the first one. >>> -     * >>> -     * The latter case would drop one more buf(that is 2) since >>> -     * there's not buf in shadow when the second FE received. This's >>> -     * also required because the second FE maybe corrupt especially >>> -     * when run at 120fps. >>> -     */ >>> -    if (!other->is_streaming) { >>> -        /* force cfg update */ >>> -        rkisp1_write(rkisp1, >>> -                 RKISP1_CIF_MI_INIT_SOFT_UPD, RKISP1_CIF_MI_INIT); >>> -        rkisp1_set_next_buf(cap); >>> -    } >>> -    spin_unlock_irq(&cap->buf.lock); >>> -    cap->is_streaming = true; >>> -} >>> - >>>   static int >>>   rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) >>>   { >>> @@ -1001,28 +1006,22 @@ rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) >>>           goto err_pipe_pm_put; >>>       } >>>   >> >> The previous code with the 'rkisp1_pipeline_sink_walk' only followed enabled links. >> We should probably first check if the link between the resizer and the isp is enabled >> and also between the isp to the sensor. and return -EPIPE if not. > > Very good point, yes, I'll fix this in v2. Actually this is not required, since resizer and isp sink pads use MEDIA_PAD_FL_MUST_CONNECT, media_pipeline_start() will failed with -ENOLINK if it is not connected. Thanks Helen > >> Actually I think that the code that set the 'active_sensor' (callingrkisp1_get_remote_sensor) >> should move to here since this also check if the link to the sensor is enabled. > > ok > > Thanks for your review > Helen > >> >> Thanks, >> Dafna >> >>> -    rkisp1_stream_start(cap); >>> - >>> -    /* start sub-devices */ >>> -    ret = rkisp1_pipeline_sink_walk(entity, NULL, >>> -                    rkisp1_pipeline_enable_cb); >>> -    if (ret) >>> -        goto err_stop_stream; >>> - >>>       ret = media_pipeline_start(entity, &cap->rkisp1->pipe); >>>       if (ret) { >>>           dev_err(cap->rkisp1->dev, "start pipeline failed %d\n", ret); >>> -        goto err_pipe_disable; >>> +        goto err_v4l2_pm_put; >>>       } >>> +    ret = rkisp1_pipeline_stream_enable(cap); >>> +    if (ret) >>> +        goto err_media_pipeline_stop; >>>         mutex_unlock(&cap->rkisp1->stream_lock); >>>         return 0; >>>   -err_pipe_disable: >>> -    rkisp1_pipeline_sink_walk(entity, NULL, rkisp1_pipeline_disable_cb); >>> -err_stop_stream: >>> -    rkisp1_stream_stop(cap); >>> +err_media_pipeline_stop: >>> +    media_pipeline_stop(entity); >>> +err_v4l2_pm_put: >>>       v4l2_pipeline_pm_put(entity); >>>   err_pipe_pm_put: >>>       pm_runtime_put(cap->rkisp1->dev); >>> >